OSDN Git Service

Add switch bar to enable/disable dev settings in new page.
authorFan Zhang <zhfan@google.com>
Fri, 8 Sep 2017 22:29:54 +0000 (15:29 -0700)
committerFan Zhang <zhfan@google.com>
Tue, 12 Sep 2017 17:25:43 +0000 (10:25 -0700)
Bug: 65522852
Test: make RunSettingsRoboTests -j40 ROBOTEST_FILTER=Development
Change-Id: I0958950dc6aaee24d8d5e0be58d7564d108bc72e

src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
src/com/android/settings/development/DevelopmentSwitchBarController.java
src/com/android/settings/development/EnableDevelopmentSettingWarningDialog.java [new file with mode: 0644]
tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
tests/robotests/src/com/android/settings/development/DevelopmentSwitchBarControllerTest.java

index 30be654..919dc3a 100644 (file)
 package com.android.settings.development;
 
 import android.content.Context;
+import android.os.Bundle;
 import android.os.UserManager;
 import android.provider.SearchIndexableResource;
 import android.util.Log;
+import android.widget.Switch;
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.Utils;
 import com.android.settings.dashboard.RestrictedDashboardFragment;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Indexable;
@@ -33,22 +37,68 @@ import com.android.settingslib.development.DevelopmentSettingsEnabler;
 import java.util.Arrays;
 import java.util.List;
 
