org.wso2.emm.system.service.EMMSystemService.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.emm.system.service.EMMSystemService.java

Source

/*
 * Copyright (c) 2014, 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.system.service;

import android.annotation.TargetApi;
import android.app.IntentService;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.PowerManager;
import android.os.SystemProperties;
import android.os.UserManager;
import android.util.Log;
import android.util.Patterns;

import org.json.JSONException;
import org.json.JSONObject;
import org.wso2.emm.system.service.api.OTADownload;
import org.wso2.emm.system.service.api.SettingsManager;
import org.wso2.emm.system.service.services.BatteryChargingStateReceiver;
import org.wso2.emm.system.service.utils.AlarmUtils;
import org.wso2.emm.system.service.utils.AppUtils;
import org.wso2.emm.system.service.utils.CommonUtils;
import org.wso2.emm.system.service.utils.Constants;
import org.wso2.emm.system.service.utils.Preference;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.text.ParseException;
import java.util.Timer;
import java.util.TimerTask;

import static android.os.UserManager.ALLOW_PARENT_PROFILE_APP_LINKING;
import static android.os.UserManager.DISALLOW_ADD_USER;
import static android.os.UserManager.DISALLOW_ADJUST_VOLUME;
import static android.os.UserManager.DISALLOW_APPS_CONTROL;
import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
import static android.os.UserManager.DISALLOW_CONFIG_CELL_BROADCASTS;
import static android.os.UserManager.DISALLOW_CONFIG_CREDENTIALS;
import static android.os.UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS;
import static android.os.UserManager.DISALLOW_CONFIG_TETHERING;
import static android.os.UserManager.DISALLOW_CONFIG_VPN;
import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
import static android.os.UserManager.DISALLOW_CREATE_WINDOWS;
import static android.os.UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE;
import static android.os.UserManager.DISALLOW_DEBUGGING_FEATURES;
import static android.os.UserManager.DISALLOW_FACTORY_RESET;
import static android.os.UserManager.DISALLOW_INSTALL_APPS;
import static android.os.UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES;
import static android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS;
import static android.os.UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA;
import static android.os.UserManager.DISALLOW_NETWORK_RESET;
import static android.os.UserManager.DISALLOW_OUTGOING_BEAM;
import static android.os.UserManager.DISALLOW_OUTGOING_CALLS;
import static android.os.UserManager.DISALLOW_REMOVE_USER;
import static android.os.UserManager.DISALLOW_SAFE_BOOT;
import static android.os.UserManager.DISALLOW_SHARE_LOCATION;
import static android.os.UserManager.DISALLOW_SMS;
import static android.os.UserManager.DISALLOW_UNINSTALL_APPS;
import static android.os.UserManager.DISALLOW_UNMUTE_MICROPHONE;
import static android.os.UserManager.DISALLOW_USB_FILE_TRANSFER;
import static android.os.UserManager.ENSURE_VERIFY_APPS;

/**
 * This is the service class which exposes all the system level operations
 * to the EMM Agent app. Agent can bind to this service and execute permitted operations by
 * sending necessary parameters.
 */
public class EMMSystemService extends IntentService {

    private static final String TAG = "EMMSystemService";
    private static final int ACTIVATION_REQUEST = 0x00000002;
    private static final String BUILD_DATE_UTC_PROPERTY = "ro.build.date.utc";
    private static final int DEFAULT_STATE_INFO_CODE = 0;
    public static ComponentName cdmDeviceAdmin;
    public static DevicePolicyManager devicePolicyManager;
    public static UserManager mUserManager;
    private static boolean restrictionCode = false;
    private String operationCode = null;
    private String command = null;
    private String appUri = null;
    private int operationId;
    private Context context;

    private static String[] AUTHORIZED_PINNING_APPS;
    private static String AGENT_PACKAGE_NAME;

