org.wso2.emm.agent.services.operationMgt.OperationManager.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.emm.agent.services.operationMgt.OperationManager.java

Source

/*
 * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.wso2.emm.agent.services.operationMgt;

import android.annotation.TargetApi;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.wso2.emm.agent.AlertActivity;
import org.wso2.emm.agent.AndroidAgentException;
import org.wso2.emm.agent.LockActivity;
import org.wso2.emm.agent.R;
import org.wso2.emm.agent.ServerDetails;
import org.wso2.emm.agent.api.ApplicationManager;
import org.wso2.emm.agent.api.DeviceInfo;
import org.wso2.emm.agent.api.GPSTracker;
import org.wso2.emm.agent.api.RuntimeInfo;
import org.wso2.emm.agent.api.WiFiConfig;
import org.wso2.emm.agent.beans.Application;
import org.wso2.emm.agent.beans.ComplianceFeature;
import org.wso2.emm.agent.beans.DeviceAppInfo;
import org.wso2.emm.agent.beans.Notification;
import org.wso2.emm.agent.beans.Operation;
import org.wso2.emm.agent.dao.NotificationDAO;
import org.wso2.emm.agent.proxy.interfaces.APIResultCallBack;
import org.wso2.emm.agent.services.AgentDeviceAdminReceiver;
import org.wso2.emm.agent.services.DeviceInfoPayload;
import org.wso2.emm.agent.services.NotificationReceiver;
import org.wso2.emm.agent.services.PolicyComplianceChecker;
import org.wso2.emm.agent.services.PolicyOperationsMapper;
import org.wso2.emm.agent.services.ResultPayload;
import org.wso2.emm.agent.utils.CommonUtils;
import org.wso2.emm.agent.utils.Constants;
import org.wso2.emm.agent.utils.Preference;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;

public abstract class OperationManager implements APIResultCallBack, VersionBasedOperations {

    private Context context;
    private DevicePolicyManager devicePolicyManager;
    private ComponentName cdmDeviceAdmin;
    private ApplicationManager appList;
    private Resources resources;
    private ResultPayload resultBuilder;
    private DeviceInfo deviceInfo;
    private GPSTracker gps;
    private NotificationDAO notificationDAO;
    private NotificationManager notifyManager;
    private ApplicationManager applicationManager;

    private static final String TAG = OperationManager.class.getSimpleName();

    private static final String APP_INFO_TAG_NAME = "name";
    private static final String APP_INFO_TAG_PACKAGE = "package";
    private static final String APP_INFO_TAG_VERSION = "version";
    private static final int DEFAULT_PASSWORD_LENGTH = 0;
    private static final int DEFAULT_VOLUME = 0;
    private static final int DEFAULT_FLAG = 0;
    private static final int DEFAULT_PASSWORD_MIN_LENGTH = 4;
    private static final long DAY_MILLISECONDS_MULTIPLIER = 24 * 60 * 60 * 1000;
    private static String[] AUTHORIZED_PINNING_APPS;
    private static String AGENT_PACKAGE_NAME;

    public OperationManager(Context context) {
        this.context = context;
        this.resources = context.getResources();
        this.devicePolicyManager = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
        this.cdmDeviceAdmin = new ComponentName(context, AgentDeviceAdminReceiver.class);
        this.appList = new ApplicationManager(context.getApplicationContext());
        this.resultBuilder = new ResultPayload();
        deviceInfo = new DeviceInfo(context.getApplicationContext());
        notificationDAO = new NotificationDAO(context);
        AGENT_PACKAGE_NAME = context.getPackageName();
        AUTHORIZED_PINNING_APPS = new String[] { AGENT_PACKAGE_NAME };
        notifyManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        applicationManager = new ApplicationManager(context);
    }

    /**
     *  Methods used by child classes to retrieve values of private variables in Parent Class
     */

    /* Retrieve context resources. */
    public Resources getContextResources() {
        return resources;
    }

    /* Retrieve resultBuilder. */
    public ResultPayload getResultBuilder() {
        return resultBuilder;
    }

    /* Retrieve devicePolicyManager. */
    public DevicePolicyManager getDevicePolicyManager() {
        return devicePolicyManager;
    }

    /* Retrieve cdmDeviceAdmin */
    public ComponentName getCdmDeviceAdmin() {
        return cdmDeviceAdmin;
    }

    /* Retrieve default password length */
    public int getDefaultPasswordLength() {
        return DEFAULT_PASSWORD_LENGTH;
    }

    /* Retrieve appList */
    public ApplicationManager getAppList() {
        return appList;
    }

    /* Retrieve Default Password Minimum Length */
    public int getDefaultPasswordMinLength() {
        return DEFAULT_PASSWORD_MIN_LENGTH;
    }

    /* Retrieve Day Milliseconds Multiplier */
    public long getDayMillisecondsMultiplier() {
        return DAY_MILLISECONDS_MULTIPLIER;
    }

    /* Retrieve Context */
    public Context getContext() {
        return context;
    }

    /* Retrive applicationManager */
    public ApplicationManager getApplicationManager() {
        return applicationManager;
    }
    /* End of methods used by child classes to access private variables in Parent Class */

    /**
     * Retrieve device information.
     *
     * @param operation - Operation object.
     */
    public void getDeviceInfo(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException {
        DeviceInfoPayload deviceInfoPayload = new DeviceInfoPayload(context);
        deviceInfoPayload.build();
        String replyPayload = deviceInfoPayload.getDeviceInfoPayload();

        operation.setOperationResponse(replyPayload);
        operation.setStatus(resources.getString(R.string.operation_value_completed));
        resultBuilder.build(operation);
    }

    /**
     * Retrieve location device information.
     *
     * @param operation - Operation object.
     */
    public void getLocationInfo(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException {
        gps = GPSTracker.getInstance(context);
        gps.updateLocation();
        JSONObject result = new JSONObject();
        if (gps != null) {
            try {
                result.put(Constants.LocationInfo.LATITUDE, gps.getLatitude());
                result.put(Constants.LocationInfo.LONGITUDE, gps.getLongitude());
                result.put(Constants.LocationInfo.CITY, gps.getCity());
                result.put(Constants.LocationInfo.COUNTRY, gps.getCountry());
                result.put(Constants.LocationInfo.STATE, gps.getState());
                result.put(Constants.LocationInfo.STREET1, gps.getStreet1());
                result.put(Constants.LocationInfo.STREET2, gps.getStreet2());
                result.put(Constants.LocationInfo.ZIP, gps.getZip());

                operation.setOperationResponse(result.toString());
                operation.setStatus(resources.getString(R.string.operation_value_completed));
                resultBuilder.build(operation);
                if (Constants.DEBUG_MODE_ENABLED) {
                    Log.d(TAG, "Device location sent");
                }
            } catch (JSONException e) {
                operation.setStatus(resources.getString(R.string.operation_value_error));
                resultBuilder.build(operation);
                throw new AndroidAgentException("Invalid JSON format.", e);
            }
        } else {
            operation.setStatus(resources.getString(R.string.operation_value_error));
            resultBuilder.build(operation);
            throw new AndroidAgentException("Error occurred while initiating location service");
        }
    }

    /**
     * Retrieve device application information.
     *
     * @param operation - Operation object.
     */
    public void getApplicationList(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException {
        ArrayList<DeviceAppInfo> apps = new ArrayList<>(appList.getInstalledApps().values());
        JSONArray result = new JSONArray();
        RuntimeInfo runtimeInfo = new RuntimeInfo(context);
        Map<String, Application> applications = runtimeInfo.getAppMemory();
        for (DeviceAppInfo infoApp : apps) {
            JSONObject app = new JSONObject();
            try {
                Application application = applications.get(infoApp.getPackagename());
                app.put(APP_INFO_TAG_NAME, Uri.encode(infoApp.getAppname()));
                app.put(APP_INFO_TAG_PACKAGE, infoApp.getPackagename());
                app.put(APP_INFO_TAG_VERSION, infoApp.getVersionCode());
                if (application != null) {
                    app.put(Constants.Device.USS, application.getUss());
                }
                result.put(app);
            } catch (JSONException e) {
                operation.setStatus(resources.getString(R.string.operation_value_error));
                resultBuilder.build(operation);
                throw new AndroidAgentException("Invalid JSON format.", e);
            }
        }
        operation.setOperationResponse(result.toString());
        operation.setStatus(resources.getString(R.string.operation_value_completed));
        resultBuilder.build(operation);

        if (Constants.DEBUG_MODE_ENABLED) {
            Log.d(TAG, "Application list sent");
        }
    }

    /**
     * Ring the device.
     *
     * @param operation - Operation object.
     */
    public void ringDevice(org.wso2.emm.agent.beans.Operation operation) {
        operation.setStatus(resources.getString(R.string.operation_value_completed));
        resultBuilder.build(operation);
        Intent intent = new Intent(context, AlertActivity.class);
        intent.putExtra(resources.getString(R.string.intent_extra_type),
                resources.getString(R.string.intent_extra_ring));
        intent.putExtra(resources.getString(R.string.intent_extra_message),
                resources.getString(R.string.intent_extra_stop_ringing));
        intent.setFlags(
                Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);

        if (Constants.DEBUG_MODE_ENABLED) {
            Log.d(TAG, "Ringing is activated on the device");
        }
    }

    /**
     * Configure device WIFI profile.
     *
     * @param operation - Operation object.
     */
    public void configureWifi(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException {
        boolean wifiStatus;
        String ssid = null;
        String password = null;
        JSONObject result = new JSONObject();

        try {
            JSONObject wifiData = new JSONObject(operation.getPayLoad().toString());
            if (!wifiData.isNull(resources.getString(R.string.intent_extra_ssid))) {
                ssid = (String) wifiData.get(resources.getString(R.string.intent_extra_ssid));
            }
            if (!wifiData.isNull(resources.getString(R.string.intent_extra_password))) {
                password = (String) wifiData.get(resources.getString(R.string.intent_extra_password));
            }
        } catch (JSONException e) {
            operation.setStatus(resources.getString(R.string.operation_value_error));
            resultBuilder.build(operation);
            throw new AndroidAgentException("Invalid JSON format.", e);
        }

        WiFiConfig config = new WiFiConfig(context.getApplicationContext());
        wifiStatus = config.saveWEPConfig(ssid, password);

        try {
            String status;
            if (wifiStatus) {
                status = resources.getString(R.string.shared_pref_default_status);
                result.put(resources.getString(R.string.operation_status), status);
            } else {
                status = resources.getString(R.string.shared_pref_false_status);
                result.put(resources.getString(R.string.operation_status), status);
            }
        } catch (JSONException e) {
            operation.setStatus(resources.getString(R.string.operation_value_error));
            resultBuilder.build(operation);
            throw new AndroidAgentException("Invalid JSON format.", e);
        }
        if (Constants.DEBUG_MODE_ENABLED) {
            Log.d(TAG, "Wifi configured");
        }
        operation.setStatus(resources.getString(R.string.operation_value_completed));
        operation.setPayLoad(result.toString());
        resultBuilder.build(operation);
    }

    /**
     * Disable/Enable device camera.
     *
     * @param operation - Operation object.
     */
    public void disableCamera(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException {
        boolean camFunc = operation.isEnabled();
        operation.setStatus(resources.getString(R.string.operation_value_completed));
        resultBuilder.build(operation);
        devicePolicyManager.setCameraDisabled(cdmDeviceAdmin, !camFunc);
        if (Constants.DEBUG_MODE_ENABLED) {
            Log.d(TAG, "Camera enabled: " + camFunc);
        }
    }

    /**
     * Mute the device.
     *
     * @param operation - Operation object.
     */
    public void muteDevice(org.wso2.emm.agent.beans.Operation operation) {
        operation.setStatus(resources.getString(R.string.operation_value_completed));
        resultBuilder.build(operation);

        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        audioManager.setStreamVolume(AudioManager.STREAM_RING, DEFAULT_VOLUME, DEFAULT_FLAG);
        if (Constants.DEBUG_MODE_ENABLED) {
            Log.d(TAG, "Device muted");
        }
    }

    /**
     * Create web clip (Web app shortcut on device home screen).
     *
     * @param operation - Operation object.
     */
    public void manageWebClip(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException {
        String appUrl;
        String title;
        String operationType;

        try {
            JSONObject webClipData = new JSONObject(operation.getPayLoad().toString());
            appUrl = webClipData.getString(resources.getString(R.string.intent_extra_identity));
            title = webClipData.getString(resources.getString(R.string.intent_extra_title));
            operationType = webClipData.getString(resources.getString(R.string.operation_type));
        } catch (JSONException e) {
            operation.setStatus(resources.getString(R.string.operation_value_error));
            resultBuilder.build(operation);
            throw new AndroidAgentException("Invalid JSON format.", e);
        }

        operation.setStatus(resources.getString(R.string.operation_value_completed));
        resultBuilder.build(operation);

        if (appUrl != null && title != null) {
            appList.manageWebAppBookmark(appUrl, title, operationType);
        }
        if (Constants.DEBUG_MODE_ENABLED) {
            Log.d(TAG, "Created webclip");
        }
    }

    /**
     * Open Google Play store application with an application given.
     *
     * @param packageName - Application package name.
     */
    public void triggerGooglePlayApp(String packageName) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setData(Uri.parse(Constants.GOOGLE_PLAY_APP_URI + packageName));
        context.startActivity(intent);
    }

    /**
     * Monitor currently enforced policy for compliance.
     *
     * @param operation - Operation object.
     */
    public void monitorPolicy(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException {
        String payload = Preference.getString(context, Constants.PreferenceFlag.APPLIED_POLICY);
        PolicyOperationsMapper operationsMapper = new PolicyOperationsMapper();
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);

        PolicyComplianceChecker policyChecker = new PolicyComplianceChecker(context);
        ArrayList<ComplianceFeature> result = new ArrayList<>();

        try {
            if (payload != null) {
                List<org.wso2.emm.agent.beans.Operation> operations = mapper.readValue(payload,
                        mapper.getTypeFactory().constructCollectionType(List.class,
                                org.wso2.emm.agent.beans.Operation.class));
                for (org.wso2.emm.agent.beans.Operation op : operations) {
                    op = operationsMapper.getOperation(op);
                    result.add(policyChecker.checkPolicyState(op));
                }
                operation.setStatus(resources.getString(R.string.operation_value_completed));
                operation.setPayLoad(mapper.writeValueAsString(result));
                resultBuilder.build(operation);
            }
        } catch (IOException e) {
            operation.setStatus(resources.getString(R.string.operation_value_error));
            resultBuilder.build(operation);
            throw new AndroidAgentException("Error occurred while parsing stream.", e);
        }
    }

    /**
     * Revoke currently enforced policy.
     *
     * @param operation - Operation object.
     */
    public void revokePolicy(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException {
        CommonUtils.revokePolicy(context);
        operation.setStatus(resources.getString(R.string.operation_value_completed));
        resultBuilder.build(operation);
    }

    /**
     * Blacklisting apps.
     *
     * @param operation - Operation object.
     */
    public void blacklistApps(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException {

    }

    /**
     * Uninstall application.
     *
     * @param operation - Operation object.
     */
    public void uninstallApplication(Operation operation) throws AndroidAgentException {
        String packageName;
        String type;
        String schedule = null;
        try {
            JSONObject appData = new JSONObject(operation.getPayLoad().toString());
            type = appData.getString(getContextResources().getString(R.string.app_type));

            if (getContextResources().getString(R.string.intent_extra_web).equalsIgnoreCase(type)) {
                String appUrl = appData.getString(getContextResources().getString(R.string.app_url));
                String name = appData.getString(getContextResources().getString(R.string.intent_extra_name));
                String operationType = getContextResources().getString(R.string.operation_uninstall);
                JSONObject payload = new JSONObject();
                payload.put(getContextResources().getString(R.string.intent_extra_identity), appUrl);
                payload.put(getContextResources().getString(R.string.intent_extra_title), name);
                payload.put(getContextResources().getString(R.string.operation_type), operationType);
                operation.setPayLoad(payload.toString());
                manageWebClip(operation);
            } else {
                packageName = appData.getString(getContextResources().getString(R.string.app_identifier));
                if (appData.has(getContextResources().getString(R.string.app_schedule))) {
                    schedule = appData.getString(getContextResources().getString(R.string.app_schedule));
                }
                getAppList().uninstallApplication(packageName, schedule);
                operation.setStatus(getContextResources().getString(R.string.operation_value_completed));
                getResultBuilder().build(operation);
            }

            if (Constants.DEBUG_MODE_ENABLED) {
                Log.d(TAG, "Application started to uninstall");
            }
        } catch (JSONException e) {
            operation.setStatus(getContextResources().getString(R.string.operation_value_error));
            getResultBuilder().build(operation);
            throw new AndroidAgentException("Invalid JSON format.", e);
        }
    }

    /**
     * Reboot the device [System app required].
     *
     * @param operation - Operation object.
     */
    public void rebootDevice(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException {
        JSONObject result = new JSONObject();

        try {
            String status = resources.getString(R.string.shared_pref_default_status);
            result.put(resources.getString(R.string.operation_status), status);
            operation.setPayLoad(result.toString());

            if (status.equals(resources.getString(R.string.shared_pref_default_status))) {
                Toast.makeText(context, resources.getString(R.string.toast_message_reboot), Toast.LENGTH_LONG)
                        .show();
                operation.setStatus(resources.getString(R.string.operation_value_completed));
                resultBuilder.build(operation);

                if (Constants.DEBUG_MODE_ENABLED) {
                    Log.d(TAG, "Reboot initiated.");
                }
            } else {
                Toast.makeText(context, resources.getString(R.string.toast_message_reboot_failed),
                        Toast.LENGTH_LONG).show();
                operation.setStatus(resources.getString(R.string.operation_value_error));
                resultBuilder.build(operation);
            }
        } catch (JSONException e) {
            operation.setStatus(resources.getString(R.string.operation_value_error));
            resultBuilder.build(operation);
            throw new AndroidAgentException("Invalid JSON format.", e);
        }
    }

    /**
     * Upgrading device firmware from the configured OTA server.
     *
     * @param operation - Operation object.
     */
    public void upgradeFirmware(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException {
        JSONObject result = new JSONObject();
        String schedule;

        try {
            JSONObject upgradeData = new JSONObject(operation.getPayLoad().toString());
            if (!upgradeData.isNull(resources.getString(R.string.intent_extra_schedule))) {
                schedule = (String) upgradeData.get(resources.getString(R.string.intent_extra_schedule));
                Preference.putString(context, resources.getString(R.string.pref_key_schedule), schedule);
            }

        } catch (JSONException e) {
            operation.setStatus(resources.getString(R.string.operation_value_error));
            resultBuilder.build(operation);
            throw new AndroidAgentException("Invalid JSON format.", e);
        }

        try {
            String status = resources.getString(R.string.shared_pref_default_status);
            result.put(resources.getString(R.string.operation_status), status);

            operation.setPayLoad(result.toString());

            if (status.equals(resources.getString(R.string.shared_pref_default_status))) {
                operation.setStatus(resources.getString(R.string.operation_value_completed));
                resultBuilder.build(operation);

                if (Constants.DEBUG_MODE_ENABLED) {
                    Log.d(TAG, "Firmware upgrade started.");
                }
            } else {
                operation.setStatus(resources.getString(R.string.operation_value_error));
                resultBuilder.build(operation);
            }
        } catch (JSONException e) {
            operation.setStatus(resources.getString(R.string.operation_value_error));
            resultBuilder.build(operation);
            throw new AndroidAgentException("Invalid JSON format.", e);
        }
    }

    /**
     * Execute shell commands as the super user.
     *
     * @param operation - Operation object.
     */
    public void executeShellCommand(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException {
        JSONObject result = new JSONObject();

        try {
            String status = resources.getString(R.string.shared_pref_default_status);
            result.put(resources.getString(R.string.operation_status), status);

            operation.setPayLoad(result.toString());

            if (status.equals(resources.getString(R.string.shared_pref_default_status))) {
                operation.setStatus(resources.getString(R.string.operation_value_completed));
                resultBuilder.build(operation);

                if (Constants.DEBUG_MODE_ENABLED) {
                    Log.d(TAG, "Shell command received.");
                }
            } else {
                operation.setStatus(resources.getString(R.string.operation_value_error));
                resultBuilder.build(operation);
            }
        } catch (JSONException e) {
            operation.setStatus(resources.getString(R.string.operation_value_error));
            resultBuilder.build(operation);
            throw new AndroidAgentException("Invalid JSON format.", e);
        }
    }

    /**
     * This method returns the completed operations list.
     *
     * @return operation list
     */
    public List<org.wso2.emm.agent.beans.Operation> getResultPayload() {
        return resultBuilder.getResultPayload();
    }

    /**
     * This method is used to add notification to the embedded db.
     * @param id notification id (operation id).
     * @param message notification.
     * @param status current status of the notification.
     */
    private void addNotification(int id, String message, Notification.Status status) {
        Notification notification = new Notification();
        notification.setId(id);
        notification.setMessage(message);
        notification.setStatus(status);
        notification.setReceivedTime(Calendar.getInstance().getTime().toString());
        notificationDAO.open();
        if (notificationDAO.getNotification(id) == null) {
            notificationDAO.addNotification(notification);
        }
        notificationDAO.close();
    }

    /**
     * This method checks whether there are any previous notifications which were not sent
     * and send if found any.
     */
    public void checkPreviousNotifications() {
        notificationDAO.open();
        List<Notification> dismissedNotifications = notificationDAO.getAllDismissedNotifications();
        org.wso2.emm.agent.beans.Operation operation;
        for (Notification notification : dismissedNotifications) {
            operation = new org.wso2.emm.agent.beans.Operation();
            operation.setId(notification.getId());
            operation.setCode(Constants.Operation.NOTIFICATION);
            operation.setStatus(resources.getString(R.string.operation_value_completed));
            operation.setOperationResponse("Alert was dismissed: " + notification.getResponseTime());
            resultBuilder.build(operation);
            notificationDAO.updateNotification(notification.getId(), Notification.Status.SENT);
        }
        notificationDAO.close();
    }

    /**
     * Lock the device.
     *
     * @param operation - Operation object.
     */
    public void lockDevice(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException {
        operation.setStatus(resources.getString(R.string.operation_value_completed));
        resultBuilder.build(operation);
        JSONObject inputData;
        String message = null;
        boolean isHardLockEnabled = false;
        try {
            if (operation.getPayLoad() != null) {
                inputData = new JSONObject(operation.getPayLoad().toString());
                message = inputData.getString(Constants.ADMIN_MESSAGE);
                isHardLockEnabled = inputData.getBoolean(Constants.IS_HARD_LOCK_ENABLED);
            }
        } catch (JSONException e) {
            operation.setStatus(resources.getString(R.string.operation_value_error));
            resultBuilder.build(operation);
            throw new AndroidAgentException("Invalid JSON format.", e);
        }
        if (isHardLockEnabled) {
            if (message == null || message.isEmpty()) {
                message = resources.getString(R.string.txt_lock_activity);
            }
            Preference.putBoolean(context, Constants.IS_LOCKED, true);
            Preference.putString(context, Constants.LOCK_MESSAGE, message);
            enableHardLock(message);
        } else {
            devicePolicyManager.lockNow();
        }

        if (Constants.DEBUG_MODE_ENABLED) {
            Log.d(TAG, "Device locked");
        }
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public void enableHardLock(String message) {
        if (isDeviceOwner()) {
            devicePolicyManager.setLockTaskPackages(cdmDeviceAdmin, AUTHORIZED_PINNING_APPS);
            Intent intent = new Intent(context, LockActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP
                    | Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra(Constants.ADMIN_MESSAGE, message);
            intent.putExtra(Constants.IS_LOCKED, true);
            context.startActivity(intent);
        } else {
            devicePolicyManager.lockNow();
        }
    }

    /**
     * Unlock the device.
     *
     * @param operation - Operabtion object.
     */
    public void unlockDevice(org.wso2.emm.agent.beans.Operation operation) {
        operation.setStatus(resources.getString(R.string.operation_value_completed));
        resultBuilder.build(operation);

        boolean isLocked = Preference.getBoolean(context, Constants.IS_LOCKED);
        if (isLocked) {
            if (isDeviceOwner()) {
                Intent intent = new Intent(context, ServerDetails.class);
                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP
                        | Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(intent);
            }
        }
        if (Constants.DEBUG_MODE_ENABLED) {
            Log.d(TAG, "Device unlocked");
        }
    }

    /**
     * This method is used to check whether agent is registered as the device owner.
     *
     * @return true if agent is the device owner.
     */
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
    private boolean isDeviceOwner() {
        return devicePolicyManager.isDeviceOwnerApp(AGENT_PACKAGE_NAME);
    }

    /**
     * Install google play applications.
     *
     * @param operation - Operation object.
     */
    public void installGooglePlayApp(Operation operation) throws AndroidAgentException {
        String packageName;
        try {
            JSONObject appData = new JSONObject(operation.getPayLoad().toString());
            packageName = (String) appData.get(getContextResources().getString(R.string.intent_extra_package));

        } catch (JSONException e) {
            operation.setStatus(getContextResources().getString(R.string.operation_value_error));
            getResultBuilder().build(operation);
            throw new AndroidAgentException("Invalid JSON format.", e);
        }

        if (Constants.DEBUG_MODE_ENABLED) {
            Log.d(TAG, "Started installing GoogleApp");
        }

        operation.setStatus(getContextResources().getString(R.string.operation_value_completed));
        getResultBuilder().build(operation);

        triggerGooglePlayApp(packageName);
    }

    /**
     * This method is used to post a notification in the device.
     *
     * @param operationId id of the calling notification operation.
     * @param message message to be displayed
     */
    private void initNotification(int operationId, String message) {

        Intent notification = new Intent(context, NotificationReceiver.class);
        notification.putExtra(Constants.OPERATION_ID, operationId);
        PendingIntent dismiss = PendingIntent.getBroadcast(context, operationId, notification,
                PendingIntent.FLAG_ONE_SHOT);
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
                .setSmallIcon(R.drawable.notification)
                .setContentTitle(resources.getString(R.string.txt_notification)).setContentText(message)
                .setPriority(android.app.Notification.PRIORITY_MAX)
                .setDefaults(android.app.Notification.DEFAULT_VIBRATE)
                .setDefaults(android.app.Notification.DEFAULT_SOUND)
                .setCategory(android.app.Notification.CATEGORY_CALL).setOngoing(true).setOnlyAlertOnce(true)
                .setTicker(resources.getString(R.string.txt_notification))
                .addAction(R.drawable.abs__ic_clear, "Dismiss", dismiss);

        notifyManager.notify(operationId, mBuilder.build());
    }

    /**
     * Display notification.
     *
     * @param operation - Operation object.
     */
    public void displayNotification(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException {
        try {

            operation.setStatus(resources.getString(R.string.operation_value_progress));
            boolean isLocked = Preference.getBoolean(context, Constants.IS_LOCKED);
            if (isLocked) {
                operation.setOperationResponse(
                        "Alert is received to locked device: " + Calendar.getInstance().getTime().toString());
            } else {
                operation.setOperationResponse("Alert is received: " + Calendar.getInstance().getTime().toString());
            }

            resultBuilder.build(operation);
            JSONObject inputData = new JSONObject(operation.getPayLoad().toString());
            String message = inputData.getString(resources.getString(R.string.intent_extra_message));

            if (message != null && !message.isEmpty()) {
                addNotification(operation.getId(), message, Notification.Status.PENDING); //adding notification to the db
                if (deviceInfo.getSdkVersion() >= Build.VERSION_CODES.LOLLIPOP) {
                    initNotification(operation.getId(), message);
                } else {
                    Intent intent = new Intent(context, AlertActivity.class);
                    intent.putExtra(resources.getString(R.string.intent_extra_message), message);
                    intent.putExtra(resources.getString(R.string.intent_extra_operation_id), operation.getId());
                    intent.putExtra(resources.getString(R.string.intent_extra_type),
                            resources.getString(R.string.intent_extra_alert));
                    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP
                            | Intent.FLAG_ACTIVITY_NEW_TASK);
                    intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                    context.startActivity(intent);

                }
            }
            if (Constants.DEBUG_MODE_ENABLED) {
                Log.d(TAG, "Notification received");
            }
        } catch (JSONException e) {
            operation.setStatus(resources.getString(R.string.operation_value_error));
            resultBuilder.build(operation);
            throw new AndroidAgentException("Invalid JSON format.", e);
        }
    }

    /**
     * Configure device VPN profile.
     *
     * @param operation - Operation object.
     */
    public void configureVPN(org.wso2.emm.agent.beans.Operation operation) throws AndroidAgentException {
        String serverAddress = null;
        JSONObject result = new JSONObject();

        try {
            JSONObject vpnData = new JSONObject(operation.getPayLoad().toString());
            if (!vpnData.isNull(resources.getString(R.string.intent_extra_server))) {
                serverAddress = (String) vpnData.get(resources.getString(R.string.intent_extra_server));
            }

        } catch (JSONException e) {
            operation.setStatus(resources.getString(R.string.operation_value_error));
            resultBuilder.build(operation);
            throw new AndroidAgentException("Invalid JSON format.", e);
        }

        if (serverAddress != null) {
            Intent intent = new Intent(context, AlertActivity.class);
            intent.putExtra(resources.getString(R.string.intent_extra_message),
                    resources.getString(R.string.toast_message_vpn));
            intent.putExtra(resources.getString(R.string.intent_extra_operation_id), operation.getId());
            intent.putExtra(resources.getString(R.string.intent_extra_payload), operation.getPayLoad().toString());
            intent.putExtra(resources.getString(R.string.intent_extra_type), Constants.Operation.VPN);
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP
                    | Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
            context.startActivity(intent);
        }

        if (Constants.DEBUG_MODE_ENABLED) {
            Log.d(TAG, "VPN configured");
        }
        operation.setStatus(resources.getString(R.string.operation_value_completed));
        operation.setPayLoad(result.toString());
        resultBuilder.build(operation);
    }

    @Override
    public void passOperationToSystemApp(Operation operation) throws AndroidAgentException {
        if (getApplicationManager().isPackageInstalled(Constants.SERVICE_PACKAGE_NAME)) {
            CommonUtils.callSystemApp(getContext(), operation.getCode(), Boolean.toString(operation.isEnabled()),
                    null);
        } else {
            if (operation.isEnabled()) {
                Log.e(TAG, "Invalid operation code received");
            }
        }
    }

    /**
     * This method is being invoked when get info operation get executed.
     *
     * @param result response result
     * @param requestCode code of the requested operation
     */
    @Override
    public void onReceiveAPIResult(Map<String, String> result, int requestCode) {
        String responseStatus;
        String response;
        if (requestCode == Constants.DEVICE_INFO_REQUEST_CODE) {
            if (result != null) {
                responseStatus = result.get(Constants.STATUS_KEY);
                if (Constants.Status.SUCCESSFUL.equals(responseStatus)) {
                    response = result.get(Constants.RESPONSE);
                    if (response != null && !response.isEmpty()) {
                        if (Constants.DEBUG_MODE_ENABLED) {
                            Log.d(TAG, "onReceiveAPIResult." + response);
                            Log.d(TAG, "Device information sent");
                        }
                    }
                }
            }
        }
    }

}