-public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFragment {
+public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFragment
+        implements SwitchBar.OnSwitchChangeListener {
 
     private static final String TAG = "DevSettingsDashboard";
 
+    private boolean mIsAvailable = true;
     private SwitchBar mSwitchBar;
+    private DevelopmentSwitchBarController mSwitchBarController;
 
     public DevelopmentSettingsDashboardFragment() {
         super(UserManager.DISALLOW_DEBUGGING_FEATURES);
     }
 
     @Override
+    public void onActivityCreated(Bundle icicle) {
+        super.onActivityCreated(icicle);
+        // Apply page-level restrictions
+        setIfOnlyAvailableForAdmins(true);
+        if (isUiRestricted() || !Utils.isDeviceProvisioned(getActivity())) {
+            // Block access to developer options if the user is not the owner, if user policy
+            // restricts it, or if the device has not been provisioned
+            mIsAvailable = false;
+            // Show error message
+            if (!isUiRestrictedByOnlyAdmin()) {
+                getEmptyTextView().setText(R.string.development_settings_not_available);
+            }
+            getPreferenceScreen().removeAll();
+            return;
+        }
+        // Set up master switch
+        mSwitchBar = ((SettingsActivity) getActivity()).getSwitchBar();
+        mSwitchBarController = new DevelopmentSwitchBarController(
+                this /* DevelopmentSettings */, mSwitchBar, mIsAvailable, getLifecycle());
+        mSwitchBar.show();
+    }
+
+    @Override
     public int getMetricsCategory() {
         return MetricsProto.MetricsEvent.DEVELOPMENT;
     }
 
     @Override
+    public void onSwitchChanged(Switch switchView, boolean isChecked) {
+        if (switchView != mSwitchBar.getSwitch()) {
+            return;
+        }
+        final boolean developmentEnabledState =
+                DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(getContext());
+        if (isChecked != developmentEnabledState) {
+            if (isChecked) {
+                EnableDevelopmentSettingWarningDialog.show(this /* host */);
+            } else {
+                // TODO: Reset dangerous options (move logic from DevelopmentSettings).
+                // resetDangerousOptions();
+                DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(getContext(), false);
+                // TODO: Refresh all prefs' enabled state (move logic from DevelopmentSettings).
+                // setPrefsEnabledState(false);
+            }
+        }
+    }
+
+    @Override
     protected String getLogTag() {
         return TAG;
     }
@@ -69,6 +119,16 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
         return buildPreferenceControllers(context);
     }
 
+    void onEnableDevelopmentOptionsConfirmed() {
+        DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(getContext(), true);
+        // TODO: Refresh all prefs' enabled state (move logic from DevelopmentSettings).
+    }
+
+    void onEnableDevelopmentOptionsRejected() {
+        // Reset the toggle
+        mSwitchBar.setChecked(false);
+    }
+
     private static List<AbstractPreferenceController> buildPreferenceControllers(Context context) {
         return null;
     }
index 168f7c0..ae875b3 100644 (file)
@@ -22,18 +22,39 @@ import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.OnStart;
 import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settingslib.development.DevelopmentSettingsEnabler;
 
 public class DevelopmentSwitchBarController implements LifecycleObserver, OnStart, OnStop {
 
     private final SwitchBar mSwitchBar;
     private final boolean mIsAvailable;
     private final DevelopmentSettings mSettings;
+    private final DevelopmentSettingsDashboardFragment mNewSettings;
 
+    /**
+     * @deprecated in favor of the other constructor.
+     */
+    @Deprecated
     public DevelopmentSwitchBarController(DevelopmentSettings settings, SwitchBar switchBar,
             boolean isAvailable, Lifecycle lifecycle) {
         mSwitchBar = switchBar;
         mIsAvailable = isAvailable && !Utils.isMonkeyRunning();
         mSettings = settings;
+        mNewSettings = null;
+
+        if (mIsAvailable) {
+            lifecycle.addObserver(this);
+        } else {
+            mSwitchBar.setEnabled(false);
+        }
+    }
+
+    public DevelopmentSwitchBarController(DevelopmentSettingsDashboardFragment settings,
+            SwitchBar switchBar, boolean isAvailable, Lifecycle lifecycle) {
+        mSwitchBar = switchBar;
+        mIsAvailable = isAvailable && !Utils.isMonkeyRunning();
+        mSettings = null;
+        mNewSettings = settings;
 
         if (mIsAvailable) {
             lifecycle.addObserver(this);
@@ -44,11 +65,24 @@ public class DevelopmentSwitchBarController implements LifecycleObserver, OnStar
 
     @Override
     public void onStart() {
-        mSwitchBar.addOnSwitchChangeListener(mSettings);
+        if (mSettings != null) {
+            mSwitchBar.addOnSwitchChangeListener(mSettings);
+        }
+        if (mNewSettings != null) {
+            final boolean developmentEnabledState = DevelopmentSettingsEnabler
+                    .isDevelopmentSettingsEnabled(mNewSettings.getContext());
+            mSwitchBar.setChecked(developmentEnabledState);
+            mSwitchBar.addOnSwitchChangeListener(mNewSettings);
+        }
     }
 
     @Override
     public void onStop() {
-        mSwitchBar.removeOnSwitchChangeListener(mSettings);
+        if (mSettings != null) {
+            mSwitchBar.removeOnSwitchChangeListener(mSettings);
+        }
+        if (mNewSettings != null) {
+            mSwitchBar.removeOnSwitchChangeListener(mNewSettings);
+        }
     }
 }
diff --git a/src/com/android/settings/development/EnableDevelopmentSettingWarningDialog.java b/src/com/android/settings/development/EnableDevelopmentSettingWarningDialog.java
new file mode 100644 (file)
index 0000000..3c3d645
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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 android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.FragmentManager;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+public class EnableDevelopmentSettingWarningDialog extends InstrumentedDialogFragment
+        implements DialogInterface.OnClickListener {
+
+    public static final String TAG = "EnableDevSettingDlg";
+
+    public static void show(
+            DevelopmentSettingsDashboardFragment host) {
+        final EnableDevelopmentSettingWarningDialog dialog =
+                new EnableDevelopmentSettingWarningDialog();
+        dialog.setTargetFragment(host, 0 /* requestCode */);
+        final FragmentManager manager = host.getActivity().getFragmentManager();
+        if (manager.findFragmentByTag(TAG) == null) {
+            dialog.show(manager, TAG);
+        }
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsProto.MetricsEvent.DIALOG_ENABLE_DEVELOPMENT_OPTIONS;
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        return new AlertDialog.Builder(getActivity())
+                .setMessage(R.string.dev_settings_warning_message)
+                .setTitle(R.string.dev_settings_warning_title)
+                .setPositiveButton(android.R.string.yes, this)
+                .setNegativeButton(android.R.string.no, this)
+                .create();
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        final DevelopmentSettingsDashboardFragment host =
+                (DevelopmentSettingsDashboardFragment) getTargetFragment();
+        if (which == DialogInterface.BUTTON_POSITIVE) {
+            host.onEnableDevelopmentOptionsConfirmed();
+        } else {
+            host.onEnableDevelopmentOptionsRejected();
+        }
+    }
+}
index 04ff721..a001aaf 100644 (file)
 package com.android.settings.development;
 
 import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.provider.SearchIndexableResource;
+import android.provider.Settings;
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
 import com.android.settings.TestConfig;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.testutils.shadow.SettingsShadowResources;
+import com.android.settings.widget.SwitchBar;
+import com.android.settings.widget.ToggleSwitch;
 import com.android.settingslib.development.DevelopmentSettingsEnabler;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.util.ReflectionHelpers;
 
 import java.util.List;
 
@@ -44,11 +54,24 @@ import java.util.List;
         })
 public class DevelopmentSettingsDashboardFragmentTest {
 
+    private SwitchBar mSwitchBar;
+    private ToggleSwitch mSwitch;
+    private Context mContext;
     private DevelopmentSettingsDashboardFragment mDashboard;
 
     @Before
     public void setUp() {
-        mDashboard = new DevelopmentSettingsDashboardFragment();
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mSwitchBar = new SwitchBar(mContext);
+        mSwitch = mSwitchBar.getSwitch();
+        mDashboard = spy(new DevelopmentSettingsDashboardFragment());
+        ReflectionHelpers.setField(mDashboard, "mSwitchBar", mSwitchBar);
+    }
+
+    @After
+    public void tearDown() {
+        ShadowEnableDevelopmentSettingWarningDialog.reset();
     }
 
     @Test
@@ -95,4 +118,62 @@ public class DevelopmentSettingsDashboardFragmentTest {
 
         assertThat(nonIndexableKeys).doesNotContain("development_prefs_screen");
     }
+
+    @Test
+    @Config(shadows = {
+            ShadowEnableDevelopmentSettingWarningDialog.class
+    })
+    public void onSwitchChanged_sameState_shouldDoNothing() {
+        when(mDashboard.getContext()).thenReturn(mContext);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0);
+
+        mDashboard.onSwitchChanged(mSwitch, false /* isChecked */);
+        assertThat(ShadowEnableDevelopmentSettingWarningDialog.mShown).isFalse();
+    }
+
+    @Test
+    @Config(shadows = {
+            ShadowEnableDevelopmentSettingWarningDialog.class
+    })
+    public void onSwitchChanged_turnOn_shouldShowWarningDialog() {
+        when(mDashboard.getContext()).thenReturn(mContext);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0);
+
+        mDashboard.onSwitchChanged(mSwitch, true /* isChecked */);
+        assertThat(ShadowEnableDevelopmentSettingWarningDialog.mShown).isTrue();
+    }
+
+    @Test
+    @Config(shadows = {
+            ShadowEnableDevelopmentSettingWarningDialog.class
+    })
+    public void onSwitchChanged_turnOff_shouldTurnOff() {
+        when(mDashboard.getContext()).thenReturn(mContext);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
+
+        mDashboard.onSwitchChanged(mSwitch, false /* isChecked */);
+
+        assertThat(ShadowEnableDevelopmentSettingWarningDialog.mShown).isFalse();
+        assertThat(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext))
+                .isFalse();
+    }
+
+    @Implements(EnableDevelopmentSettingWarningDialog.class)
+    public static class ShadowEnableDevelopmentSettingWarningDialog {
+
+        static boolean mShown;
+
+        public static void reset() {
+            mShown = false;
+        }
+
+        @Implementation
+        public static void show(
+                DevelopmentSettingsDashboardFragment host) {
+            mShown = true;
+        }
+    }
 }
