diff --git a/src/com/android/settings/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java index 1230ae58c0f..b29f8a0940c 100644 --- a/src/com/android/settings/DisplaySettings.java +++ b/src/com/android/settings/DisplaySettings.java @@ -104,7 +104,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)); + 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 index e0000d6949d..d012ac33abb 100644 --- a/src/com/android/settings/display/BrightnessLevelPreferenceController.java +++ b/src/com/android/settings/display/BrightnessLevelPreferenceController.java @@ -13,20 +13,79 @@ */ package com.android.settings.display; -import static android.provider.Settings.System.SCREEN_BRIGHTNESS; - +import android.content.ContentResolver; import android.content.Context; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +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 { +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; - public BrightnessLevelPreferenceController(Context context) { + 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()) { + @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 @@ -40,10 +99,66 @@ public class BrightnessLevelPreferenceController extends PreferenceController { } @Override - public void updateState(Preference preference) { - final double brightness = Settings.System.getInt(mContext.getContentResolver(), - SCREEN_BRIGHTNESS, 0); - preference.setSummary(NumberFormat.getPercentInstance().format(brightness / 255)); + 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 index 025e1ae908d..0b330890617 100644 --- a/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java @@ -16,27 +16,31 @@ package com.android.settings.display; -import static android.provider.Settings.System.SCREEN_BRIGHTNESS; 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; +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 com.android.settings.testutils.shadow.SettingsShadowSystemProperties; -import java.text.NumberFormat; 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) @@ -46,6 +50,10 @@ public class BrightnessLevelPreferenceControllerTest { @Mock private ContentResolver mContentResolver; @Mock + private PowerManagerWrapper mPowerManager; + @Mock + private PreferenceScreen mScreen; + @Mock private Preference mPreference; private BrightnessLevelPreferenceController mController; @@ -53,8 +61,15 @@ public class BrightnessLevelPreferenceControllerTest { @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(); - mController = new BrightnessLevelPreferenceController(mContext); } @Test @@ -63,14 +78,80 @@ public class BrightnessLevelPreferenceControllerTest { } @Test - public void updateState_shouldSetSummary() { - final NumberFormat formatter = NumberFormat.getPercentInstance(); - when(mContext.getContentResolver()).thenReturn(mContentResolver); - Settings.System.putInt(mContentResolver, SCREEN_BRIGHTNESS, 45); + 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(formatter.format(45.0 / 255)); + 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..474a3c4c827 100644 --- a/tests/robotests/src/com/android/settings/search/DatabaseIndexingUtilsTest.java +++ b/tests/robotests/src/com/android/settings/search/DatabaseIndexingUtilsTest.java @@ -17,29 +17,29 @@ 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.deviceinfo.SystemUpdatePreferenceController; import com.android.settings.search2.DatabaseIndexingUtils; - 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 +51,7 @@ public class DatabaseIndexingUtilsTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mContext = ShadowApplication.getInstance().getApplicationContext(); + mContext = RuntimeEnvironment.application; } @Test @@ -68,11 +68,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,10 +100,10 @@ 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); assertThat(payload).isInstanceOf(ResultPayload.class); } -} \ No newline at end of file +}