OSDN Git Service

Don't lose dialogs during configuration change
authorTony Mantler <nicoya@google.com>
Wed, 9 Aug 2017 21:16:48 +0000 (14:16 -0700)
committerTony Mantler <nicoya@google.com>
Thu, 10 Aug 2017 21:21:04 +0000 (14:21 -0700)
Bug: 62442606
Test: Rotate device when a dialog is showing
Change-Id: I616d6030e2c43937e4b59dd7f6d78dd7124228dc

src/com/android/settings/development/DevelopmentSettings.java
src/com/android/settings/development/EnableAdbPreferenceController.java
src/com/android/settings/development/LogpersistPreferenceController.java
tests/robotests/src/com/android/settings/development/EnableAdbPreferenceControllerTest.java [new file with mode: 0644]
tests/robotests/src/com/android/settings/development/LogpersistPreferenceControllerTest.java [new file with mode: 0644]

index 1a3c3ad..0af3dd4 100644 (file)
@@ -96,6 +96,7 @@ import com.android.settings.widget.SwitchBar;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 import com.android.settingslib.RestrictedSwitchPreference;
+import com.android.settingslib.core.ConfirmationDialogController;
 import com.android.settingslib.development.AbstractEnableAdbPreferenceController;
 import com.android.settingslib.development.DevelopmentSettingsEnabler;
 import com.android.settingslib.development.SystemPropPoker;
@@ -211,6 +212,10 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
 
     private static final int[] MOCK_LOCATION_APP_OPS = new int[]{AppOpsManager.OP_MOCK_LOCATION};
 
+    private static final String STATE_SHOWING_DIALOG_KEY = "showing_dialog_key";
+
+    private String mPendingDialogKey;
+
     private IWindowManager mWindowManager;
     private IBackupManager mBackupManager;
     private IWebViewUpdateService mWebViewUpdateService;
@@ -342,6 +347,11 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
+        if (icicle != null) {
+            // Don't show this in onCreate since we might be on the back stack
+            mPendingDialogKey = icicle.getString(STATE_SHOWING_DIALOG_KEY);
+        }
+
         mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
         mBackupManager = IBackupManager.Stub.asInterface(
                 ServiceManager.getService(Context.BACKUP_SERVICE));
@@ -654,6 +664,11 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
             mColorModePreference.startListening();
             mColorModePreference.updateCurrentAndSupported();
         }
+
+        if (mPendingDialogKey != null) {
+            recreateDialogForKey(mPendingDialogKey);
+            mPendingDialogKey = null;
+        }
     }
 
     @Override
@@ -665,6 +680,12 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
     }
 
     @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putString(STATE_SHOWING_DIALOG_KEY, getKeyForShowingDialog());
+    }
+
+    @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
         IntentFilter filter = new IntentFilter();
@@ -2334,8 +2355,44 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
         return false;
     }
 
