Don't show multiple wipe warning dialogs
Stacking them on top of each other like that does not count as defence
in depth and we should not do it.
Bug: 32934848
Test: make RunSettingsRoboTests # added one specifically for this
Change-Id: I9490652c05a630e7c3f9164a9144fadfc0f41ea1
diff --git a/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java b/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java
index cabc805..a5f9830 100644
--- a/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java
+++ b/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java
@@ -14,18 +14,21 @@
* limitations under the License
*/
+// TODO (b/35202196): move this class out of the root of the package.
package com.android.settings;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
import android.app.IActivityManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentSender;
import android.graphics.Point;
@@ -289,12 +292,13 @@
// Last try
final String title = getActivity().getString(
R.string.lock_profile_wipe_warning_title);
- final String message = getActivity().getString(getLastTryErrorMessage());
- showDialog(title, message, android.R.string.ok, false /* dismiss */);
+ LastTryDialog.show(getFragmentManager(), title, getLastTryErrorMessage(),
+ android.R.string.ok, false /* dismiss */);
} else if (remainingAttempts <= 0) {
// Profile is wiped
- final String message = getActivity().getString(R.string.lock_profile_wipe_content);
- showDialog(null, message, R.string.lock_profile_wipe_dismiss, true /* dismiss */);
+ LastTryDialog.show(getFragmentManager(), null /* title */,
+ R.string.lock_profile_wipe_content, R.string.lock_profile_wipe_dismiss,
+ true /* dismiss */);
}
if (mErrorTextView != null) {
final String message = getActivity().getString(R.string.lock_profile_wipe_attempts,
@@ -328,19 +332,55 @@
showError(getText(msg), timeout);
}
- private void showDialog(String title, String message, int buttonString, final boolean dismiss) {
- final AlertDialog dialog = new AlertDialog.Builder(getActivity())
- .setTitle(title)
- .setMessage(message)
- .setPositiveButton(buttonString, new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (dismiss) {
- getActivity().finish();
- }
- }
- })
- .create();
- dialog.show();
+ public static class LastTryDialog extends DialogFragment {
+ private static final String TAG = LastTryDialog.class.getSimpleName();
+
+ private static final String ARG_TITLE = "title";
+ private static final String ARG_MESSAGE = "message";
+ private static final String ARG_BUTTON = "button";
+ private static final String ARG_DISMISS = "dismiss";
+
+ static boolean show(FragmentManager from, String title, int message, int button,
+ boolean dismiss) {
+ LastTryDialog existent = (LastTryDialog) from.findFragmentByTag(TAG);
+ if (existent != null && !existent.isRemoving()) {
+ return false;
+ }
+ Bundle args = new Bundle();
+ args.putString(ARG_TITLE, title);
+ args.putInt(ARG_MESSAGE, message);
+ args.putInt(ARG_BUTTON, button);
+ args.putBoolean(ARG_DISMISS, dismiss);
+
+ DialogFragment dialog = new LastTryDialog();
+ dialog.setArguments(args);
+ dialog.show(from, TAG);
+ return true;
+ }
+
+ static void hide(FragmentManager from) {
+ LastTryDialog dialog = (LastTryDialog) from.findFragmentByTag(TAG);
+ if (dialog != null) {
+ dialog.dismissAllowingStateLoss();
+ from.executePendingTransactions();
+ }
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getArguments().getString(ARG_TITLE))
+ .setMessage(getArguments().getInt(ARG_MESSAGE))
+ .setPositiveButton(getArguments().getInt(ARG_BUTTON), null)
+ .create();
+ }
+
+ @Override
+ public void onDismiss(final DialogInterface dialog) {
+ super.onDismiss(dialog);
+ if (getActivity() != null && getArguments().getBoolean(ARG_DISMISS)) {
+ getActivity().finish();
+ }
+ }
}
}
diff --git a/tests/robotests/src/com/android/settings/ConfirmCredentialTest.java b/tests/robotests/src/com/android/settings/ConfirmCredentialTest.java
new file mode 100644
index 0000000..f771a1f
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/ConfirmCredentialTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+import static com.android.settings.ConfirmDeviceCredentialBaseFragment.LastTryDialog;
+import static com.google.common.truth.Truth.assertThat;
+
+import android.R;
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+
+import com.android.settings.testutils.shadow.SettingsShadowResources;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(
+ manifest = TestConfig.MANIFEST_PATH,
+ sdk = TestConfig.SDK_VERSION,
+ shadows = {
+ SettingsShadowResources.class,
+ SettingsShadowResources.SettingsShadowTheme.class,
+ })
+public class ConfirmCredentialTest {
+ @Test
+ public void testLastTryDialogShownExactlyOnce() {
+ FragmentManager fm = Robolectric.buildActivity(Activity.class).get().getFragmentManager();
+
+ // Launch only one instance at a time.
+ assertThat(LastTryDialog.show(fm, "title", R.string.yes, R.string.ok, false)).isTrue();
+ assertThat(LastTryDialog.show(fm, "title", R.string.yes, R.string.ok, false)).isFalse();
+
+ // After cancelling, the dialog should be re-shown when asked for.
+ LastTryDialog.hide(fm);
+ assertThat(LastTryDialog.show(fm, "title", R.string.yes, R.string.ok, false)).isTrue();
+ }
+}