    public EMMSystemService() {
        super("EMMSystemService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        context = this.getApplicationContext();
        cdmDeviceAdmin = new ComponentName(this, ServiceDeviceAdminReceiver.class);
        devicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
        mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
        AGENT_PACKAGE_NAME = context.getPackageName();
        AUTHORIZED_PINNING_APPS = new String[] { AGENT_PACKAGE_NAME, Constants.AGENT_APP_PACKAGE_NAME };
        if (!devicePolicyManager.isAdminActive(cdmDeviceAdmin)) {
            startAdmin();
        } else {
            /*This function handles the "Execute Command on Device" Operation.
            All requests are handled on a single worker thread. They may take as long as necessary
            (and will not block the application's main thread),
            but only one request will be processed at a time.*/
            Log.d(TAG, "Entered onHandleIntent of the Command Runner Service.");
            Bundle extras = intent.getExtras();
            if (extras != null) {
                operationCode = extras.getString("operation");

                if (extras.containsKey("command")) {
                    command = extras.getString("command");
                    if (command != null) {
                        restrictionCode = command.equals("true");
                    }
                }

                if (extras.containsKey("appUri")) {
                    appUri = extras.getString("appUri");
                }

                if (extras.containsKey("operationId")) {
                    operationId = extras.getInt("operationId");
                }
            }

            if ((operationCode != null)) {
                if (Constants.AGENT_APP_PACKAGE_NAME.equals(intent.getPackage())) {
                    Log.d(TAG, "EMM agent has sent a command with operation code: " + operationCode + " command: "
                            + command);
                    doTask(operationCode);
                } else {
                    Log.d(TAG, "Received command from external application. operation code: " + operationCode
                            + " command: " + command);
                    boolean isAutomaticRetry;
                    switch (operationCode) {
                    case Constants.Operation.FIRMWARE_UPGRADE_AUTOMATIC_RETRY:
                        if ("false".equals(command) || "true".equals(command)) {
                            isAutomaticRetry = "true".equals(command);
                            Preference.putBoolean(context,
                                    context.getResources().getString(R.string.firmware_upgrade_automatic_retry),
                                    isAutomaticRetry);
                            if (isAutomaticRetry) {
                                String status = Preference.getString(context,
                                        context.getResources().getString(R.string.upgrade_download_status));
                                if (Constants.Status.WIFI_OFF.equals(status) && !checkNetworkOnline()) {
                                    Preference.putString(context,
                                            context.getResources().getString(R.string.upgrade_download_status),
                                            Constants.Status.FAILED);
                                } else if (Constants.Status.BATTERY_LEVEL_INSUFFICIENT_TO_DOWNLOAD.equals(status)) {
                                    Preference.putString(context,
                                            context.getResources().getString(R.string.upgrade_download_status),
                                            Constants.Status.FAILED);
                                } else if (Constants.Status.BATTERY_LEVEL_INSUFFICIENT_TO_INSTALL
                                        .equals(Preference.getString(context, context.getResources()
                                                .getString(R.string.upgrade_install_status)))) {
                                    Preference.putString(context,
                                            context.getResources().getString(R.string.upgrade_install_status),
                                            Constants.Status.FAILED);
                                }
                            }
                            CommonUtils.callAgentApp(context, Constants.Operation.FIRMWARE_UPGRADE_AUTOMATIC_RETRY,
                                    0, command); //Sending command as the message
                            CommonUtils.sendBroadcast(context, Constants.Operation.FIRMWARE_UPGRADE_AUTOMATIC_RETRY,
                                    Constants.Code.SUCCESS, Constants.Status.SUCCESSFUL, "Updated");
                        } else {
                            CommonUtils.sendBroadcast(context, Constants.Operation.FIRMWARE_UPGRADE_AUTOMATIC_RETRY,
                                    Constants.Code.FAILURE, Constants.Status.MALFORMED_REQUEST,
                                    "Invalid command argument.");
                        }
                        break;
                    case Constants.Operation.UPGRADE_FIRMWARE:
                        try {
                            JSONObject upgradeData = new JSONObject(command);
                            isAutomaticRetry = (Preference.hasPreferenceKey(context,
                                    context.getResources().getString(R.string.firmware_upgrade_automatic_retry))
                                    && Preference.getBoolean(context,
                                            context.getResources()
                                                    .getString(R.string.firmware_upgrade_automatic_retry)))
                                    || !Preference.hasPreferenceKey(context, context.getResources()
                                            .getString(R.string.firmware_upgrade_automatic_retry));
                            if (!upgradeData.isNull(
                                    context.getResources().getString(R.string.firmware_upgrade_automatic_retry))) {
                                isAutomaticRetry = upgradeData.getBoolean(context.getResources()
                                        .getString(R.string.firmware_upgrade_automatic_retry));
                            }
                            CommonUtils.callAgentApp(context, Constants.Operation.FIRMWARE_UPGRADE_AUTOMATIC_RETRY,
                                    0, (isAutomaticRetry ? "true" : "false"));
                        } catch (JSONException e) {
                            String error = "Failed to build JSON object form the request: " + command;
                            Log.e(TAG, error);
                            Preference.putString(context,
                                    context.getResources().getString(R.string.upgrade_download_status),
                                    Constants.Status.MALFORMED_REQUEST);
                            CommonUtils.sendBroadcast(context, Constants.Operation.UPGRADE_FIRMWARE,
                                    Constants.Code.FAILURE, Constants.Status.MALFORMED_REQUEST, error);
                            break;
                        }
                    case Constants.Operation.GET_FIRMWARE_UPGRADE_PACKAGE_STATUS:
                    case Constants.Operation.GET_FIRMWARE_BUILD_DATE:
                    case Constants.Operation.GET_FIRMWARE_UPGRADE_DOWNLOAD_PROGRESS:
                        doTask(operationCode);
                        break;
                    default:
                        Log.e(TAG, "Invalid operation code: " + operationCode);
                        break;
                    }
                }
            }
        }
        context.registerReceiver(new BatteryChargingStateReceiver(),
                new IntentFilter(Intent.ACTION_BATTERY_CHANGED));

        //Checking is there any interrupted firmware download is there
        String status = Preference.getString(context,
                context.getResources().getString(R.string.upgrade_download_status));
        if (Constants.Status.OTA_UPGRADE_ONGOING.equals(status)) {
            Preference.putString(context, context.getResources().getString(R.string.upgrade_download_status),
                    Constants.Status.REQUEST_PLACED);
            Timer timeoutTimer = new Timer();
            timeoutTimer.schedule(new TimerTask() {
                @Override
                public void run() {
                    if (Constants.Status.REQUEST_PLACED.equals(Preference.getString(context,
                            context.getResources().getString(R.string.upgrade_download_status)))) {
                        if (Preference.getBoolean(context,
                                context.getResources().getString(R.string.firmware_upgrade_automatic_retry))) {
                            Log.i(TAG,
                                    "Found incomplete firmware download. Proceeding with last download request from the agent.");
                            OTADownload otaDownload = new OTADownload(context);
                            otaDownload.startOTA();
                        }
                    }
                }
            }, Constants.FIRMWARE_UPGRADE_READ_TIMEOUT);
        }
    }

    private void startAdmin() {
        Intent intentDeviceAdmin = new Intent(this, MainActivity.class);
        intentDeviceAdmin.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intentDeviceAdmin);
    }