+    /**
+     * Iterates through preference controllers that show confirmation dialogs and returns the
+     * preference key for the first currently showing dialog. Ideally there should only ever be one.
+     * @return Preference key, or null if no dialog is showing
+     */
+    private String getKeyForShowingDialog() {
+        // TODO: iterate through a fragment-wide list of PreferenceControllers and just pick out the
+        // ConfirmationDialogController objects
+        final List<ConfirmationDialogController> dialogControllers = new ArrayList<>(2);
+        dialogControllers.add(mEnableAdbController);
+        dialogControllers.add(mLogpersistController);
+        for (ConfirmationDialogController dialogController : dialogControllers) {
+            if (dialogController.isConfirmationDialogShowing()) {
+                return dialogController.getPreferenceKey();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Re-show the dialog we lost previously
+     * @param preferenceKey Key for the preference the dialog is for
+     */
+    private void recreateDialogForKey(String preferenceKey) {
+        // TODO: iterate through a fragment-wide list of PreferenceControllers and just pick out the
+        // ConfirmationDialogController objects
+        final List<ConfirmationDialogController> dialogControllers = new ArrayList<>(2);
+        dialogControllers.add(mEnableAdbController);
+        dialogControllers.add(mLogpersistController);
+        for (ConfirmationDialogController dialogController : dialogControllers) {
+            if (TextUtils.equals(preferenceKey, dialogController.getPreferenceKey())) {
+                dialogController.showConfirmationDialog(findPreference(preferenceKey));
+            }
+        }
+    }
+
     private void dismissDialogs() {
-        mEnableAdbController.dismissDialogs();
+        mEnableAdbController.dismissConfirmationDialog();
         if (mAdbKeysDialog != null) {
             mAdbKeysDialog.dismiss();
             mAdbKeysDialog = null;
@@ -2344,7 +2401,7 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
             mEnableDialog.dismiss();
             mEnableDialog = null;
         }
-        mLogpersistController.dismissDialogs();
+        mLogpersistController.dismissConfirmationDialog();
     }
 
     public void onClick(DialogInterface dialog, int which) {
index a159f0a..bd6267b 100644 (file)
@@ -19,8 +19,9 @@ package com.android.settings.development;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.Context;
-import android.provider.Settings;
-import android.support.v14.preference.SwitchPreference;
+import android.support.annotation.Nullable;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.TwoStatePreference;
 
 import com.android.settings.R;
 import com.android.settings.core.PreferenceControllerMixin;
@@ -37,33 +38,43 @@ public class EnableAdbPreferenceController extends AbstractEnableAdbPreferenceCo
     }
 
     @Override
-    public void showConfirmationDialog(SwitchPreference preference) {
+    public void showConfirmationDialog(@Nullable Preference preference) {
+        if (preference == null) {
+            return;
+        }
+        final TwoStatePreference twoStatePreference = (TwoStatePreference) preference;
         mDialogClicked = false;
-        dismissDialogs();
+        dismissConfirmationDialog();
         mAdbDialog = new AlertDialog.Builder(mContext).setMessage(
                 mContext.getString(R.string.adb_warning_message))
                 .setTitle(R.string.adb_warning_title)
                 .setPositiveButton(android.R.string.yes, (dialog, which) -> {
                     mDialogClicked = true;
                     writeAdbSetting(true);
+                    twoStatePreference.setChecked(true);
                 })
-                .setNegativeButton(android.R.string.no, (dialog, which) -> {
-                    preference.setChecked(false);
-                })
+                .setNegativeButton(android.R.string.no,
+                        (dialog, which) -> twoStatePreference.setChecked(false))
                 .show();
         mAdbDialog.setOnDismissListener(dialog -> {
             // Assuming that onClick gets called first
             if (!mDialogClicked) {
-                preference.setChecked(false);
+                twoStatePreference.setChecked(false);
             }
             mAdbDialog = null;
         });
     }
 
-    public void dismissDialogs() {
+    @Override
+    public void dismissConfirmationDialog() {
         if (mAdbDialog != null) {
             mAdbDialog.dismiss();
             mAdbDialog = null;
         }
     }
+
+    @Override
+    public boolean isConfirmationDialogShowing() {
+        return mAdbDialog != null;
+    }
 }
index 5baac3d..a1ca186 100644 (file)
@@ -19,8 +19,10 @@ package com.android.settings.development;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.Context;
-import android.support.v7.preference.ListPreference;
+import android.support.annotation.Nullable;
+import android.support.v7.preference.Preference;
 
+import com.android.settings.R;
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.development.AbstractLogpersistPreferenceController;
@@ -35,23 +37,30 @@ public class LogpersistPreferenceController extends AbstractLogpersistPreference
     }
 
     @Override
-    public void showConfirmationDialog(ListPreference preference) {
-        if (mLogpersistClearDialog != null) dismissDialogs();
-        mLogpersistClearDialog = new AlertDialog.Builder(mContext).setMessage(
-                mContext.getString(
-                        com.android.settingslib.R.string.dev_logpersist_clear_warning_message))
-                .setTitle(com.android.settingslib.R.string.dev_logpersist_clear_warning_title)
+    public void showConfirmationDialog(@Nullable Preference preference) {
+        if (preference == null) {
+            return;
+        }
+        if (mLogpersistClearDialog != null) dismissConfirmationDialog();
+        mLogpersistClearDialog = new AlertDialog.Builder(mContext)
+                .setMessage(R.string.dev_logpersist_clear_warning_message)
+                .setTitle(R.string.dev_logpersist_clear_warning_title)
                 .setPositiveButton(android.R.string.yes, (dialog, which) -> setLogpersistOff(true))
                 .setNegativeButton(android.R.string.no, (dialog, which) -> updateLogpersistValues())
                 .show();
         mLogpersistClearDialog.setOnDismissListener(dialog -> mLogpersistClearDialog = null);
-
     }
 
-    public void dismissDialogs() {
+    @Override
+    public void dismissConfirmationDialog() {
         if (mLogpersistClearDialog != null) {
             mLogpersistClearDialog.dismiss();
             mLogpersistClearDialog = null;
         }
     }
+
+    @Override
+    public boolean isConfirmationDialogShowing() {
+        return mLogpersistClearDialog != null;
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/development/EnableAdbPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/EnableAdbPreferenceControllerTest.java
new file mode 100644 (file)
index 0000000..6dcfbf2
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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.development;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.support.v14.preference.SwitchPreference;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class EnableAdbPreferenceControllerTest {
+
+    @Mock
+    private SwitchPreference mSwitchPreference;
+
+    private EnableAdbPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mController
+                = new EnableAdbPreferenceController(RuntimeEnvironment.application);
+    }
+
+    @Test
+    public void testIsConfirmationDialogShowing() {
+        assertThat(mController.isConfirmationDialogShowing()).isFalse();
+        mController.showConfirmationDialog(mSwitchPreference);
+        assertThat(mController.isConfirmationDialogShowing()).isTrue();
+        mController.dismissConfirmationDialog();
+        assertThat(mController.isConfirmationDialogShowing()).isFalse();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/LogpersistPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/LogpersistPreferenceControllerTest.java
new file mode 100644 (file)
index 0000000..450f29d
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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.development;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.support.v7.preference.ListPreference;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class LogpersistPreferenceControllerTest {
+
+    private Lifecycle mLifecycle = new Lifecycle();
+
+    @Mock
+    private ListPreference mListPreference;
+
+    private LogpersistPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mController
+                = new LogpersistPreferenceController(RuntimeEnvironment.application, mLifecycle);
+    }
+
+    @Test
+    public void testIsConfirmationDialogShowing() {
+        assertThat(mController.isConfirmationDialogShowing()).isFalse();
+        mController.showConfirmationDialog(mListPreference);
+        assertThat(mController.isConfirmationDialogShowing()).isTrue();
+        mController.dismissConfirmationDialog();
+        assertThat(mController.isConfirmationDialogShowing()).isFalse();
+    }
+}