Don't lose dialogs during configuration change
Bug: 62442606 Test: Rotate device when a dialog is showing Change-Id: I616d6030e2c43937e4b59dd7f6d78dd7124228dc
This commit is contained in:
@@ -96,6 +96,7 @@ import com.android.settings.widget.SwitchBar;
|
|||||||
import com.android.settingslib.RestrictedLockUtils;
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||||
import com.android.settingslib.RestrictedSwitchPreference;
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
|
import com.android.settingslib.core.ConfirmationDialogController;
|
||||||
import com.android.settingslib.development.AbstractEnableAdbPreferenceController;
|
import com.android.settingslib.development.AbstractEnableAdbPreferenceController;
|
||||||
import com.android.settingslib.development.DevelopmentSettingsEnabler;
|
import com.android.settingslib.development.DevelopmentSettingsEnabler;
|
||||||
import com.android.settingslib.development.SystemPropPoker;
|
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 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 IWindowManager mWindowManager;
|
||||||
private IBackupManager mBackupManager;
|
private IBackupManager mBackupManager;
|
||||||
private IWebViewUpdateService mWebViewUpdateService;
|
private IWebViewUpdateService mWebViewUpdateService;
|
||||||
@@ -342,6 +347,11 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
|
|||||||
public void onCreate(Bundle icicle) {
|
public void onCreate(Bundle icicle) {
|
||||||
super.onCreate(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"));
|
mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
|
||||||
mBackupManager = IBackupManager.Stub.asInterface(
|
mBackupManager = IBackupManager.Stub.asInterface(
|
||||||
ServiceManager.getService(Context.BACKUP_SERVICE));
|
ServiceManager.getService(Context.BACKUP_SERVICE));
|
||||||
@@ -654,6 +664,11 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
|
|||||||
mColorModePreference.startListening();
|
mColorModePreference.startListening();
|
||||||
mColorModePreference.updateCurrentAndSupported();
|
mColorModePreference.updateCurrentAndSupported();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mPendingDialogKey != null) {
|
||||||
|
recreateDialogForKey(mPendingDialogKey);
|
||||||
|
mPendingDialogKey = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -664,6 +679,12 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
outState.putString(STATE_SHOWING_DIALOG_KEY, getKeyForShowingDialog());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
@@ -2334,8 +2355,44 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
|
|||||||
return false;
|
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() {
|
private void dismissDialogs() {
|
||||||
mEnableAdbController.dismissDialogs();
|
mEnableAdbController.dismissConfirmationDialog();
|
||||||
if (mAdbKeysDialog != null) {
|
if (mAdbKeysDialog != null) {
|
||||||
mAdbKeysDialog.dismiss();
|
mAdbKeysDialog.dismiss();
|
||||||
mAdbKeysDialog = null;
|
mAdbKeysDialog = null;
|
||||||
@@ -2344,7 +2401,7 @@ public class DevelopmentSettings extends RestrictedSettingsFragment
|
|||||||
mEnableDialog.dismiss();
|
mEnableDialog.dismiss();
|
||||||
mEnableDialog = null;
|
mEnableDialog = null;
|
||||||
}
|
}
|
||||||
mLogpersistController.dismissDialogs();
|
mLogpersistController.dismissConfirmationDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
@@ -19,8 +19,9 @@ package com.android.settings.development;
|
|||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.provider.Settings;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v14.preference.SwitchPreference;
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.support.v7.preference.TwoStatePreference;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.core.PreferenceControllerMixin;
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
@@ -37,33 +38,43 @@ public class EnableAdbPreferenceController extends AbstractEnableAdbPreferenceCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showConfirmationDialog(SwitchPreference preference) {
|
public void showConfirmationDialog(@Nullable Preference preference) {
|
||||||
|
if (preference == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final TwoStatePreference twoStatePreference = (TwoStatePreference) preference;
|
||||||
mDialogClicked = false;
|
mDialogClicked = false;
|
||||||
dismissDialogs();
|
dismissConfirmationDialog();
|
||||||
mAdbDialog = new AlertDialog.Builder(mContext).setMessage(
|
mAdbDialog = new AlertDialog.Builder(mContext).setMessage(
|
||||||
mContext.getString(R.string.adb_warning_message))
|
mContext.getString(R.string.adb_warning_message))
|
||||||
.setTitle(R.string.adb_warning_title)
|
.setTitle(R.string.adb_warning_title)
|
||||||
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
|
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
|
||||||
mDialogClicked = true;
|
mDialogClicked = true;
|
||||||
writeAdbSetting(true);
|
writeAdbSetting(true);
|
||||||
|
twoStatePreference.setChecked(true);
|
||||||
})
|
})
|
||||||
.setNegativeButton(android.R.string.no, (dialog, which) -> {
|
.setNegativeButton(android.R.string.no,
|
||||||
preference.setChecked(false);
|
(dialog, which) -> twoStatePreference.setChecked(false))
|
||||||
})
|
|
||||||
.show();
|
.show();
|
||||||
mAdbDialog.setOnDismissListener(dialog -> {
|
mAdbDialog.setOnDismissListener(dialog -> {
|
||||||
// Assuming that onClick gets called first
|
// Assuming that onClick gets called first
|
||||||
if (!mDialogClicked) {
|
if (!mDialogClicked) {
|
||||||
preference.setChecked(false);
|
twoStatePreference.setChecked(false);
|
||||||
}
|
}
|
||||||
mAdbDialog = null;
|
mAdbDialog = null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dismissDialogs() {
|
@Override
|
||||||
|
public void dismissConfirmationDialog() {
|
||||||
if (mAdbDialog != null) {
|
if (mAdbDialog != null) {
|
||||||
mAdbDialog.dismiss();
|
mAdbDialog.dismiss();
|
||||||
mAdbDialog = null;
|
mAdbDialog = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isConfirmationDialogShowing() {
|
||||||
|
return mAdbDialog != null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,8 +19,10 @@ package com.android.settings.development;
|
|||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
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.settings.core.PreferenceControllerMixin;
|
||||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||||
import com.android.settingslib.development.AbstractLogpersistPreferenceController;
|
import com.android.settingslib.development.AbstractLogpersistPreferenceController;
|
||||||
@@ -35,23 +37,30 @@ public class LogpersistPreferenceController extends AbstractLogpersistPreference
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showConfirmationDialog(ListPreference preference) {
|
public void showConfirmationDialog(@Nullable Preference preference) {
|
||||||
if (mLogpersistClearDialog != null) dismissDialogs();
|
if (preference == null) {
|
||||||
mLogpersistClearDialog = new AlertDialog.Builder(mContext).setMessage(
|
return;
|
||||||
mContext.getString(
|
}
|
||||||
com.android.settingslib.R.string.dev_logpersist_clear_warning_message))
|
if (mLogpersistClearDialog != null) dismissConfirmationDialog();
|
||||||
.setTitle(com.android.settingslib.R.string.dev_logpersist_clear_warning_title)
|
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))
|
.setPositiveButton(android.R.string.yes, (dialog, which) -> setLogpersistOff(true))
|
||||||
.setNegativeButton(android.R.string.no, (dialog, which) -> updateLogpersistValues())
|
.setNegativeButton(android.R.string.no, (dialog, which) -> updateLogpersistValues())
|
||||||
.show();
|
.show();
|
||||||
mLogpersistClearDialog.setOnDismissListener(dialog -> mLogpersistClearDialog = null);
|
mLogpersistClearDialog.setOnDismissListener(dialog -> mLogpersistClearDialog = null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dismissDialogs() {
|
@Override
|
||||||
|
public void dismissConfirmationDialog() {
|
||||||
if (mLogpersistClearDialog != null) {
|
if (mLogpersistClearDialog != null) {
|
||||||
mLogpersistClearDialog.dismiss();
|
mLogpersistClearDialog.dismiss();
|
||||||
mLogpersistClearDialog = null;
|
mLogpersistClearDialog = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isConfirmationDialogShowing() {
|
||||||
|
return mLogpersistClearDialog != 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();
|
||||||
|
}
|
||||||
|
}
|
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user