diff --git a/AndroidManifest.xml b/AndroidManifest.xml index d4a7826..d575831 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -47,6 +47,7 @@ + + + + + + + + + + + + + + + Use on screen navigation keys instead of hardware keys. Use secure SMS %s to encrypt SMS conversations with other users using secure SMS on a %s device. + + Unlock + This device has been locked by the user. + Require your Cyanogen OS account password in order to use your device even after a factory reset. + To turn this feature off/on, please go to Settings > Security + Without a Cyanogen OS Account, you won\'t be able to:\n\nCustomize your phone with new icons, wallpapers and more in the Themes app\n\nLocate or remotely erase your phone if it\'s lost diff --git a/src/com/cyanogenmod/setupwizard/SetupWizardApp.java b/src/com/cyanogenmod/setupwizard/SetupWizardApp.java index a1d644b..82b466d 100644 --- a/src/com/cyanogenmod/setupwizard/SetupWizardApp.java +++ b/src/com/cyanogenmod/setupwizard/SetupWizardApp.java @@ -34,6 +34,7 @@ public class SetupWizardApp extends Application { public static final String ACTION_FINISHED = "com.cyanogenmod.setupwizard.SETUP_FINISHED"; + public static final String ACCOUNT_TYPE_CYANOGEN = "com.cyanogen"; public static final String ACCOUNT_TYPE_GMS = "com.google"; public static final String ACTION_SETUP_WIFI = "com.android.net.wifi.SETUP_WIFI_NETWORK"; @@ -46,6 +47,8 @@ public class SetupWizardApp extends Application { public static final String EXTRA_USE_IMMERSIVE = "useImmersiveMode"; public static final String EXTRA_THEME = "theme"; public static final String EXTRA_MATERIAL_LIGHT = "material_light"; + public static final String EXTRA_CKSOP = "cksOp"; + public static final String EXTRA_LOGIN_FOR_KILL_SWITCH = "authCks"; private static final String KEY_DETECT_CAPTIVE_PORTAL = "captive_portal_detection_enabled"; @@ -61,11 +64,14 @@ public class SetupWizardApp extends Application { public static final int REQUEST_CODE_SETUP_CYANOGEN= 3; public static final int REQUEST_CODE_SETUP_CAPTIVE_PORTAL= 4; public static final int REQUEST_CODE_SETUP_BLUETOOTH= 5; + public static final int REQUEST_CODE_UNLOCK = 6; public static final int RADIO_READY_TIMEOUT = 10 * 1000; private boolean mIsRadioReady = false; + private boolean mIsAuthorized = false; + private StatusBarManager mStatusBarManager; private final Handler mHandler = new Handler(); @@ -114,6 +120,14 @@ public class SetupWizardApp extends Application { mIsRadioReady = radioReady; } + public boolean isAuthorized() { + return mIsAuthorized; + } + + public void setIsAuthorized(boolean isAuthorized) { + mIsAuthorized = isAuthorized; + } + public void disableStatusBar() { mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND | StatusBarManager.DISABLE_NOTIFICATION_ALERTS | StatusBarManager.DISABLE_NOTIFICATION_TICKER | StatusBarManager.DISABLE_RECENT | StatusBarManager.DISABLE_HOME diff --git a/src/com/cyanogenmod/setupwizard/setup/CyanogenServicesPage.java b/src/com/cyanogenmod/setupwizard/setup/CyanogenServicesPage.java index 479f2be..e71dd79 100644 --- a/src/com/cyanogenmod/setupwizard/setup/CyanogenServicesPage.java +++ b/src/com/cyanogenmod/setupwizard/setup/CyanogenServicesPage.java @@ -101,6 +101,9 @@ public class CyanogenServicesPage extends SetupPage { resultCode == Activity.RESULT_OK ? "success" : "skipped"); if (SetupWizardUtils.accountExists(mContext, mContext.getString(R.string.cm_account_type))) { + if (SetupWizardUtils.isDeviceLocked()) { + ((SetupWizardApp) mContext.getApplicationContext()).setIsAuthorized(true); + } setHidden(true); } getCallbacks().onNextPage(); diff --git a/src/com/cyanogenmod/setupwizard/setup/CyanogenSettingsPage.java b/src/com/cyanogenmod/setupwizard/setup/CyanogenSettingsPage.java index bdc3076..86906da 100644 --- a/src/com/cyanogenmod/setupwizard/setup/CyanogenSettingsPage.java +++ b/src/com/cyanogenmod/setupwizard/setup/CyanogenSettingsPage.java @@ -42,6 +42,7 @@ import android.view.IWindowManager; import android.view.View; import android.view.WindowManagerGlobal; import android.widget.CheckBox; +import android.widget.ImageView; import android.widget.TextView; import com.cyanogenmod.setupwizard.R; @@ -213,6 +214,9 @@ public class CyanogenSettingsPage extends SetupPage { public static class CyanogenSettingsFragment extends SetupPageFragment { + private View mKillSwitchView; + private TextView mKillSwitchTitle; + private ImageView mKillSwitchStatus; private View mMetricsRow; private View mDefaultThemeRow; private View mNavKeysRow; @@ -287,6 +291,21 @@ public class CyanogenSettingsPage extends SetupPage { privacyPolicy.setMovementMethod(LinkMovementMethod.getInstance()); privacyPolicy.setText(ss); + mKillSwitchView = mRootView.findViewById(R.id.killswitch); + mKillSwitchTitle = (TextView)mRootView.findViewById(R.id.killswitch_title); + mKillSwitchStatus = (ImageView)mRootView.findViewById(R.id.killswitch_check); + if (hideKillSwitch()) { + mKillSwitchView.setVisibility(View.GONE); + } else { + if (SetupWizardUtils.isDeviceLocked()) { + mKillSwitchTitle.setEnabled(true); + mKillSwitchStatus.setImageResource(R.drawable.tick); + } else { + mKillSwitchTitle.setEnabled(false); + mKillSwitchStatus.setImageResource(R.drawable.cross); + } + } + mMetricsRow = mRootView.findViewById(R.id.metrics); mMetricsRow.setOnClickListener(mMetricsClickListener); String metricsHelpImproveCM = @@ -414,5 +433,9 @@ public class CyanogenSettingsPage extends SetupPage { } } + private static boolean hideKillSwitch() { + return !SetupWizardUtils.hasKillSwitch(); + } + } } diff --git a/src/com/cyanogenmod/setupwizard/setup/WelcomePage.java b/src/com/cyanogenmod/setupwizard/setup/WelcomePage.java index 1f63878..3f01e53 100644 --- a/src/com/cyanogenmod/setupwizard/setup/WelcomePage.java +++ b/src/com/cyanogenmod/setupwizard/setup/WelcomePage.java @@ -16,6 +16,10 @@ package com.cyanogenmod.setupwizard.setup; +import android.accounts.AccountManager; +import android.accounts.AccountManagerCallback; +import android.accounts.AccountManagerFuture; +import android.app.Activity; import android.app.ActivityOptions; import android.app.Fragment; import android.app.FragmentManager; @@ -25,14 +29,17 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.os.Bundle; import android.os.Handler; +import android.util.Log; import android.view.View; import android.widget.ArrayAdapter; import android.widget.NumberPicker; import com.cyanogenmod.setupwizard.R; +import com.cyanogenmod.setupwizard.SetupWizardApp; import com.cyanogenmod.setupwizard.cmstats.SetupStats; import com.cyanogenmod.setupwizard.ui.LocalePicker; import com.cyanogenmod.setupwizard.ui.SetupPageFragment; +import com.cyanogenmod.setupwizard.util.SetupWizardUtils; import java.util.Locale; @@ -42,21 +49,23 @@ public class WelcomePage extends SetupPage { private static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL"; + private WelcomeFragment mWelcomeFragment; + public WelcomePage(Context context, SetupDataCallbacks callbacks) { super(context, callbacks); } @Override public Fragment getFragment(FragmentManager fragmentManager, int action) { - Fragment fragment = fragmentManager.findFragmentByTag(getKey()); - if (fragment == null) { + mWelcomeFragment = (WelcomeFragment)fragmentManager.findFragmentByTag(getKey()); + if (mWelcomeFragment == null) { Bundle args = new Bundle(); args.putString(Page.KEY_PAGE_ARGUMENT, getKey()); args.putInt(Page.KEY_PAGE_ACTION, action); - fragment = new WelcomeFragment(); - fragment.setArguments(args); + mWelcomeFragment = new WelcomeFragment(); + mWelcomeFragment.setArguments(args); } - return fragment; + return mWelcomeFragment; } @Override @@ -64,6 +73,16 @@ public class WelcomePage extends SetupPage { return R.string.setup_welcome; } + @Override + public boolean doNextAction() { + if (isLocked()) { + confirmCyanogenCredentials(mWelcomeFragment); + return true; + } else { + return super.doNextAction(); + } + } + @Override public boolean doPreviousAction() { Intent intent = new Intent(ACTION_EMERGENCY_DIAL); @@ -81,16 +100,66 @@ public class WelcomePage extends SetupPage { return true; } + @Override + public boolean onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == SetupWizardApp.REQUEST_CODE_UNLOCK) { + if (resultCode == Activity.RESULT_OK) { + ((SetupWizardApp) mContext.getApplicationContext()).setIsAuthorized(true); + getCallbacks().onNextPage(); + return true; + } + } + return false; + } + @Override public String getKey() { return TAG; } + @Override + public int getNextButtonTitleResId() { + if (isLocked()) { + return R.string.setup_unlock; + } else { + return R.string.next; + } + } + @Override public int getPrevButtonTitleResId() { return R.string.emergency_call; } + private void confirmCyanogenCredentials(final Fragment fragment) { + AccountManager accountManager = AccountManager.get(mContext); + accountManager.editProperties(SetupWizardApp.ACCOUNT_TYPE_CYANOGEN, null, + new AccountManagerCallback() { + public void run(AccountManagerFuture f) { + try { + Bundle b = f.getResult(); + Intent i = b.getParcelable(AccountManager.KEY_INTENT); + i.putExtra(SetupWizardApp.EXTRA_FIRST_RUN, true); + i.putExtra(SetupWizardApp.EXTRA_SHOW_BUTTON_BAR, true); + i.putExtra(SetupWizardApp.EXTRA_USE_IMMERSIVE, true); + i.putExtra(SetupWizardApp.EXTRA_LOGIN_FOR_KILL_SWITCH, true); + fragment.startActivityForResult(i, + SetupWizardApp.REQUEST_CODE_UNLOCK); + } catch (Throwable t) { + Log.e(getKey(), "confirmCredentials failed", t); + } + } + }, null); + } + + private boolean isLocked() { + boolean isAuthorized = ((SetupWizardApp) mContext.getApplicationContext()).isAuthorized(); + if (SetupWizardUtils.isDeviceLocked()) { + return !isAuthorized; + } + return false; + } + public static class WelcomeFragment extends SetupPageFragment { private ArrayAdapter mLocaleAdapter; diff --git a/src/com/cyanogenmod/setupwizard/util/SetupWizardUtils.java b/src/com/cyanogenmod/setupwizard/util/SetupWizardUtils.java index 19ce2e8..113e204 100644 --- a/src/com/cyanogenmod/setupwizard/util/SetupWizardUtils.java +++ b/src/com/cyanogenmod/setupwizard/util/SetupWizardUtils.java @@ -17,6 +17,7 @@ package com.cyanogenmod.setupwizard.util; import android.accounts.AccountManager; +import android.app.AppGlobals; import android.content.ComponentName; import android.content.Context; import android.content.pm.ComponentInfo; @@ -25,6 +26,8 @@ import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.wifi.WifiManager; +import android.os.IBinder; +import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; import android.telephony.ServiceState; @@ -32,6 +35,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; +import com.android.internal.os.IKillSwitchService; import com.cyanogenmod.setupwizard.SetupWizardApp; import com.google.android.gms.common.ConnectionResult; @@ -124,6 +128,36 @@ public class SetupWizardUtils { return true; } + 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 boolean hasKillSwitch() { + IBinder b = ServiceManager.getService(Context.KILLSWITCH_SERVICE); + IKillSwitchService service = IKillSwitchService.Stub.asInterface(b); + if (service != null) { + try { + return service.hasKillSwitch(); + } catch (Exception e) { + // silently fail + } + } + return false; + } + + public static boolean hasAuthorized() { + return ((SetupWizardApp) AppGlobals.getInitialApplication()).isAuthorized(); + } + public static boolean isRadioReady(Context context, ServiceState state) { final SetupWizardApp setupWizardApp = (SetupWizardApp)context.getApplicationContext(); if (setupWizardApp.isRadioReady()) {