    /**
     * Executes device management operations on the device.
     *
     * @param operationCode - Operation object.
     */
    public void doTask(String operationCode) {
        switch (operationCode) {
        case Constants.Operation.DEVICE_LOCK:
            enableHardLock();
            break;
        case Constants.Operation.DEVICE_UNLOCK:
            disableHardLock();
            break;
        case Constants.Operation.ENABLE_ADMIN:
            startAdmin();
            break;
        case Constants.Operation.UPGRADE_FIRMWARE:
            upgradeFirmware(false);
            break;
        case Constants.Operation.REBOOT:
            rebootDevice();
            break;
        case Constants.Operation.EXECUTE_SHELL_COMMAND:
            if (command != null) {
                executeShellCommand(command);
            }
            break;
        case Constants.Operation.SILENT_INSTALL_APPLICATION:
        case Constants.Operation.SILENT_UPDATE_APPLICATION:
            if (appUri != null) {
                silentInstallApp(getApplicationContext(), appUri);
            }
            break;
        case Constants.Operation.SILENT_UNINSTALL_APPLICATION:
            if (appUri != null) {
                silentUninstallApp(getApplicationContext(), appUri);
            }
            break;
        case Constants.Operation.REMOVE_DEVICE_OWNER:
            SettingsManager.clearDeviceOwner();
            break;
        case Constants.Operation.DISALLOW_ADJUST_VOLUME:
            SettingsManager.restrict(DISALLOW_ADJUST_VOLUME, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_ADD_USER:
            SettingsManager.restrict(DISALLOW_ADD_USER, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_APPS_CONTROL:
            SettingsManager.restrict(DISALLOW_APPS_CONTROL, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_CONFIG_BLUETOOTH:
            SettingsManager.restrict(DISALLOW_CONFIG_BLUETOOTH, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_CONFIG_CELL_BROADCASTS:
            SettingsManager.restrict(DISALLOW_CONFIG_CELL_BROADCASTS, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_CONFIG_CREDENTIALS:
            SettingsManager.restrict(DISALLOW_CONFIG_CREDENTIALS, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_CONFIG_MOBILE_NETWORKS:
            SettingsManager.restrict(DISALLOW_CONFIG_MOBILE_NETWORKS, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_CONFIG_TETHERING:
            SettingsManager.restrict(DISALLOW_CONFIG_TETHERING, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_CONFIG_VPN:
            SettingsManager.restrict(DISALLOW_CONFIG_VPN, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_CONFIG_WIFI:
            SettingsManager.restrict(DISALLOW_CONFIG_WIFI, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_CREATE_WINDOWS:
            SettingsManager.restrict(DISALLOW_CREATE_WINDOWS, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_CROSS_PROFILE_COPY_PASTE:
            SettingsManager.restrict(DISALLOW_CROSS_PROFILE_COPY_PASTE, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_DEBUGGING_FEATURES:
            SettingsManager.restrict(DISALLOW_DEBUGGING_FEATURES, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_FACTORY_RESET:
            SettingsManager.restrict(DISALLOW_FACTORY_RESET, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_INSTALL_APPS:
            SettingsManager.restrict(DISALLOW_INSTALL_APPS, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_INSTALL_UNKNOWN_SOURCES:
            SettingsManager.restrict(DISALLOW_INSTALL_UNKNOWN_SOURCES, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_MODIFY_ACCOUNTS:
            SettingsManager.restrict(DISALLOW_MODIFY_ACCOUNTS, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_MOUNT_PHYSICAL_MEDIA:
            SettingsManager.restrict(DISALLOW_MOUNT_PHYSICAL_MEDIA, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_NETWORK_RESET:
            SettingsManager.restrict(DISALLOW_NETWORK_RESET, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_OUTGOING_BEAM:
            SettingsManager.restrict(DISALLOW_OUTGOING_BEAM, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_OUTGOING_CALLS:
            SettingsManager.restrict(DISALLOW_OUTGOING_CALLS, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_REMOVE_USER:
            SettingsManager.restrict(DISALLOW_REMOVE_USER, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_SAFE_BOOT:
            SettingsManager.restrict(DISALLOW_SAFE_BOOT, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_SHARE_LOCATION:
            SettingsManager.restrict(DISALLOW_SHARE_LOCATION, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_SMS:
            SettingsManager.restrict(DISALLOW_SMS, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_UNINSTALL_APPS:
            SettingsManager.restrict(DISALLOW_UNINSTALL_APPS, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_UNMUTE_MICROPHONE:
            SettingsManager.restrict(DISALLOW_UNMUTE_MICROPHONE, restrictionCode);
            break;
        case Constants.Operation.DISALLOW_USB_FILE_TRANSFER:
            SettingsManager.restrict(DISALLOW_USB_FILE_TRANSFER, restrictionCode);
            break;
        case Constants.Operation.ENSURE_VERIFY_APPS:
            SettingsManager.restrict(ENSURE_VERIFY_APPS, restrictionCode);
            break;
        case Constants.Operation.ALLOW_PARENT_PROFILE_APP_LINKING:
            SettingsManager.restrict(ALLOW_PARENT_PROFILE_APP_LINKING, restrictionCode);
            break;
        case Constants.Operation.AUTO_TIME:
            SettingsManager.setAutoTimeRequired(restrictionCode);
            break;
        case Constants.Operation.SET_SCREEN_CAPTURE_DISABLED:
            SettingsManager.setScreenCaptureDisabled(restrictionCode);
            break;
        case Constants.Operation.APP_RESTRICTION:
            if (command != null && (command.equals("true") || command.equals("false"))) {
                SettingsManager.setVisibilityOfApp(appUri, Boolean.parseBoolean(command));
            }
            break;
        //Only With Android M.
        case Constants.Operation.SET_STATUS_BAR_DISABLED:
            SettingsManager.setStatusBarDisabled(restrictionCode);
            break;
        case Constants.Operation.GET_FIRMWARE_UPGRADE_PACKAGE_STATUS:
            upgradeFirmware(true);
            break;
        case Constants.Operation.WIPE_DATA:
            try {
                Runtime.getRuntime().exec("sh");
                Runtime.getRuntime().exec("am broadcast -a android.intent.action.MASTER_CLEAR");
            } catch (IOException e) {
                Log.e("TAG", "Shell command execution failed." + e);
            }
            break;
        case Constants.Operation.GET_FIRMWARE_UPGRADE_DOWNLOAD_PROGRESS:
            publishFirmwareDownloadProgress();
            break;
        case Constants.Operation.GET_FIRMWARE_BUILD_DATE:
            publishFirmwareBuildDate();
            break;
        case Constants.Operation.LOGCAT:
            getLogCat(command);
            break;
        default:
            Log.e(TAG, "Invalid operation code received");
            break;
        }
    }

    /**
     * Returns the device LogCat
     */
    public void getLogCat(String command) {
        try {
            JSONObject commandObj = new JSONObject(command);
            String filePath = Environment.getLegacyExternalStorageDirectory() + "/logcat"
                    + commandObj.getInt("operation_id") + ".log";
            String[] cmd = new String[] { "logcat", "-d", "-v", "time", commandObj.getString("log_level") };
            Process process = Runtime.getRuntime().exec(cmd);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            PrintWriter writer = new PrintWriter(filePath, "UTF-8");
            while ((line = bufferedReader.readLine()) != null) {
                writer.println(line);
            }
            writer.close();
            CommonUtils.callAgentApp(context, Constants.Operation.LOGCAT, commandObj.getInt("operation_id"),
                    filePath);
        } catch (IOException e) {
            Log.e(TAG, "getLog failed", e);
        } catch (JSONException e) {
            Log.e(TAG, "Unable to parse command string", e);
        }
    }

    /**
     * Upgrading device firmware over the air (OTA).
     */
    public void upgradeFirmware(final boolean isStatusCheck) {
        Log.i(TAG, "An upgrade has been requested");

        Preference.putBoolean(context, context.getResources().getString(R.string.firmware_status_check_in_progress),
                isStatusCheck);
        Preference.putString(context, context.getResources().getString(R.string.firmware_download_progress),
                String.valueOf(DEFAULT_STATE_INFO_CODE));
        Preference.putInt(context, context.getResources().getString(R.string.operation_id), operationId);

        String schedule = null;
        String server;
        if (command != null && !command.trim().isEmpty()) {
            try {
                JSONObject upgradeData = new JSONObject(command);
                if (!upgradeData.isNull(context.getResources().getString(R.string.alarm_schedule))) {
                    schedule = (String) upgradeData.get(context.getResources().getString(R.string.alarm_schedule));
                }

                boolean isAutomaticRetry = (Preference.hasPreferenceKey(context,
                        context.getResources().getString(R.string.firmware_upgrade_automatic_retry))
                        && Preference.getBoolean(context,
                                context.getResources().getString(R.string.firmware_upgrade_automatic_retry)))
                        || !Preference.hasPreferenceKey(context,
                                context.getResources().getString(R.string.firmware_upgrade_automatic_retry));
                if (!upgradeData
                        .isNull(context.getResources().getString(R.string.firmware_upgrade_automatic_retry))) {
                    isAutomaticRetry = upgradeData.getBoolean(
                            context.getResources().getString(R.string.firmware_upgrade_automatic_retry));
                    if (!isAutomaticRetry) {
                        Log.i(TAG, "Automatic retry on firmware upgrade failure is disabled.");
                    }
                }

                Preference.putBoolean(context,
                        context.getResources().getString(R.string.firmware_upgrade_automatic_retry),
                        isAutomaticRetry);

                if (!upgradeData.isNull(context.getResources().getString(R.string.firmware_server))) {
                    server = (String) upgradeData.get(context.getResources().getString(R.string.firmware_server));
                    // When the server is empty, that means it is indicating to download from default server
                    if (!server.isEmpty() && !Patterns.WEB_URL.matcher(server).matches()) {
                        String message = "Firmware upgrade URL provided is not valid.";
                        CommonUtils.sendBroadcast(context, Constants.Operation.UPGRADE_FIRMWARE,
                                Constants.Code.FAILURE, Constants.Status.MALFORMED_OTA_URL, message);
                        CommonUtils.callAgentApp(context, Constants.Operation.FIRMWARE_UPGRADE_FAILURE,
                                Preference.getInt(context, context.getResources().getString(R.string.operation_id)),
                                message);
                        Log.e(TAG, message);
                        return;
                    } else {
                        Preference.putString(context, context.getResources().getString(R.string.firmware_server),
                                server);
                    }
                }
            } catch (JSONException e) {
                Log.e(TAG, "Firmware upgrade payload parsing failed." + e);
                return;
            }
        }
        if (schedule != null && !schedule.trim().isEmpty()) {
            Log.i(TAG, "Upgrade scheduled received: " + schedule);
            Preference.putString(context, context.getResources().getString(R.string.alarm_schedule), schedule);
            try {
                AlarmUtils.setOneTimeAlarm(context, schedule, Constants.Operation.UPGRADE_FIRMWARE, null);
            } catch (ParseException e) {
                CommonUtils.sendBroadcast(context, Constants.Operation.UPGRADE_FIRMWARE, Constants.Code.FAILURE,
                        Constants.Status.MALFORMED_REQUEST, e.getMessage());
            }
        } else {
            if (isStatusCheck) {
                Log.i(TAG, "Firmware status check is initiated by admin.");
            } else {
                Log.i(TAG, "Upgrade request initiated by admin.");

                String status = Preference.getString(context,
                        context.getResources().getString(R.string.upgrade_download_status));
                boolean isAutomaticUpgrade = Preference.getBoolean(context,
                        context.getResources().getString(R.string.firmware_upgrade_automatic_retry));

                if (Constants.Status.WIFI_OFF.equals(status) && isAutomaticUpgrade && !checkNetworkOnline()) {
                    String msg = "Ignoring request as service waiting for WiFi to start upgrade.";
                    Log.d(TAG, msg);
                    CommonUtils.sendBroadcast(context, Constants.Operation.UPGRADE_FIRMWARE, Constants.Code.PENDING,
                            Constants.Status.OTA_UPGRADE_PENDING, msg);
                    return;
                } else if (Constants.Status.OTA_UPGRADE_ONGOING.equals(status)) {
                    String msg = "Checking for existing download. Will proceed this request if current download is no longer ongoing.";
                    Log.d(TAG, msg);
                    CommonUtils.sendBroadcast(context, Constants.Operation.UPGRADE_FIRMWARE, Constants.Code.PENDING,
                            Constants.Status.OTA_UPGRADE_ONGOING, msg);
                    Preference.putString(context,
                            context.getResources().getString(R.string.upgrade_download_status),
                            Constants.Status.REQUEST_PLACED);
                    Timer timeoutTimer = new Timer();
                    timeoutTimer.schedule(new TimerTask() {
                        @Override
                        public void run() {
                            if (Constants.Status.REQUEST_PLACED.equals(Preference.getString(context,
                                    context.getResources().getString(R.string.upgrade_download_status)))) {
                                Log.d(TAG,
                                        "Download is no longer ongoing. Proceeding download request from the agent.");
                                OTADownload otaDownload = new OTADownload(context);
                                otaDownload.startOTA();
                            } else {
                                String msg = "Request ignored because another download is ongoing.";
                                Log.d(TAG, msg);
                                CommonUtils.sendBroadcast(context, Constants.Operation.UPGRADE_FIRMWARE,
                                        Constants.Code.FAILURE, Constants.Status.OTA_UPGRADE_ONGOING, msg);
                            }
                        }
                    }, Constants.FIRMWARE_UPGRADE_READ_TIMEOUT);
                    return;
                }
            }

            //Prepare for upgrade
            OTADownload otaDownload = new OTADownload(context);
            otaDownload.startOTA();
        }
    }

    private boolean checkNetworkOnline() {
        ConnectivityManager connectivityManager = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = connectivityManager.getActiveNetworkInfo();
        boolean status = false;
        if (info != null && info.isConnectedOrConnecting()) {
            status = true;
        }

        return status;
    }

    /**
     * Rebooting the device.
     */
    private void rebootDevice() {
        Log.i(TAG, "Reboot request initiated by admin.");
        try {
            Thread.sleep(5000);
            PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
            powerManager.reboot(null);
        } catch (InterruptedException e) {
            Log.e(TAG, "Reboot initiating thread interrupted." + e);
        }
    }

    /**
     * Executing shell commands as super user.
     */
    private void executeShellCommand(String command) {
        Process process;
        try {
            process = Runtime.getRuntime().exec("sh");
            DataOutputStream dataOutputStream = new DataOutputStream(process.getOutputStream());
            dataOutputStream.writeBytes("am start " + command + "\\n");
            dataOutputStream.writeBytes("exit\n");
            dataOutputStream.flush();
        } catch (IOException e) {
            Log.e(TAG, "Shell command execution failed." + e);
        }
    }

    /**
     * Silently installs the app resides in the provided URI.
     */
    private void silentInstallApp(Context context, String packageUri) {
        AppUtils.silentInstallApp(context, Uri.parse(packageUri));
    }

    /**
     * Silently uninstalls the app resides in the provided URI.
     */
    private void silentUninstallApp(Context context, final String packageName) {
        AppUtils.silentUninstallApp(context, packageName);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void enableHardLock() {
        String message = context.getResources().getString(R.string.txt_lock_activity);
        if (appUri != null && !appUri.isEmpty()) {
            message = appUri;
        }
        if (SettingsManager.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.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
            intent.putExtra(Constants.ADMIN_MESSAGE, message);
            intent.putExtra(Constants.IS_LOCKED, true);
            context.startActivity(intent);
        } else {
            Log.e(TAG, "Device owner is not set, hence executing default lock");
            devicePolicyManager.lockNow();
        }
    }

    private void publishFirmwareDownloadProgress() {
        String status = Preference.getString(context,
                context.getResources().getString(R.string.upgrade_download_status));
        Log.d(TAG, "Current status: " + status);
        boolean isAutomaticRetry = (Preference.hasPreferenceKey(context,
                context.getResources().getString(R.string.firmware_upgrade_automatic_retry))
                && Preference.getBoolean(context,
                        context.getResources().getString(R.string.firmware_upgrade_automatic_retry)))
                || !Preference.hasPreferenceKey(context,
                        context.getResources().getString(R.string.firmware_upgrade_automatic_retry));
        String statusCode = isAutomaticRetry ? Constants.Code.PENDING : Constants.Code.FAILURE;

        if (status == null) {
            CommonUtils.sendBroadcast(context, Constants.Operation.GET_FIRMWARE_UPGRADE_DOWNLOAD_PROGRESS,
                    Constants.Code.SUCCESS, Constants.Status.NO_HISTORY, "History not found");
            return;
        }

        switch (status) {
        case Constants.Status.MALFORMED_REQUEST:
            CommonUtils.sendBroadcast(context, Constants.Operation.GET_FIRMWARE_UPGRADE_DOWNLOAD_PROGRESS,
                    Constants.Code.FAILURE, Constants.Status.MALFORMED_REQUEST, null);
            break;
        case Constants.Status.WIFI_OFF:
            CommonUtils.sendBroadcast(context, Constants.Operation.GET_FIRMWARE_UPGRADE_DOWNLOAD_PROGRESS,
                    statusCode, Constants.Status.WIFI_OFF, null);
            break;
        case Constants.Status.NETWORK_UNREACHABLE:
            CommonUtils.sendBroadcast(context, Constants.Operation.GET_FIRMWARE_UPGRADE_DOWNLOAD_PROGRESS,
                    statusCode, Constants.Status.NETWORK_UNREACHABLE, null);
            break;
        case Constants.Status.BATTERY_LEVEL_INSUFFICIENT_TO_DOWNLOAD:
            CommonUtils.sendBroadcast(context, Constants.Operation.GET_FIRMWARE_UPGRADE_DOWNLOAD_PROGRESS,
                    statusCode, Constants.Status.BATTERY_LEVEL_INSUFFICIENT_TO_DOWNLOAD, null);
            break;
        case Constants.Status.LOW_DISK_SPACE:
            CommonUtils.sendBroadcast(context, Constants.Operation.GET_FIRMWARE_UPGRADE_DOWNLOAD_PROGRESS,
                    Constants.Code.FAILURE, Constants.Status.LOW_DISK_SPACE, null);
            break;
        case Constants.Status.FILE_NOT_FOUND:
            CommonUtils.sendBroadcast(context, Constants.Operation.GET_FIRMWARE_UPGRADE_DOWNLOAD_PROGRESS,
                    Constants.Code.FAILURE, Constants.Status.FILE_NOT_FOUND, null);
            break;
        case Constants.Status.CONNECTION_FAILED:
            CommonUtils.sendBroadcast(context, Constants.Operation.GET_FIRMWARE_UPGRADE_DOWNLOAD_PROGRESS,
                    Constants.Code.FAILURE, Constants.Status.CONNECTION_FAILED, null);
            break;
        case Constants.Status.REQUEST_PLACED:
            CommonUtils.sendBroadcast(context, Constants.Operation.GET_FIRMWARE_UPGRADE_DOWNLOAD_PROGRESS,
                    Constants.Code.PENDING, Constants.Status.REQUEST_PLACED, null);
            break;
        case Constants.Status.OTA_UPGRADE_ONGOING:
            long progress;
            JSONObject result = new JSONObject();
            if (Preference.getString(context,
                    context.getResources().getString(R.string.firmware_download_progress)) != null) {
                progress = Long.valueOf(Preference.getString(context,
                        context.getResources().getString(R.string.firmware_download_progress)));
            } else {
                progress = DEFAULT_STATE_INFO_CODE;
            }
            try {
                result.put("progress", String.valueOf(progress));
                CommonUtils.sendBroadcast(context, Constants.Operation.GET_FIRMWARE_UPGRADE_DOWNLOAD_PROGRESS,
                        Constants.Code.SUCCESS, Constants.Status.OTA_UPGRADE_ONGOING, result.toString());
            } catch (JSONException e) {
                String error = "Failed to create JSON object when publishing OTA progress.";
                Log.e(TAG, error, e);
                CommonUtils.sendBroadcast(context, Constants.Operation.GET_FIRMWARE_UPGRADE_DOWNLOAD_PROGRESS,
                        Constants.Code.FAILURE, Constants.Status.INTERNAL_ERROR, error);
            }
            break;
        }
    }

    private void disableHardLock() {
        Intent intent = new Intent(context, MainActivity.class);
        intent.setFlags(
                Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }

    private void publishFirmwareBuildDate() {
        String buildDate;
        JSONObject result = new JSONObject();

        buildDate = SystemProperties.get(BUILD_DATE_UTC_PROPERTY);
        try {
            result.put("buildDate", buildDate);
            CommonUtils.sendBroadcast(context, Constants.Operation.GET_FIRMWARE_BUILD_DATE, Constants.Code.SUCCESS,
                    Constants.Status.SUCCESSFUL, result.toString());
        } catch (JSONException e) {
            String error = "Failed to create JSON object when publishing OTA progress.";
            Log.e(TAG, error, e);
            CommonUtils.sendBroadcast(context, Constants.Operation.GET_FIRMWARE_BUILD_DATE, Constants.Code.FAILURE,
                    Constants.Status.INTERNAL_ERROR, String.valueOf(DEFAULT_STATE_INFO_CODE));
        }
    }

}