Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 476ce6cf authored by Roman Birg's avatar Roman Birg
Browse files

Settings: add killswitch logic to factory reset screen



Change-Id: I8b9cb53ede9f7ebc54d37e7b863fe74e7262e9c1
Signed-off-by: default avatarRoman Birg <roman@cyngn.com>
parent 29041d7f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@
    <uses-permission android:name="android.permission.OEM_UNLOCK_STATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.HARDWARE_ABSTRACTION_ACCESS" />
    <uses-permission android:name="com.cyanogen.permission.REQUEST_KILL_SWITCH_OP" />

    <permission
        android:name="cyanogenmod.permission.PROTECTED_APP"
+7 −0
Original line number Diff line number Diff line
@@ -1222,4 +1222,11 @@
    <string name="master_clear_desc_cm" product="tablet">This will erase all data from your tablet\'s <b>internal storage</b>, including:\n\n<li>Your device accounts</li>\n<li>System and app data and settings</li>\n<li>Downloaded apps</li></string>
    <!-- SD card & phone storage settings screen, message on screen after user selects Factory data reset [CHAR LIMIT=NONE] -->
    <string name="master_clear_desc_cm" product="default">This will erase all data from your phone\'s <b>internal storage</b>, including:\n\n<li>Your device accounts</li>\n<li>System and app data and settings</li>\n<li>Downloaded apps</li></string>

    <!-- Killswitch -->
    <string name="lock_to_cyanogen_title">Device Protection</string>
    <string name="lock_to_cyanogen_summary">Require your Cyanogen OS account password even after a factory reset</string>
    <string name="lock_to_cyanogen_create_account_msg">Your device uses the Cyanogen OS account password to protect your device even in the event of a factory reset. You will need to create a Cyanogen OS account.</string>
    <string name="lock_to_cyanogen_disable_msg">Disabling this feature will allow unauthorized users to reset your phone to factory defaults if it is stolen. Your personal data may not be protected. Do you want to disable this feature?</string>
    <string name="lock_to_cyanogen_master_clear_warning">Device Protection is enabled. Please disable to continue resetting your device.</string>
</resources>
+5 −0
Original line number Diff line number Diff line
@@ -46,6 +46,11 @@
                        android:title="@string/device_admin_title"
                        android:persistent="false">

        <SwitchPreference android:key="lock_to_cyanogen_account"
                          android:title="@string/lock_to_cyanogen_title"
                          android:summary="@string/lock_to_cyanogen_summary"
                          android:persistent="false" />

        <Preference android:key="manage_device_admin"
                    android:title="@string/manage_device_admin"
                    android:summary="@string/manage_device_admin_summary"
+36 −1
Original line number Diff line number Diff line
@@ -20,8 +20,10 @@ import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorDescription;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
@@ -61,6 +63,7 @@ public class MasterClear extends Fragment {
    private static final String TAG = "MasterClear";

    private static final int KEYGUARD_REQUEST = 55;
    private static final int LOCK_REQUEST = 56;

    static final String ERASE_EXTERNAL_EXTRA = "erase_sd";

@@ -86,7 +89,12 @@ public class MasterClear extends Fragment {
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode != KEYGUARD_REQUEST) {
        if (requestCode == LOCK_REQUEST) {
            if (resultCode != Activity.RESULT_OK) {
                getActivity().finish();
            }
            return;
        } else if (requestCode != KEYGUARD_REQUEST) {
            return;
        }

@@ -302,4 +310,31 @@ public class MasterClear extends Fragment {
                0);
        return inflater.inflate(resId, parent, false);
    }

    @Override
    public void onResume() {
        super.onResume();

        if (SecuritySettings.isDeviceLocked()) {
            new AlertDialog.Builder(getActivity())
                    .setMessage(R.string.lock_to_cyanogen_master_clear_warning)
                    .setNegativeButton(R.string.wizard_back, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            getActivity().finish();
                        }
                    })
                    .setPositiveButton(R.string.lockpassword_continue_label, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            SecuritySettings.updateCyanogenDeviceLockState(MasterClear.this,
                                    false, LOCK_REQUEST);
                        }
                    })
                    .setCancelable(false)
                    .create()
                    .show();

        }
    }
}
+161 −1
Original line number Diff line number Diff line
@@ -22,6 +22,13 @@ package com.android.settings;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AppOpsManager;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorDescription;
import android.app.AlertDialog;
import android.app.Fragment;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
@@ -32,6 +39,8 @@ import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.preference.SwitchPreference;
@@ -51,6 +60,7 @@ import android.telephony.SubscriptionInfo;
import android.text.TextUtils;
import android.util.Log;

