diff --git a/src/com/android/settings/CredentialStorage.java b/src/com/android/settings/CredentialStorage.java index 03a5f4bbd0a..e5d40b7add0 100644 --- a/src/com/android/settings/CredentialStorage.java +++ b/src/com/android/settings/CredentialStorage.java @@ -47,8 +47,8 @@ import android.widget.Toast; import com.android.internal.widget.LockPatternUtils; import com.android.org.bouncycastle.asn1.ASN1InputStream; import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import com.android.settings.password.ChooseLockGeneric; import com.android.settings.password.ChooseLockSettingsHelper; +import com.android.settings.security.ConfigureKeyGuardDialog; import com.android.settings.vpn2.VpnUtils; import java.io.ByteArrayInputStream; @@ -74,14 +74,14 @@ import sun.security.x509.AlgorithmId; * KeyGuard: ON * Action: confirm key guard * Notes: user had key guard but no keystore and upgraded from pre-ICS - * OR user had key guard and pre-ICS keystore password which was then reset + * OR user had key guard and pre-ICS keystore password which was then reset * * KeyStore: LOCKED * KeyGuard: OFF/ON * Action: old unlock dialog * Notes: assume old password, need to use it to unlock. - * if unlock, ensure key guard before install. - * if reset, treat as UNINITALIZED/OFF + * if unlock, ensure key guard before install. + * if reset, treat as UNINITALIZED/OFF * * KeyStore: UNLOCKED * KeyGuard: OFF @@ -103,7 +103,7 @@ public final class CredentialStorage extends Activity { // This is the minimum acceptable password quality. If the current password quality is // lower than this, keystore should not be activated. - static final int MIN_PASSWORD_QUALITY = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; + public static final int MIN_PASSWORD_QUALITY = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; private static final int CONFIRM_KEY_GUARD_REQUEST = 1; private static final int CONFIRM_CLEAR_SYSTEM_CREDENTIAL_REQUEST = 2; @@ -171,7 +171,8 @@ public final class CredentialStorage extends Activity { } case UNLOCKED: { if (!checkKeyGuardQuality()) { - new ConfigureKeyGuardDialog(); + final ConfigureKeyGuardDialog dialog = new ConfigureKeyGuardDialog(); + dialog.show(getFragmentManager(), ConfigureKeyGuardDialog.TAG); return; } installIfAvailable(); @@ -190,7 +191,8 @@ public final class CredentialStorage extends Activity { private void ensureKeyGuard() { if (!checkKeyGuardQuality()) { // key guard not setup, doing so will initialize keystore - new ConfigureKeyGuardDialog(); + final ConfigureKeyGuardDialog dialog = new ConfigureKeyGuardDialog(); + dialog.show(getFragmentManager(), ConfigureKeyGuardDialog.TAG); // will return to onResume after Activity return; } @@ -308,8 +310,7 @@ public final class CredentialStorage extends Activity { * Prompt for reset confirmation, resetting on confirmation, finishing otherwise. */ private class ResetDialog - implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener - { + implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener { private boolean mResetConfirmed; private ResetDialog() { @@ -323,11 +324,13 @@ public final class CredentialStorage extends Activity { dialog.show(); } - @Override public void onClick(DialogInterface dialog, int button) { + @Override + public void onClick(DialogInterface dialog, int button) { mResetConfirmed = (button == DialogInterface.BUTTON_POSITIVE); } - @Override public void onDismiss(DialogInterface dialog) { + @Override + public void onDismiss(DialogInterface dialog) { if (mResetConfirmed) { mResetConfirmed = false; if (confirmKeyGuard(CONFIRM_CLEAR_SYSTEM_CREDENTIAL_REQUEST)) { @@ -344,7 +347,8 @@ public final class CredentialStorage extends Activity { */ private class ResetKeyStoreAndKeyChain extends AsyncTask { - @Override protected Boolean doInBackground(Void... unused) { + @Override + protected Boolean doInBackground(Void... unused) { // Clear all the users credentials could have been installed in for this user. new LockPatternUtils(CredentialStorage.this).resetKeyStore(UserHandle.myUserId()); @@ -364,14 +368,15 @@ public final class CredentialStorage extends Activity { } } - @Override protected void onPostExecute(Boolean success) { + @Override + protected void onPostExecute(Boolean success) { if (success) { Toast.makeText(CredentialStorage.this, - R.string.credentials_erased, Toast.LENGTH_SHORT).show(); + R.string.credentials_erased, Toast.LENGTH_SHORT).show(); clearLegacyVpnIfEstablished(); } else { Toast.makeText(CredentialStorage.this, - R.string.credentials_not_erased, Toast.LENGTH_SHORT).show(); + R.string.credentials_not_erased, Toast.LENGTH_SHORT).show(); } finish(); } @@ -385,42 +390,6 @@ public final class CredentialStorage extends Activity { } } - /** - * Prompt for key guard configuration confirmation. - */ - private class ConfigureKeyGuardDialog - implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener - { - private boolean mConfigureConfirmed; - - private ConfigureKeyGuardDialog() { - AlertDialog dialog = new AlertDialog.Builder(CredentialStorage.this) - .setTitle(android.R.string.dialog_alert_title) - .setMessage(R.string.credentials_configure_lock_screen_hint) - .setPositiveButton(android.R.string.ok, this) - .setNegativeButton(android.R.string.cancel, this) - .create(); - dialog.setOnDismissListener(this); - dialog.show(); - } - - @Override public void onClick(DialogInterface dialog, int button) { - mConfigureConfirmed = (button == DialogInterface.BUTTON_POSITIVE); - } - - @Override public void onDismiss(DialogInterface dialog) { - if (mConfigureConfirmed) { - mConfigureConfirmed = false; - Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD); - intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, - MIN_PASSWORD_QUALITY); - startActivity(intent); - return; - } - finish(); - } - } - /** * Check that the caller is either certinstaller or Settings running in a profile of this user. */ @@ -506,8 +475,7 @@ public final class CredentialStorage extends Activity { * On unsuccessful unlock, retry by calling handleUnlockOrInstall. */ private class UnlockDialog implements TextWatcher, - DialogInterface.OnClickListener, DialogInterface.OnDismissListener - { + DialogInterface.OnClickListener, DialogInterface.OnDismissListener { private boolean mUnlockConfirmed; private final Button mButton; @@ -546,21 +514,26 @@ public final class CredentialStorage extends Activity { mButton.setEnabled(false); } - @Override public void afterTextChanged(Editable editable) { + @Override + public void afterTextChanged(Editable editable) { mButton.setEnabled(mOldPassword == null || mOldPassword.getText().length() > 0); } - @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { } - @Override public void onTextChanged(CharSequence s,int start, int before, int count) { + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { } - @Override public void onClick(DialogInterface dialog, int button) { + @Override + public void onClick(DialogInterface dialog, int button) { mUnlockConfirmed = (button == DialogInterface.BUTTON_POSITIVE); } - @Override public void onDismiss(DialogInterface dialog) { + @Override + public void onDismiss(DialogInterface dialog) { if (mUnlockConfirmed) { mUnlockConfirmed = false; mError.setVisibility(View.VISIBLE); @@ -569,16 +542,16 @@ public final class CredentialStorage extends Activity { if (error == KeyStore.NO_ERROR) { mRetriesRemaining = -1; Toast.makeText(CredentialStorage.this, - R.string.credentials_enabled, - Toast.LENGTH_SHORT).show(); + R.string.credentials_enabled, + Toast.LENGTH_SHORT).show(); // aha, now we are unlocked, switch to key guard. // we'll end up back in onResume to install ensureKeyGuard(); } else if (error == KeyStore.UNINITIALIZED) { mRetriesRemaining = -1; Toast.makeText(CredentialStorage.this, - R.string.credentials_erased, - Toast.LENGTH_SHORT).show(); + R.string.credentials_erased, + Toast.LENGTH_SHORT).show(); // we are reset, we can now set new password with key guard handleUnlockOrInstall(); } else if (error >= KeyStore.WRONG_PASSWORD) { diff --git a/src/com/android/settings/security/ConfigureKeyGuardDialog.java b/src/com/android/settings/security/ConfigureKeyGuardDialog.java new file mode 100644 index 00000000000..3c893407698 --- /dev/null +++ b/src/com/android/settings/security/ConfigureKeyGuardDialog.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed 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 com.android.settings.security; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.admin.DevicePolicyManager; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.VisibleForTesting; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.CredentialStorage; +import com.android.settings.R; +import com.android.settings.core.instrumentation.InstrumentedDialogFragment; +import com.android.settings.password.ChooseLockGeneric; + +/** + * Prompt for key guard configuration confirmation. + */ +public class ConfigureKeyGuardDialog extends InstrumentedDialogFragment + implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener { + + public static final String TAG = "ConfigureKeyGuardDialog"; + + private boolean mConfigureConfirmed; + + @Override + public int getMetricsCategory() { + return MetricsProto.MetricsEvent.CONFIGURE_KEYGUARD_DIALOG; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + return new AlertDialog.Builder(getActivity()) + .setTitle(android.R.string.dialog_alert_title) + .setMessage(R.string.credentials_configure_lock_screen_hint) + .setPositiveButton(android.R.string.ok, this) + .setNegativeButton(android.R.string.cancel, this) + .create(); + } + + @Override + public void onClick(DialogInterface dialog, int button) { + mConfigureConfirmed = (button == DialogInterface.BUTTON_POSITIVE); + } + + @Override + public void onDismiss(DialogInterface dialog) { + if (mConfigureConfirmed) { + mConfigureConfirmed = false; + startPasswordSetup(); + return; + } else { + final Activity activity = getActivity(); + if (activity != null) { + activity.finish(); + } + } + } + + @VisibleForTesting + void startPasswordSetup() { + Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD); + intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, + CredentialStorage.MIN_PASSWORD_QUALITY); + startActivity(intent); + } +} diff --git a/tests/robotests/src/com/android/settings/security/ConfigureKeyGuardDialogTest.java b/tests/robotests/src/com/android/settings/security/ConfigureKeyGuardDialogTest.java new file mode 100644 index 00000000000..8a80fe58033 --- /dev/null +++ b/tests/robotests/src/com/android/settings/security/ConfigureKeyGuardDialogTest.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed 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 com.android.settings.security; + + +import android.content.DialogInterface; + +import com.android.settings.SettingsRobolectricTestRunner; +import com.android.settings.TestConfig; +import com.android.settings.testutils.shadow.ShadowEventLogWriter; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.Robolectric; +import org.robolectric.annotation.Config; +import org.robolectric.util.FragmentController; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class ConfigureKeyGuardDialogTest { + + @Test + @Config(shadows = ShadowEventLogWriter.class) + public void displayDialog_clickPositiveButton_launchSetNewPassword() { + final FragmentController fragmentController = + Robolectric.buildFragment(ConfigureKeyGuardDialog.class); + final ConfigureKeyGuardDialog fragment = spy(fragmentController.get()); + doNothing().when(fragment).startPasswordSetup(); + fragmentController.attach().create().start().resume(); + fragment.onClick(null /* dialog */, DialogInterface.BUTTON_POSITIVE); + fragment.onDismiss(null /* dialog */); + + verify(fragment).startPasswordSetup(); + } +}