index a53b836..6f79faf 100644 (file)
@@ -17,6 +17,7 @@
 package com.android.settings.development;
 
 import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
 
 import com.android.settings.TestConfig;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -45,6 +46,8 @@ public class DevelopmentSwitchBarControllerTest {
 
     @Mock
     private DevelopmentSettings mSettings;
+    @Mock
+    private DevelopmentSettingsDashboardFragment mNewSettings;
     private Lifecycle mLifecycle;
     private SwitchBar mSwitchBar;
     private DevelopmentSwitchBarController mController;
@@ -77,6 +80,21 @@ public class DevelopmentSwitchBarControllerTest {
     }
 
     @Test
+    public void runThroughLifecycle_v2_isMonkeyRun_shouldNotRegisterListener() {
+        ShadowUtils.setIsUserAMonkey(true);
+        mController = new DevelopmentSwitchBarController(mNewSettings, mSwitchBar,
+                true /* isAvailable */, mLifecycle);
+        final ArrayList<SwitchBar.OnSwitchChangeListener> listeners =
+                ReflectionHelpers.getField(mSwitchBar, "mSwitchChangeListeners");
+
+        mLifecycle.onStart();
+        assertThat(listeners).doesNotContain(mNewSettings);
+
+        mLifecycle.onStop();
+        assertThat(listeners).doesNotContain(mNewSettings);
+    }
+
+    @Test
     public void runThroughLifecycle_isNotMonkeyRun_shouldRegisterAndRemoveListener() {
         ShadowUtils.setIsUserAMonkey(false);
         mController = new DevelopmentSwitchBarController(mSettings, mSwitchBar,
@@ -92,6 +110,22 @@ public class DevelopmentSwitchBarControllerTest {
     }
 
     @Test
+    public void runThroughLifecycle_v2_isNotMonkeyRun_shouldRegisterAndRemoveListener() {
+        when(mNewSettings.getContext()).thenReturn(RuntimeEnvironment.application);
+        ShadowUtils.setIsUserAMonkey(false);
+        mController = new DevelopmentSwitchBarController(mNewSettings, mSwitchBar,
+                true /* isAvailable */, mLifecycle);
+        final ArrayList<SwitchBar.OnSwitchChangeListener> listeners =
+                ReflectionHelpers.getField(mSwitchBar, "mSwitchChangeListeners");
+
+        mLifecycle.onStart();
+        assertThat(listeners).contains(mNewSettings);
+
+        mLifecycle.onStop();
+        assertThat(listeners).doesNotContain(mNewSettings);
+    }
+
+    @Test
     public void buildController_unavailable_shouldDisableSwitchBar() {
         ShadowUtils.setIsUserAMonkey(false);
         mController = new DevelopmentSwitchBarController(mSettings, mSwitchBar,