import com.android.internal.os.IKillSwitchService;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.TrustAgentUtils.TrustAgentComponentInfo;
import com.android.settings.search.BaseSearchIndexProvider;
@@ -86,11 +96,22 @@ public class SecuritySettings extends SettingsPreferenceFragment
    private static final String KEY_CREDENTIALS_MANAGER = "credentials_management";
    private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
    private static final String KEY_SCREEN_PINNING = "screen_pinning_settings";

    // Cyanogen device lock
    public static final String ACCOUNT_TYPE_CYANOGEN = "com.cyanogen";
    private static final String EXTRA_CREATE_ACCOUNT = "create-account";
    private static final String LOCK_TO_CYANOGEN_ACCOUNT = "lock_to_cyanogen_account";
    private static final String EXTRA_LOGIN_FOR_KILL_SWITCH = "authCks";
    private static final String EXTRA_CKSOP = "cksOp";
    private static final int LOCK_REQUEST = 57;

    private SwitchPreference mLockDeviceToCyanogenAccount;

    private static final String KEY_SMS_SECURITY_CHECK_PREF = "sms_security_check_limit";

    // These switch preferences need special handling since they're not all stored in Settings.
    private static final String SWITCH_PREFERENCE_KEYS[] = { KEY_SHOW_PASSWORD,
            KEY_TOGGLE_INSTALL_APPLICATIONS };
            KEY_TOGGLE_INSTALL_APPLICATIONS, LOCK_TO_CYANOGEN_ACCOUNT };

    // Only allow one trust agent on the platform.
    private static final boolean ONLY_ONE_TRUST_AGENT = false;
@@ -241,6 +262,15 @@ public class SecuritySettings extends SettingsPreferenceFragment
        mToggleAppInstallation = (SwitchPreference) findPreference(
                KEY_TOGGLE_INSTALL_APPLICATIONS);
        mToggleAppInstallation.setChecked(isNonMarketAppsAllowed());

        // Cyanogen kill switch
        mLockDeviceToCyanogenAccount = (SwitchPreference)
                deviceAdminCategory.findPreference(LOCK_TO_CYANOGEN_ACCOUNT);
        if (!hasKillSwitch(getActivity())) {
            deviceAdminCategory.removePreference(mLockDeviceToCyanogenAccount);
            mLockDeviceToCyanogenAccount = null;
        }

        // Side loading of apps.
        // Disable for restricted profiles. For others, check if policy disallows it.
        mToggleAppInstallation.setEnabled(!um.getUserInfo(UserHandle.myUserId()).isRestricted());
