From 2e4ff90f5afba2a3d5b1def3a19837db19ebdeff Mon Sep 17 00:00:00 2001 From: Doris Ling Date: Thu, 13 Apr 2017 15:06:36 -0700 Subject: [PATCH] Listen to brigtness updates to update brightness summary. - add content observer for brightness relates changes, and update the brightness preference summary when changes occur. - also check for VR mode and auto brightness mode when reading the current brightness value. Change-Id: I611ec77174ab45315ccbee2952bdbc2c9a9cd954 Fix: 37227609 Test: make RunSettingsRoboTests --- src/com/android/settings/DisplaySettings.java | 2 + .../BrightnessLevelPreferenceController.java | 166 ++++++++++++++++++ .../settings/display/PowerManagerWrapper.java | 49 ++++++ ...ightnessLevelPreferenceControllerTest.java | 157 +++++++++++++++++ .../search/DatabaseIndexingUtilsTest.java | 25 +-- 5 files changed, 387 insertions(+), 12 deletions(-) create mode 100644 src/com/android/settings/display/BrightnessLevelPreferenceController.java create mode 100644 src/com/android/settings/display/PowerManagerWrapper.java create mode 100644 tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java diff --git a/src/com/android/settings/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java index d6fcb72cf2c..2bb79b1767b 100644 --- a/src/com/android/settings/DisplaySettings.java +++ b/src/com/android/settings/DisplaySettings.java @@ -27,6 +27,7 @@ import com.android.settings.core.lifecycle.Lifecycle; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.display.AutoBrightnessPreferenceController; import com.android.settings.display.AutoRotatePreferenceController; +import com.android.settings.display.BrightnessLevelPreferenceController; import com.android.settings.display.CameraGesturePreferenceController; import com.android.settings.display.DozePreferenceController; import com.android.settings.display.FontSizePreferenceController; @@ -106,6 +107,7 @@ public class DisplaySettings extends DashboardFragment { controllers.add(new VrDisplayPreferenceController(context)); controllers.add(new WallpaperPreferenceController(context)); controllers.add(new ThemePreferenceController(context)); + controllers.add(new BrightnessLevelPreferenceController(context, lifecycle)); return controllers; } diff --git a/src/com/android/settings/display/BrightnessLevelPreferenceController.java b/src/com/android/settings/display/BrightnessLevelPreferenceController.java new file mode 100644 index 00000000000..a6e5ed742c8 --- /dev/null +++ b/src/com/android/settings/display/BrightnessLevelPreferenceController.java @@ -0,0 +1,166 @@ +/* + * 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.display; + +import android.content.ContentResolver; +import android.content.Context; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.os.PowerManager; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.provider.Settings; +import android.provider.Settings.System; +import android.service.vr.IVrManager; +import android.support.annotation.VisibleForTesting; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; +import android.util.Log; + +import com.android.settings.core.PreferenceController; +import com.android.settings.core.lifecycle.Lifecycle; +import com.android.settings.core.lifecycle.LifecycleObserver; +import com.android.settings.core.lifecycle.events.OnPause; +import com.android.settings.core.lifecycle.events.OnResume; + +import java.text.NumberFormat; + +public class BrightnessLevelPreferenceController extends PreferenceController implements + LifecycleObserver, OnResume, OnPause { + + private static final String TAG = "BrightnessPrefCtrl"; + private static final String KEY_BRIGHTNESS = "brightness"; + private static final Uri BRIGHTNESS_MODE_URI; + private static final Uri BRIGHTNESS_URI; + private static final Uri BRIGHTNESS_FOR_VR_URI; + private static final Uri BRIGHTNESS_ADJ_URI; + + private final int mMinBrightness; + private final int mMaxBrightness; + private final int mMinVrBrightness; + private final int mMaxVrBrightness; + private final ContentResolver mContentResolver; + + private Preference mPreference; + + static { + BRIGHTNESS_MODE_URI = System.getUriFor(System.SCREEN_BRIGHTNESS_MODE); + BRIGHTNESS_URI = System.getUriFor(System.SCREEN_BRIGHTNESS); + BRIGHTNESS_FOR_VR_URI = System.getUriFor(System.SCREEN_BRIGHTNESS_FOR_VR); + BRIGHTNESS_ADJ_URI = System.getUriFor(System.SCREEN_AUTO_BRIGHTNESS_ADJ); + } + + private ContentObserver mBrightnessObserver = + new ContentObserver(new Handler(Looper.getMainLooper())) { + @Override + public void onChange(boolean selfChange) { + updatedSummary(mPreference); + } + }; + + public BrightnessLevelPreferenceController(Context context, Lifecycle lifecycle) { + this(context, lifecycle, new PowerManagerWrapper( + (PowerManager) context.getSystemService(Context.POWER_SERVICE))); + } + + @VisibleForTesting + public BrightnessLevelPreferenceController(Context context, Lifecycle lifecycle, + PowerManagerWrapper powerManagerWrapper) { + super(context); + if (lifecycle != null) { + lifecycle.addObserver(this); + } + mMinBrightness = powerManagerWrapper.getMinimumScreenBrightnessSetting(); + mMaxBrightness = powerManagerWrapper.getMaximumScreenBrightnessSetting(); + mMinVrBrightness = powerManagerWrapper.getMinimumScreenBrightnessForVrSetting(); + mMaxVrBrightness = powerManagerWrapper.getMaximumScreenBrightnessForVrSetting(); + mContentResolver = mContext.getContentResolver(); + } + + @Override + public boolean isAvailable() { + return true; + } + + @Override + public String getPreferenceKey() { + return KEY_BRIGHTNESS; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(KEY_BRIGHTNESS); + } + + @Override + public void updateState(Preference preference) { + updatedSummary(preference); + } + + @Override + public void onResume() { + mContentResolver.registerContentObserver(BRIGHTNESS_MODE_URI, false, mBrightnessObserver); + mContentResolver.registerContentObserver(BRIGHTNESS_URI, false, mBrightnessObserver); + mContentResolver.registerContentObserver(BRIGHTNESS_FOR_VR_URI, false, mBrightnessObserver); + mContentResolver.registerContentObserver(BRIGHTNESS_ADJ_URI, false, mBrightnessObserver); + } + + @Override + public void onPause() { + mContentResolver.unregisterContentObserver(mBrightnessObserver); + } + + private void updatedSummary(Preference preference) { + if (preference != null) { + preference.setSummary(NumberFormat.getPercentInstance().format(getCurrentBrightness())); + } + } + + private double getCurrentBrightness() { + if (isInVrMode()) { + final double value = System.getInt(mContentResolver, System.SCREEN_BRIGHTNESS_FOR_VR, + mMaxBrightness); + return getPercentage(value, mMinVrBrightness, mMaxVrBrightness); + } + final int brightnessMode = Settings.System.getInt(mContentResolver, + System.SCREEN_BRIGHTNESS_MODE, System.SCREEN_BRIGHTNESS_MODE_MANUAL); + if (brightnessMode == System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) { + final float value = Settings.System.getFloat(mContentResolver, + System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0); + // auto brightness is between -1 and 1 + return ((value + 1)) / 2; + } + final double value = Settings.System.getInt(mContentResolver, System.SCREEN_BRIGHTNESS, + mMinBrightness); + return getPercentage(value, mMinBrightness, mMaxBrightness); + } + + private double getPercentage(double value, int min, int max) { + return (value - min) / (max - min); + } + + @VisibleForTesting + boolean isInVrMode() { + try { + return IVrManager.Stub.asInterface(ServiceManager.getService(Context.VR_SERVICE)) + .getVrModeState(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to check vr mode!", e); + } + return false; + } +} diff --git a/src/com/android/settings/display/PowerManagerWrapper.java b/src/com/android/settings/display/PowerManagerWrapper.java new file mode 100644 index 00000000000..afa2f333590 --- /dev/null +++ b/src/com/android/settings/display/PowerManagerWrapper.java @@ -0,0 +1,49 @@ +/* + * 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.display; + +import android.os.PowerManager; + +/** + * This class replicates a subset of the android.os.PowerManager. The class exists so that we can + * use a thin wrapper around the PowerManager in production code and a mock in tests. We cannot + * directly mock or shadow the PowerManager, because some of the methods we rely on are newer than + * the API version supported by Robolectric or are hidden. + */ +public class PowerManagerWrapper { + private final PowerManager mPowerManager; + + public PowerManagerWrapper(PowerManager powerManager) { + mPowerManager = powerManager; + } + + public int getMinimumScreenBrightnessSetting() { + return mPowerManager.getMinimumScreenBrightnessSetting(); + } + + public int getMaximumScreenBrightnessSetting() { + return mPowerManager.getMaximumScreenBrightnessSetting(); + } + + public int getMinimumScreenBrightnessForVrSetting() { + return mPowerManager.getMinimumScreenBrightnessForVrSetting(); + } + + public int getMaximumScreenBrightnessForVrSetting() { + return mPowerManager.getMaximumScreenBrightnessForVrSetting(); + } +} diff --git a/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java new file mode 100644 index 00000000000..0b330890617 --- /dev/null +++ b/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java @@ -0,0 +1,157 @@ +/* + * 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.display; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.ContentResolver; +import android.content.Context; +import android.provider.Settings.System; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; + +import com.android.settings.SettingsRobolectricTestRunner; +import com.android.settings.TestConfig; + +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; +import org.robolectric.internal.ShadowExtractor; +import org.robolectric.shadows.ShadowContentResolver; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class BrightnessLevelPreferenceControllerTest { + @Mock + private Context mContext; + @Mock + private ContentResolver mContentResolver; + @Mock + private PowerManagerWrapper mPowerManager; + @Mock + private PreferenceScreen mScreen; + @Mock + private Preference mPreference; + + private BrightnessLevelPreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(mContext.getContentResolver()).thenReturn(mContentResolver); + when(mPowerManager.getMinimumScreenBrightnessSetting()).thenReturn(0); + when(mPowerManager.getMaximumScreenBrightnessSetting()).thenReturn(100); + when(mPowerManager.getMinimumScreenBrightnessForVrSetting()).thenReturn(0); + when(mPowerManager.getMaximumScreenBrightnessForVrSetting()).thenReturn(100); + when(mScreen.findPreference(anyString())).thenReturn(mPreference); + mController = spy(new BrightnessLevelPreferenceController(mContext, null, mPowerManager)); + doReturn(false).when(mController).isInVrMode(); + + } + + @Test + public void isAvailable_shouldAlwaysReturnTrue() { + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void onResume_shouldRegisterObserver() { + Context context = RuntimeEnvironment.application; + BrightnessLevelPreferenceController controller = + new BrightnessLevelPreferenceController(context, null, mPowerManager); + ShadowContentResolver shadowContentResolver = + (ShadowContentResolver) ShadowExtractor.extract(context.getContentResolver()); + + controller.onResume(); + + assertThat(shadowContentResolver.getContentObservers( + System.getUriFor(System.SCREEN_BRIGHTNESS_MODE))).isNotEmpty(); + assertThat(shadowContentResolver.getContentObservers( + System.getUriFor(System.SCREEN_BRIGHTNESS))).isNotEmpty(); + assertThat(shadowContentResolver.getContentObservers( + System.getUriFor(System.SCREEN_BRIGHTNESS_FOR_VR))).isNotEmpty(); + assertThat(shadowContentResolver.getContentObservers( + System.getUriFor(System.SCREEN_AUTO_BRIGHTNESS_ADJ))).isNotEmpty(); + } + + @Test + public void onPause_shouldUnregisterObserver() { + Context context = RuntimeEnvironment.application; + BrightnessLevelPreferenceController controller = + new BrightnessLevelPreferenceController(context, null, mPowerManager); + ShadowContentResolver shadowContentResolver = + (ShadowContentResolver) ShadowExtractor.extract(context.getContentResolver()); + + controller.displayPreference(mScreen); + controller.onResume(); + controller.onPause(); + + assertThat(shadowContentResolver.getContentObservers( + System.getUriFor(System.SCREEN_BRIGHTNESS_MODE))).isEmpty(); + assertThat(shadowContentResolver.getContentObservers( + System.getUriFor(System.SCREEN_BRIGHTNESS))).isEmpty(); + assertThat(shadowContentResolver.getContentObservers( + System.getUriFor(System.SCREEN_BRIGHTNESS_FOR_VR))).isEmpty(); + assertThat(shadowContentResolver.getContentObservers( + System.getUriFor(System.SCREEN_AUTO_BRIGHTNESS_ADJ))).isEmpty(); + } + + @Test + public void updateState_inVrMode_shouldSetSummaryToVrBrightness() { + doReturn(true).when(mController).isInVrMode(); + System.putInt(mContentResolver, System.SCREEN_BRIGHTNESS_FOR_VR, 85); + + mController.updateState(mPreference); + + verify(mPreference).setSummary("85%"); + } + + @Test + public void updateState_autoBrightness_shouldSetSummaryToVrBrightness() { + doReturn(false).when(mController).isInVrMode(); + System.putInt(mContentResolver, System.SCREEN_BRIGHTNESS_MODE, + System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); + + System.putFloat(mContentResolver, System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f); + + mController.updateState(mPreference); + + verify(mPreference).setSummary("50%"); + } + + @Test + public void updateState_manualBrightness_shouldSetSummaryToVrBrightness() { + doReturn(false).when(mController).isInVrMode(); + System.putInt(mContentResolver, System.SCREEN_BRIGHTNESS_MODE, + System.SCREEN_BRIGHTNESS_MODE_MANUAL); + + System.putInt(mContentResolver, System.SCREEN_BRIGHTNESS, 45); + + mController.updateState(mPreference); + + verify(mPreference).setSummary("45%"); + } +} diff --git a/tests/robotests/src/com/android/settings/search/DatabaseIndexingUtilsTest.java b/tests/robotests/src/com/android/settings/search/DatabaseIndexingUtilsTest.java index d87c63d3445..12ee5ae5557 100644 --- a/tests/robotests/src/com/android/settings/search/DatabaseIndexingUtilsTest.java +++ b/tests/robotests/src/com/android/settings/search/DatabaseIndexingUtilsTest.java @@ -17,29 +17,30 @@ package com.android.settings.search; -import android.content.Context; +import static com.google.common.truth.Truth.assertThat; +import android.content.Context; import android.util.ArrayMap; + import com.android.internal.hardware.AmbientDisplayConfiguration; import com.android.settings.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.core.PreferenceController; import com.android.settings.display.AutoBrightnessPreferenceController; import com.android.settings.search2.DatabaseIndexingUtils; - +import com.android.settings.deviceinfo.SystemUpdatePreferenceController; import com.android.settings.search2.ResultPayload; + 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; -import org.robolectric.shadows.ShadowApplication; import java.util.Map; -import static com.google.common.truth.Truth.assertThat; - @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class DatabaseIndexingUtilsTest { @@ -51,7 +52,7 @@ public class DatabaseIndexingUtilsTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mContext = ShadowApplication.getInstance().getApplicationContext(); + mContext = RuntimeEnvironment.application; } @Test @@ -68,11 +69,11 @@ public class DatabaseIndexingUtilsTest { @Test public void testGetPreferenceControllerUriMap_CompatibleClass_ReturnsValidMap() { - String className = "com.android.settings.DisplaySettings"; - - Map map = DatabaseIndexingUtils.getPreferenceControllerUriMap(className, mContext); - assertThat(map.get("auto_brightness")) - .isInstanceOf(AutoBrightnessPreferenceController.class); + final String className = "com.android.settings.system.SystemDashboardFragment"; + final Map map = + DatabaseIndexingUtils.getPreferenceControllerUriMap(className, mContext); + assertThat(map.get("system_update_settings")) + .isInstanceOf(SystemUpdatePreferenceController.class); } @Test @@ -100,7 +101,7 @@ public class DatabaseIndexingUtilsTest { return new ResultPayload(null); } }; - ArrayMap map = new ArrayMap<>(); + ArrayMap map = new ArrayMap<>(); map.put(key, prefController); ResultPayload payload = DatabaseIndexingUtils.getPayloadFromUriMap(map, key);