@@ -332,6 +362,79 @@ public class SecuritySettings extends SettingsPreferenceFragment
        return result;
    }

    private boolean hasLoggedInCyanogenAccount(Context context) {
        AccountManager accountManager = (AccountManager)
                context.getSystemService(Context.ACCOUNT_SERVICE);
        Account[] accountsByType = accountManager.getAccountsByType(ACCOUNT_TYPE_CYANOGEN);
        return accountsByType != null && accountsByType.length > 0;
    }

    public static boolean hasKillSwitch(Context context) {
        IBinder b = ServiceManager.getService(Context.KILLSWITCH_SERVICE);
        IKillSwitchService service = IKillSwitchService.Stub.asInterface(b);
        if (service != null) {
            try {
                return service.hasKillSwitch() && hasCyanogenAccountType(context);
            } catch (Exception e) {
                // silently fail
            }
        }
        return false;
    }

    public static boolean hasCyanogenAccountType(Context context) {
        AccountManager accountManager = (AccountManager)
                context.getSystemService(Context.ACCOUNT_SERVICE);
        for (AuthenticatorDescription authenticatorDescription :
                accountManager.getAuthenticatorTypes()) {
            if (authenticatorDescription.type.equals(ACCOUNT_TYPE_CYANOGEN)) {
                return true;
            }
        }
        return false;
    }

    public static boolean isDeviceLocked() {
        IBinder b = ServiceManager.getService(Context.KILLSWITCH_SERVICE);
        IKillSwitchService service = IKillSwitchService.Stub.asInterface(b);
        if (service != null) {
            try {
                return service.isDeviceLocked();
            } catch (Exception e) {
                // silently fail
            }
        }
        return false;
    }

    public static void updateCyanogenDeviceLockState(final Fragment fragment,
                                                     final boolean setCks,
                                                     final int activityRequestCode) {
        AccountManager.get(fragment.getActivity()).editProperties(ACCOUNT_TYPE_CYANOGEN, null,
                new AccountManagerCallback<Bundle>() {
                    public void run(AccountManagerFuture<Bundle> f) {
                        try {
                            Bundle b = f.getResult();
                            Intent i = b.getParcelable(AccountManager.KEY_INTENT);
                            i.putExtra(EXTRA_CKSOP, setCks ? 1 : 0);
                            i.putExtra(EXTRA_LOGIN_FOR_KILL_SWITCH, true);
                            fragment.startActivityForResult(i, activityRequestCode);
                        } catch (Throwable t) {
                            Log.e(TAG, "confirmCredentials failed", t);
                        }
                    }
                }, null);
    }


    private int getNumEnabledNotificationListeners() {
        final String flat = Settings.Secure.getString(getContentResolver(),
                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
        if (flat == null || "".equals(flat)) return 0;
        final String[] components = flat.split(":");
        return components.length;
    }

    private boolean isNonMarketAppsAllowed() {
        return Settings.Global.getInt(getContentResolver(),
                                      Settings.Global.INSTALL_NON_MARKET_APPS, 0) > 0;
@@ -382,6 +485,12 @@ public class SecuritySettings extends SettingsPreferenceFragment
        mSmsSecurityCheck.setSummary(message);
    }

    private void updateDeviceLockState() {
        if (mLockDeviceToCyanogenAccount != null) {
            mLockDeviceToCyanogenAccount.setChecked(isDeviceLocked());
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
@@ -403,6 +512,8 @@ public class SecuritySettings extends SettingsPreferenceFragment
        if (mResetCredentials != null) {
            mResetCredentials.setEnabled(!mKeyStore.isEmpty());
        }

        updateDeviceLockState();
    }

    @Override
@@ -426,6 +537,55 @@ public class SecuritySettings extends SettingsPreferenceFragment
            Settings.Secure.putInt(getContentResolver(), Settings.Global.SMS_OUTGOING_CHECK_MAX_COUNT,
                    smsSecurityCheck);
            updateSmsSecuritySummary(smsSecurityCheck);
        } else if (LOCK_TO_CYANOGEN_ACCOUNT.equals(key)) {
            if (((Boolean) value)) {
                // wants to opt in.
                if (hasLoggedInCyanogenAccount(getActivity())) {
                    updateCyanogenDeviceLockState(this, true, LOCK_REQUEST);
                } else {
                    // no account, need to create one!
                    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
                            .setMessage(R.string.lock_to_cyanogen_create_account_msg)
                            .setPositiveButton(android.R.string.ok,
                                    new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            // create new account
                                            AccountManager accountManager = (AccountManager)
                                                    getActivity()
                                                        .getSystemService(Context.ACCOUNT_SERVICE);
                                            Bundle opts = new Bundle();
                                            opts.putBoolean(EXTRA_CREATE_ACCOUNT, true);
                                            opts.putInt(EXTRA_CKSOP, 1);

                                            accountManager.addAccount(ACCOUNT_TYPE_CYANOGEN,
                                                    null, null, opts, getActivity(), null, null);
                                        }
                                    });
                    builder.create().show();
                }
            } else {
                //  opt out
                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
                        .setCancelable(false)
                        .setMessage(R.string.lock_to_cyanogen_disable_msg)
                        .setNegativeButton(android.R.string.no,
                                new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        updateDeviceLockState();
                                    }
                                })
                        .setPositiveButton(android.R.string.yes,
                                new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        updateCyanogenDeviceLockState(SecuritySettings.this,
                                                false, LOCK_REQUEST);
                                    }
                                });
                builder.create().show();
            }
        }
        return result;
    }
Loading