Merge "Add a new reason code for IMS call failed due to network congestion" into rvc-qpr-dev
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index c1ba209..0fa4ca8 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -875,12 +875,52 @@
public interface DeviceConfig {
/**
- * Key for refresh rate in the zone defined by thresholds.
+ * Key for refresh rate in the low zone defined by thresholds.
*
+ * Note that the name and value don't match because they were added before we had a high
+ * zone to consider.
* @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
* @see android.R.integer#config_defaultZoneBehavior
*/
- String KEY_REFRESH_RATE_IN_ZONE = "refresh_rate_in_zone";
+ String KEY_REFRESH_RATE_IN_LOW_ZONE = "refresh_rate_in_zone";
+
+ /**
+ * Key for accessing the low display brightness thresholds for the configured refresh
+ * rate zone.
+ * The value will be a pair of comma separated integers representing the minimum and maximum
+ * thresholds of the zone, respectively, in display backlight units (i.e. [0, 255]).
+ *
+ * Note that the name and value don't match because they were added before we had a high
+ * zone to consider.
+ *
+ * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
+ * @see android.R.array#config_brightnessThresholdsOfPeakRefreshRate
+ * @hide
+ */
+ String KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS =
+ "peak_refresh_rate_brightness_thresholds";
+
+ /**
+ * Key for accessing the low ambient brightness thresholds for the configured refresh
+ * rate zone. The value will be a pair of comma separated integers representing the minimum
+ * and maximum thresholds of the zone, respectively, in lux.
+ *
+ * Note that the name and value don't match because they were added before we had a high
+ * zone to consider.
+ *
+ * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
+ * @see android.R.array#config_ambientThresholdsOfPeakRefreshRate
+ * @hide
+ */
+ String KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS =
+ "peak_refresh_rate_ambient_thresholds";
+ /**
+ * Key for refresh rate in the high zone defined by thresholds.
+ *
+ * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
+ * @see android.R.integer#config_fixedRefreshRateInHighZone
+ */
+ String KEY_REFRESH_RATE_IN_HIGH_ZONE = "refresh_rate_in_high_zone";
/**
* Key for accessing the display brightness thresholds for the configured refresh rate zone.
@@ -888,11 +928,11 @@
* thresholds of the zone, respectively, in display backlight units (i.e. [0, 255]).
*
* @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
- * @see android.R.array#config_brightnessThresholdsOfPeakRefreshRate
+ * @see android.R.array#config_brightnessHighThresholdsOfFixedRefreshRate
* @hide
*/
- String KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS =
- "peak_refresh_rate_brightness_thresholds";
+ String KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS =
+ "fixed_refresh_rate_high_display_brightness_thresholds";
/**
* Key for accessing the ambient brightness thresholds for the configured refresh rate zone.
@@ -900,12 +940,11 @@
* thresholds of the zone, respectively, in lux.
*
* @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
- * @see android.R.array#config_ambientThresholdsOfPeakRefreshRate
+ * @see android.R.array#config_ambientHighThresholdsOfFixedRefreshRate
* @hide
*/
- String KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS =
- "peak_refresh_rate_ambient_thresholds";
-
+ String KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS =
+ "fixed_refresh_rate_high_ambient_brightness_thresholds";
/**
* Key for default peak refresh rate
*
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index efea953..47598cf 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -31,8 +31,12 @@
import libcore.io.IoUtils;
+import java.io.BufferedReader;
import java.io.FileDescriptor;
+import java.io.FileReader;
+import java.io.IOException;
import java.util.Map;
+import java.util.StringTokenizer;
import java.util.concurrent.TimeoutException;
/**
@@ -1393,4 +1397,38 @@
}
private static native int nativePidFdOpen(int pid, int flags) throws ErrnoException;
+
+ /**
+ * Checks if a process corresponding to a specific pid owns any file locks.
+ * @param pid The process ID for which we want to know the existence of file locks.
+ * @return true If the process holds any file locks, false otherwise.
+ * @throws IOException if /proc/locks can't be accessed.
+ *
+ * @hide
+ */
+ public static boolean hasFileLocks(int pid) throws IOException {
+ BufferedReader br = null;
+
+ try {
+ br = new BufferedReader(new FileReader("/proc/locks"));
+ String line;
+
+ while ((line = br.readLine()) != null) {
+ StringTokenizer st = new StringTokenizer(line);
+
+ for (int i = 0; i < 5 && st.hasMoreTokens(); i++) {
+ String str = st.nextToken();
+ if (i == 4 && Integer.parseInt(str) == pid) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ } finally {
+ if (br != null) {
+ br.close();
+ }
+ }
+ }
}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 550601a..5f02eb6 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4138,6 +4138,35 @@
If non-positive, then the refresh rate is unchanged even if thresholds are configured. -->
<integer name="config_defaultRefreshRateInZone">0</integer>
+ <!-- The display uses different gamma curves for different refresh rates. It's hard for panel
+ vendor to tune the curves to have exact same brightness for different refresh rate. So
+ flicker could be observed at switch time. The issue can be observed on the screen with
+ even full white content at the high brightness. To prevent flickering, we support fixed
+ refresh rates if the display and ambient brightness are equal to or above the provided
+ thresholds. You can define multiple threshold levels as higher brightness environments
+ may have lower display brightness requirements for the flickering is visible. And the
+ high brightness environment could have higher threshold.
+ For example, fixed refresh rate if
+ display brightness >= disp0 && ambient brightness >= amb0
+ || display brightness >= disp1 && ambient brightness >= amb1 -->
+ <integer-array translatable="false" name="config_highDisplayBrightnessThresholdsOfFixedRefreshRate">
+ <!--
+ <item>disp0</item>
+ <item>disp1</item>
+ -->
+ </integer-array>
+
+ <integer-array translatable="false" name="config_highAmbientBrightnessThresholdsOfFixedRefreshRate">
+ <!--
+ <item>amb0</item>
+ <item>amb1</item>
+ -->
+ </integer-array>
+
+ <!-- Default refresh rate in the high zone defined by brightness and ambient thresholds.
+ If non-positive, then the refresh rate is unchanged even if thresholds are configured. -->
+ <integer name="config_fixedRefreshRateInHighZone">0</integer>
+
<!-- The type of the light sensor to be used by the display framework for things like
auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. -->
<string name="config_displayLightSensorType" translatable="false" />
diff --git a/core/res/res/values/required_apps_managed_device.xml b/core/res/res/values/required_apps_managed_device.xml
index 40db9df..4c5cd68 100644
--- a/core/res/res/values/required_apps_managed_device.xml
+++ b/core/res/res/values/required_apps_managed_device.xml
@@ -27,5 +27,6 @@
<item>com.android.providers.downloads</item>
<item>com.android.providers.downloads.ui</item>
<item>com.android.documentsui</item>
+ <item>com.android.cellbroadcastreceiver</item>
</string-array>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 06f357e..b80e8e1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3783,6 +3783,11 @@
<java-symbol type="array" name="config_brightnessThresholdsOfPeakRefreshRate" />
<java-symbol type="array" name="config_ambientThresholdsOfPeakRefreshRate" />
+ <!-- For fixed refresh rate displays in high brightness-->
+ <java-symbol type="integer" name="config_fixedRefreshRateInHighZone" />
+ <java-symbol type="array" name="config_highDisplayBrightnessThresholdsOfFixedRefreshRate" />
+ <java-symbol type="array" name="config_highAmbientBrightnessThresholdsOfFixedRefreshRate" />
+
<!-- For Auto-Brightness -->
<java-symbol type="string" name="config_displayLightSensorType" />
diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp
index 3c990ab..d6df64f 100644
--- a/data/etc/car/Android.bp
+++ b/data/etc/car/Android.bp
@@ -151,13 +151,6 @@
}
prebuilt_etc {
- name: "privapp_whitelist_com.android.car.floatingcardslauncher",
- sub_dir: "permissions",
- src: "com.android.car.floatingcardslauncher.xml",
- filename_from_src: true,
-}
-
-prebuilt_etc {
name: "privapp_whitelist_com.android.car.ui.paintbooth",
sub_dir: "permissions",
src: "com.android.car.ui.paintbooth.xml",
diff --git a/data/etc/car/com.android.car.floatingcardslauncher.xml b/data/etc/car/com.android.car.floatingcardslauncher.xml
deleted file mode 100644
index 2755fee..0000000
--- a/data/etc/car/com.android.car.floatingcardslauncher.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 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
- -->
-<permissions>
- <privapp-permissions package="com.android.car.floatingcardslauncher">
- <permission name="android.permission.ACTIVITY_EMBEDDING"/>
- <permission name="android.permission.INTERACT_ACROSS_USERS"/>
- <permission name="android.permission.MANAGE_USERS"/>
- <permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
- <permission name="android.permission.MODIFY_PHONE_STATE"/>
- </privapp-permissions>
-</permissions>
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
index 1d47fc5..7daad1c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
@@ -160,12 +160,12 @@
@Override
protected void handleResetAfterError() {
- resetErrorView(mContext, mIndicatorView);
+ resetErrorView();
}
@Override
protected void handleResetAfterHelp() {
- resetErrorView(mContext, mIndicatorView);
+ resetErrorView();
}
@Override
@@ -185,7 +185,7 @@
if (newState == STATE_AUTHENTICATING_ANIMATING_IN ||
(newState == STATE_AUTHENTICATING && mSize == AuthDialog.SIZE_MEDIUM)) {
- resetErrorView(mContext, mIndicatorView);
+ resetErrorView();
}
// Do this last since the state variable gets updated.
@@ -204,9 +204,8 @@
super.onAuthenticationFailed(failureReason);
}
- static void resetErrorView(Context context, TextView textView) {
- textView.setTextColor(context.getResources().getColor(
- R.color.biometric_dialog_gray, context.getTheme()));
- textView.setVisibility(View.INVISIBLE);
+ private void resetErrorView() {
+ mIndicatorView.setTextColor(mTextColorHint);
+ mIndicatorView.setVisibility(View.INVISIBLE);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.java
index 176e9e6..45ee4ad 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.java
@@ -78,7 +78,7 @@
private void showTouchSensorString() {
mIndicatorView.setText(R.string.fingerprint_dialog_touch_sensor);
- mIndicatorView.setTextColor(R.color.biometric_dialog_gray);
+ mIndicatorView.setTextColor(mTextColorHint);
}
private void updateIcon(int lastState, int newState) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index 7c25d28..f9c6d32 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -82,7 +82,7 @@
* Authenticated, dialog animating away soon.
*/
protected static final int STATE_AUTHENTICATED = 6;
-
+
@Retention(RetentionPolicy.SOURCE)
@IntDef({STATE_IDLE, STATE_AUTHENTICATING_ANIMATING_IN, STATE_AUTHENTICATING, STATE_HELP,
STATE_ERROR, STATE_PENDING_CONFIRMATION, STATE_AUTHENTICATED})
@@ -155,8 +155,8 @@
private final Injector mInjector;
private final Handler mHandler;
private final AccessibilityManager mAccessibilityManager;
- private final int mTextColorError;
- private final int mTextColorHint;
+ protected final int mTextColorError;
+ protected final int mTextColorHint;
private AuthPanelController mPanelController;
private Bundle mBiometricPromptBundle;
@@ -169,7 +169,7 @@
private TextView mSubtitleView;
private TextView mDescriptionView;
protected ImageView mIconView;
- @VisibleForTesting protected TextView mIndicatorView;
+ protected TextView mIndicatorView;
@VisibleForTesting Button mNegativeButton;
@VisibleForTesting Button mPositiveButton;
@VisibleForTesting Button mTryAgainButton;
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
index 08cd6e3..8d77c4a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
@@ -33,7 +33,7 @@
static final String REASON_WRAP = "wrap";
/**
- * Default wake-lock timeout, to avoid battery regressions.
+ * Default wake-lock timeout in milliseconds, to avoid battery regressions.
*/
long DEFAULT_MAX_TIMEOUT = 20000;
@@ -104,6 +104,7 @@
if (count == null) {
Log.wtf(TAG, "Releasing WakeLock with invalid reason: " + why,
new Throwable());
+ return;
} else if (count == 1) {
mActiveClients.remove(why);
} else {
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 4bba0d8..7585d6b 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -1,4 +1,11 @@
filegroup {
+ name: "services.core-sources-deviceconfig-interface",
+ srcs: [
+ "java/com/android/server/utils/DeviceConfigInterface.java"
+ ],
+}
+
+filegroup {
name: "services.core-sources",
srcs: ["java/**/*.java"],
path: "java",
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 36d4a38..9eb7c07 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -1101,15 +1101,26 @@
}
private void freezeProcess(ProcessRecord proc) {
- final int pid;
- final String name;
+ final int pid = proc.pid;
+ final String name = proc.processName;
final long unfrozenDuration;
final boolean frozen;
- synchronized (mAm) {
- pid = proc.pid;
- name = proc.processName;
+ try {
+ // pre-check for locks to avoid unnecessary freeze/unfreeze operations
+ if (Process.hasFileLocks(pid)) {
+ if (DEBUG_FREEZER) {
+ Slog.d(TAG_AM, name + " (" + pid + ") holds file locks, not freezing");
+ }
+ return;
+ }
+ } catch (IOException e) {
+ Slog.e(TAG_AM, "Not freezing. Unable to check file locks for " + name + "(" + pid
+ + "): " + e);
+ return;
+ }
+ synchronized (mAm) {
if (proc.curAdj < ProcessList.CACHED_APP_MIN_ADJ
|| proc.shouldNotFreeze) {
if (DEBUG_FREEZER) {
@@ -1141,29 +1152,50 @@
frozen = proc.frozen;
}
- if (frozen) {
- if (DEBUG_FREEZER) {
- Slog.d(TAG_AM, "froze " + pid + " " + name);
+ if (!frozen) {
+ return;
+ }
+
+
+ if (DEBUG_FREEZER) {
+ Slog.d(TAG_AM, "froze " + pid + " " + name);
+ }
+
+ EventLog.writeEvent(EventLogTags.AM_FREEZE, pid, name);
+
+ try {
+ freezeBinder(pid, true);
+ } catch (RuntimeException e) {
+ Slog.e(TAG_AM, "Unable to freeze binder for " + pid + " " + name);
+ proc.kill("Unable to freeze binder interface",
+ ApplicationExitInfo.REASON_OTHER,
+ ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
+ }
+
+ // See above for why we're not taking mPhenotypeFlagLock here
+ if (mRandom.nextFloat() < mFreezerStatsdSampleRate) {
+ FrameworkStatsLog.write(FrameworkStatsLog.APP_FREEZE_CHANGED,
+ FrameworkStatsLog.APP_FREEZE_CHANGED__ACTION__FREEZE_APP,
+ pid,
+ name,
+ unfrozenDuration);
+ }
+
+ try {
+ // post-check to prevent races
+ if (Process.hasFileLocks(pid)) {
+ if (DEBUG_FREEZER) {
+ Slog.d(TAG_AM, name + " (" + pid + ") holds file locks, reverting freeze");
+ }
+
+ synchronized (mAm) {
+ unfreezeAppLocked(proc);
+ }
}
-
- EventLog.writeEvent(EventLogTags.AM_FREEZE, pid, name);
-
- try {
- freezeBinder(pid, true);
- } catch (RuntimeException e) {
- Slog.e(TAG_AM, "Unable to freeze binder for " + pid + " " + name);
- proc.kill("Unable to freeze binder interface",
- ApplicationExitInfo.REASON_OTHER,
- ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
- }
-
- // See above for why we're not taking mPhenotypeFlagLock here
- if (mRandom.nextFloat() < mFreezerStatsdSampleRate) {
- FrameworkStatsLog.write(FrameworkStatsLog.APP_FREEZE_CHANGED,
- FrameworkStatsLog.APP_FREEZE_CHANGED__ACTION__FREEZE_APP,
- pid,
- name,
- unfrozenDuration);
+ } catch (IOException e) {
+ Slog.e(TAG_AM, "Unable to check file locks for " + name + "(" + pid + "): " + e);
+ synchronized (mAm) {
+ unfreezeAppLocked(proc);
}
}
}
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 3c05080..29a77e2 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -46,13 +46,18 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.display.utils.AmbientFilter;
import com.android.server.display.utils.AmbientFilterFactory;
+import com.android.server.utils.DeviceConfigInterface;
import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Date;
import java.util.List;
+import java.util.Locale;
import java.util.Objects;
/**
@@ -64,9 +69,11 @@
private static final boolean DEBUG = false;
private static final int MSG_REFRESH_RATE_RANGE_CHANGED = 1;
- private static final int MSG_BRIGHTNESS_THRESHOLDS_CHANGED = 2;
+ private static final int MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED = 2;
private static final int MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED = 3;
- private static final int MSG_REFRESH_RATE_IN_ZONE_CHANGED = 4;
+ private static final int MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED = 4;
+ private static final int MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED = 5;
+ private static final int MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED = 6;
// Special ID used to indicate that given vote is to be applied globally, rather than to a
// specific display.
@@ -79,6 +86,13 @@
private final Context mContext;
private final DisplayModeDirectorHandler mHandler;
+ private final Injector mInjector;
+
+ private final AppRequestObserver mAppRequestObserver;
+ private final SettingsObserver mSettingsObserver;
+ private final DisplayObserver mDisplayObserver;
+ private final DeviceConfigInterface mDeviceConfig;
+ private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
// A map from the display ID to the collection of votes and their priority. The latter takes
// the form of another map from the priority to the vote itself so that each priority is
@@ -89,17 +103,19 @@
// A map from the display ID to the default mode of that display.
private SparseArray<Display.Mode> mDefaultModeByDisplay;
- private final AppRequestObserver mAppRequestObserver;
- private final SettingsObserver mSettingsObserver;
- private final DisplayObserver mDisplayObserver;
private BrightnessObserver mBrightnessObserver;
- private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
private DesiredDisplayModeSpecsListener mDesiredDisplayModeSpecsListener;
public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) {
+ this(context, handler, new RealInjector());
+ }
+
+ public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler,
+ @NonNull Injector injector) {
mContext = context;
mHandler = new DisplayModeDirectorHandler(handler.getLooper());
+ mInjector = injector;
mVotesByDisplay = new SparseArray<>();
mSupportedModesByDisplay = new SparseArray<>();
mDefaultModeByDisplay = new SparseArray<>();
@@ -108,6 +124,7 @@
mDisplayObserver = new DisplayObserver(context, handler);
mBrightnessObserver = new BrightnessObserver(context, handler);
mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
+ mDeviceConfig = injector.getDeviceConfig();
}
/**
@@ -349,6 +366,23 @@
}
/**
+ * Retrieve the Vote for the given display and priority. Intended only for testing purposes.
+ *
+ * @param displayId the display to query for
+ * @param priority the priority of the vote to return
+ * @return the vote corresponding to the given {@code displayId} and {@code priority},
+ * or {@code null} if there isn't one
+ */
+ @VisibleForTesting
+ @Nullable
+ Vote getVote(int displayId, int priority) {
+ synchronized (mLock) {
+ SparseArray<Vote> votes = getVotesLocked(displayId);
+ return votes.get(priority);
+ }
+ }
+
+ /**
* Print the object's state and debug information into the given stream.
*
* @param pw The stream to dump information to.
@@ -466,6 +500,17 @@
}
@VisibleForTesting
+ BrightnessObserver getBrightnessObserver() {
+ return mBrightnessObserver;
+ }
+
+ @VisibleForTesting
+ SettingsObserver getSettingsObserver() {
+ return mSettingsObserver;
+ }
+
+
+ @VisibleForTesting
DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
synchronized (mLock) {
@@ -493,16 +538,35 @@
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case MSG_BRIGHTNESS_THRESHOLDS_CHANGED:
+ case MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED: {
+ Pair<int[], int[]> thresholds = (Pair<int[], int[]>) msg.obj;
+ mBrightnessObserver.onDeviceConfigLowBrightnessThresholdsChanged(
+ thresholds.first, thresholds.second);
+ break;
+ }
+
+ case MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED: {
+ int refreshRateInZone = msg.arg1;
+ mBrightnessObserver.onDeviceConfigRefreshRateInLowZoneChanged(
+ refreshRateInZone);
+ break;
+ }
+
+ case MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED: {
Pair<int[], int[]> thresholds = (Pair<int[], int[]>) msg.obj;
- if (thresholds != null) {
- mBrightnessObserver.onDeviceConfigThresholdsChanged(
- thresholds.first, thresholds.second);
- } else {
- mBrightnessObserver.onDeviceConfigThresholdsChanged(null, null);
- }
+ mBrightnessObserver.onDeviceConfigHighBrightnessThresholdsChanged(
+ thresholds.first, thresholds.second);
+
break;
+ }
+
+ case MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED: {
+ int refreshRateInZone = msg.arg1;
+ mBrightnessObserver.onDeviceConfigRefreshRateInHighZoneChanged(
+ refreshRateInZone);
+ break;
+ }
case MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED:
Float defaultPeakRefreshRate = (Float) msg.obj;
@@ -510,12 +574,6 @@
defaultPeakRefreshRate);
break;
- case MSG_REFRESH_RATE_IN_ZONE_CHANGED:
- int refreshRateInZone = msg.arg1;
- mBrightnessObserver.onDeviceConfigRefreshRateInZoneChanged(
- refreshRateInZone);
- break;
-
case MSG_REFRESH_RATE_RANGE_CHANGED:
DesiredDisplayModeSpecsListener desiredDisplayModeSpecsListener =
(DesiredDisplayModeSpecsListener) msg.obj;
@@ -685,10 +743,11 @@
// by all other considerations. It acts to set a default frame rate for a device.
public static final int PRIORITY_DEFAULT_REFRESH_RATE = 0;
- // LOW_BRIGHTNESS votes for a single refresh rate like [60,60], [90,90] or null.
+ // FLICKER votes for a single refresh rate like [60,60], [90,90] or null.
// If the higher voters result is a range, it will fix the rate to a single choice.
- // It's used to avoid rate switch in certain conditions.
- public static final int PRIORITY_LOW_BRIGHTNESS = 1;
+ // It's used to avoid refresh rate switches in certain conditions which may result in the
+ // user seeing the display flickering when the switches occur.
+ public static final int PRIORITY_FLICKER = 1;
// SETTING_MIN_REFRESH_RATE is used to propose a lower bound of display refresh rate.
// It votes [MIN_REFRESH_RATE, Float.POSITIVE_INFINITY]
@@ -761,8 +820,8 @@
switch (priority) {
case PRIORITY_DEFAULT_REFRESH_RATE:
return "PRIORITY_DEFAULT_REFRESH_RATE";
- case PRIORITY_LOW_BRIGHTNESS:
- return "PRIORITY_LOW_BRIGHTNESS";
+ case PRIORITY_FLICKER:
+ return "PRIORITY_FLICKER";
case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE";
case PRIORITY_APP_REQUEST_REFRESH_RATE:
@@ -787,7 +846,8 @@
}
}
- private final class SettingsObserver extends ContentObserver {
+ @VisibleForTesting
+ final class SettingsObserver extends ContentObserver {
private final Uri mPeakRefreshRateSetting =
Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
private final Uri mMinRefreshRateSetting =
@@ -810,8 +870,7 @@
public void observe() {
final ContentResolver cr = mContext.getContentResolver();
- cr.registerContentObserver(mPeakRefreshRateSetting, false /*notifyDescendants*/, this,
- UserHandle.USER_SYSTEM);
+ mInjector.registerPeakRefreshRateObserver(cr, this);
cr.registerContentObserver(mMinRefreshRateSetting, false /*notifyDescendants*/, this,
UserHandle.USER_SYSTEM);
cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this,
@@ -829,6 +888,13 @@
}
}
+ public void setDefaultRefreshRate(float refreshRate) {
+ synchronized (mLock) {
+ mDefaultRefreshRate = refreshRate;
+ updateRefreshRateSettingLocked();
+ }
+ }
+
public void onDeviceConfigDefaultPeakRefreshRateChanged(Float defaultPeakRefreshRate) {
if (defaultPeakRefreshRate == null) {
defaultPeakRefreshRate = (float) mContext.getResources().getInteger(
@@ -1033,6 +1099,7 @@
@Override
public void onDisplayChanged(int displayId) {
updateDisplayModes(displayId);
+ // TODO: Break the coupling between DisplayObserver and BrightnessObserver.
mBrightnessObserver.onDisplayChanged(displayId);
}
@@ -1071,15 +1138,16 @@
*/
@VisibleForTesting
public class BrightnessObserver extends ContentObserver {
- // TODO: brightnessfloat: change this to the float setting
- private final Uri mDisplayBrightnessSetting =
- Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
private final static int LIGHT_SENSOR_RATE_MS = 250;
- private int[] mDisplayBrightnessThresholds;
- private int[] mAmbientBrightnessThresholds;
+ private int[] mLowDisplayBrightnessThresholds;
+ private int[] mLowAmbientBrightnessThresholds;
+ private int[] mHighDisplayBrightnessThresholds;
+ private int[] mHighAmbientBrightnessThresholds;
// valid threshold if any item from the array >= 0
- private boolean mShouldObserveDisplayChange;
- private boolean mShouldObserveAmbientChange;
+ private boolean mShouldObserveDisplayLowChange;
+ private boolean mShouldObserveAmbientLowChange;
+ private boolean mShouldObserveDisplayHighChange;
+ private boolean mShouldObserveAmbientHighChange;
private SensorManager mSensorManager;
private Sensor mLightSensor;
@@ -1087,46 +1155,123 @@
// Take it as low brightness before valid sensor data comes
private float mAmbientLux = -1.0f;
private AmbientFilter mAmbientFilter;
+ private int mBrightness = -1;
private final Context mContext;
- // Enable light sensor only when mShouldObserveAmbientChange is true, screen is on, peak
- // refresh rate changeable and low power mode off. After initialization, these states will
+ // Enable light sensor only when mShouldObserveAmbientLowChange is true or
+ // mShouldObserveAmbientHighChange is true, screen is on, peak refresh rate
+ // changeable and low power mode off. After initialization, these states will
// be updated from the same handler thread.
- private boolean mScreenOn = false;
+ private int mDefaultDisplayState = Display.STATE_UNKNOWN;
+ private boolean mIsDeviceActive = false;
private boolean mRefreshRateChangeable = false;
private boolean mLowPowerModeEnabled = false;
- private int mRefreshRateInZone;
+ private int mRefreshRateInLowZone;
+ private int mRefreshRateInHighZone;
BrightnessObserver(Context context, Handler handler) {
super(handler);
mContext = context;
- mDisplayBrightnessThresholds = context.getResources().getIntArray(
+ mLowDisplayBrightnessThresholds = context.getResources().getIntArray(
R.array.config_brightnessThresholdsOfPeakRefreshRate);
- mAmbientBrightnessThresholds = context.getResources().getIntArray(
+ mLowAmbientBrightnessThresholds = context.getResources().getIntArray(
R.array.config_ambientThresholdsOfPeakRefreshRate);
- if (mDisplayBrightnessThresholds.length != mAmbientBrightnessThresholds.length) {
- throw new RuntimeException("display brightness threshold array and ambient "
- + "brightness threshold array have different length");
+ if (mLowDisplayBrightnessThresholds.length != mLowAmbientBrightnessThresholds.length) {
+ throw new RuntimeException("display low brightness threshold array and ambient "
+ + "brightness threshold array have different length: "
+ + "displayBrightnessThresholds="
+ + Arrays.toString(mLowDisplayBrightnessThresholds)
+ + ", ambientBrightnessThresholds="
+ + Arrays.toString(mLowAmbientBrightnessThresholds));
}
+
+ mHighDisplayBrightnessThresholds = context.getResources().getIntArray(
+ R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate);
+ mHighAmbientBrightnessThresholds = context.getResources().getIntArray(
+ R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate);
+ if (mHighDisplayBrightnessThresholds.length
+ != mHighAmbientBrightnessThresholds.length) {
+ throw new RuntimeException("display high brightness threshold array and ambient "
+ + "brightness threshold array have different length: "
+ + "displayBrightnessThresholds="
+ + Arrays.toString(mHighDisplayBrightnessThresholds)
+ + ", ambientBrightnessThresholds="
+ + Arrays.toString(mHighAmbientBrightnessThresholds));
+ }
+ mRefreshRateInHighZone = context.getResources().getInteger(
+ R.integer.config_fixedRefreshRateInHighZone);
+ }
+
+ /**
+ * @return the refresh to lock to when in a low brightness zone
+ */
+ @VisibleForTesting
+ int getRefreshRateInLowZone() {
+ return mRefreshRateInLowZone;
+ }
+
+ /**
+ * @return the display brightness thresholds for the low brightness zones
+ */
+ @VisibleForTesting
+ int[] getLowDisplayBrightnessThresholds() {
+ return mLowDisplayBrightnessThresholds;
+ }
+
+ /**
+ * @return the ambient brightness thresholds for the low brightness zones
+ */
+ @VisibleForTesting
+ int[] getLowAmbientBrightnessThresholds() {
+ return mLowAmbientBrightnessThresholds;
+ }
+
+ public void registerLightSensor(SensorManager sensorManager, Sensor lightSensor) {
+ mSensorManager = sensorManager;
+ mLightSensor = lightSensor;
+
+ mSensorManager.registerListener(mLightSensorListener,
+ mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
}
public void observe(SensorManager sensorManager) {
mSensorManager = sensorManager;
+ final ContentResolver cr = mContext.getContentResolver();
+ mBrightness = Settings.System.getIntForUser(cr,
+ Settings.System.SCREEN_BRIGHTNESS, -1 /*default*/, cr.getUserId());
// DeviceConfig is accessible after system ready.
- int[] brightnessThresholds = mDeviceConfigDisplaySettings.getBrightnessThresholds();
- int[] ambientThresholds = mDeviceConfigDisplaySettings.getAmbientThresholds();
+ int[] lowDisplayBrightnessThresholds =
+ mDeviceConfigDisplaySettings.getLowDisplayBrightnessThresholds();
+ int[] lowAmbientBrightnessThresholds =
+ mDeviceConfigDisplaySettings.getLowAmbientBrightnessThresholds();
- if (brightnessThresholds != null && ambientThresholds != null
- && brightnessThresholds.length == ambientThresholds.length) {
- mDisplayBrightnessThresholds = brightnessThresholds;
- mAmbientBrightnessThresholds = ambientThresholds;
+ if (lowDisplayBrightnessThresholds != null && lowAmbientBrightnessThresholds != null
+ && lowDisplayBrightnessThresholds.length
+ == lowAmbientBrightnessThresholds.length) {
+ mLowDisplayBrightnessThresholds = lowDisplayBrightnessThresholds;
+ mLowAmbientBrightnessThresholds = lowAmbientBrightnessThresholds;
}
- mRefreshRateInZone = mDeviceConfigDisplaySettings.getRefreshRateInZone();
+
+ int[] highDisplayBrightnessThresholds =
+ mDeviceConfigDisplaySettings.getHighDisplayBrightnessThresholds();
+ int[] highAmbientBrightnessThresholds =
+ mDeviceConfigDisplaySettings.getHighAmbientBrightnessThresholds();
+
+ if (highDisplayBrightnessThresholds != null && highAmbientBrightnessThresholds != null
+ && highDisplayBrightnessThresholds.length
+ == highAmbientBrightnessThresholds.length) {
+ mHighDisplayBrightnessThresholds = highDisplayBrightnessThresholds;
+ mHighAmbientBrightnessThresholds = highAmbientBrightnessThresholds;
+ }
+
+ mRefreshRateInLowZone = mDeviceConfigDisplaySettings.getRefreshRateInLowZone();
+ mRefreshRateInHighZone = mDeviceConfigDisplaySettings.getRefreshRateInHighZone();
+
restartObserver();
mDeviceConfigDisplaySettings.startListening();
}
@@ -1138,7 +1283,7 @@
updateSensorStatus();
if (!changeable) {
// Revoke previous vote from BrightnessObserver
- updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, null);
+ updateVoteLocked(Vote.PRIORITY_FLICKER, null);
}
}
}
@@ -1150,25 +1295,48 @@
}
}
- public void onDeviceConfigThresholdsChanged(int[] brightnessThresholds,
+ public void onDeviceConfigLowBrightnessThresholdsChanged(int[] displayThresholds,
int[] ambientThresholds) {
- if (brightnessThresholds != null && ambientThresholds != null
- && brightnessThresholds.length == ambientThresholds.length) {
- mDisplayBrightnessThresholds = brightnessThresholds;
- mAmbientBrightnessThresholds = ambientThresholds;
+ if (displayThresholds != null && ambientThresholds != null
+ && displayThresholds.length == ambientThresholds.length) {
+ mLowDisplayBrightnessThresholds = displayThresholds;
+ mLowAmbientBrightnessThresholds = ambientThresholds;
} else {
// Invalid or empty. Use device default.
- mDisplayBrightnessThresholds = mContext.getResources().getIntArray(
+ mLowDisplayBrightnessThresholds = mContext.getResources().getIntArray(
R.array.config_brightnessThresholdsOfPeakRefreshRate);
- mAmbientBrightnessThresholds = mContext.getResources().getIntArray(
+ mLowAmbientBrightnessThresholds = mContext.getResources().getIntArray(
R.array.config_ambientThresholdsOfPeakRefreshRate);
}
restartObserver();
}
- public void onDeviceConfigRefreshRateInZoneChanged(int refreshRate) {
- if (refreshRate != mRefreshRateInZone) {
- mRefreshRateInZone = refreshRate;
+ public void onDeviceConfigRefreshRateInLowZoneChanged(int refreshRate) {
+ if (refreshRate != mRefreshRateInLowZone) {
+ mRefreshRateInLowZone = refreshRate;
+ restartObserver();
+ }
+ }
+
+ public void onDeviceConfigHighBrightnessThresholdsChanged(int[] displayThresholds,
+ int[] ambientThresholds) {
+ if (displayThresholds != null && ambientThresholds != null
+ && displayThresholds.length == ambientThresholds.length) {
+ mHighDisplayBrightnessThresholds = displayThresholds;
+ mHighAmbientBrightnessThresholds = ambientThresholds;
+ } else {
+ // Invalid or empty. Use device default.
+ mHighDisplayBrightnessThresholds = mContext.getResources().getIntArray(
+ R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate);
+ mHighAmbientBrightnessThresholds = mContext.getResources().getIntArray(
+ R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate);
+ }
+ restartObserver();
+ }
+
+ public void onDeviceConfigRefreshRateInHighZoneChanged(int refreshRate) {
+ if (refreshRate != mRefreshRateInHighZone) {
+ mRefreshRateInHighZone = refreshRate;
restartObserver();
}
}
@@ -1176,48 +1344,96 @@
public void dumpLocked(PrintWriter pw) {
pw.println(" BrightnessObserver");
pw.println(" mAmbientLux: " + mAmbientLux);
- pw.println(" mRefreshRateInZone: " + mRefreshRateInZone);
+ pw.println(" mBrightness: " + mBrightness);
+ pw.println(" mDefaultDisplayState: " + mDefaultDisplayState);
+ pw.println(" mIsDeviceActive: " + mIsDeviceActive);
+ pw.println(" mLowPowerModeEnabled: " + mLowPowerModeEnabled);
+ pw.println(" mRefreshRateChangeable: " + mRefreshRateChangeable);
+ pw.println(" mShouldObserveDisplayLowChange: " + mShouldObserveDisplayLowChange);
+ pw.println(" mShouldObserveAmbientLowChange: " + mShouldObserveAmbientLowChange);
+ pw.println(" mRefreshRateInLowZone: " + mRefreshRateInLowZone);
- for (int d: mDisplayBrightnessThresholds) {
- pw.println(" mDisplayBrightnessThreshold: " + d);
+ for (int d : mLowDisplayBrightnessThresholds) {
+ pw.println(" mDisplayLowBrightnessThreshold: " + d);
}
- for (int d: mAmbientBrightnessThresholds) {
- pw.println(" mAmbientBrightnessThreshold: " + d);
+ for (int d : mLowAmbientBrightnessThresholds) {
+ pw.println(" mAmbientLowBrightnessThreshold: " + d);
+ }
+
+ pw.println(" mShouldObserveDisplayHighChange: " + mShouldObserveDisplayHighChange);
+ pw.println(" mShouldObserveAmbientHighChange: " + mShouldObserveAmbientHighChange);
+ pw.println(" mRefreshRateInHighZone: " + mRefreshRateInHighZone);
+
+ for (int d : mHighDisplayBrightnessThresholds) {
+ pw.println(" mDisplayHighBrightnessThresholds: " + d);
+ }
+
+ for (int d : mHighAmbientBrightnessThresholds) {
+ pw.println(" mAmbientHighBrightnessThresholds: " + d);
}
mLightSensorListener.dumpLocked(pw);
+
+ if (mAmbientFilter != null) {
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ ipw.setIndent(" ");
+ mAmbientFilter.dump(ipw);
+ }
}
public void onDisplayChanged(int displayId) {
if (displayId == Display.DEFAULT_DISPLAY) {
- onScreenOn(isDefaultDisplayOn());
+ updateDefaultDisplayState();
}
}
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
synchronized (mLock) {
- onBrightnessChangedLocked();
+ final ContentResolver cr = mContext.getContentResolver();
+ int brightness = Settings.System.getIntForUser(cr,
+ Settings.System.SCREEN_BRIGHTNESS, -1 /*default*/, cr.getUserId());
+ if (brightness != mBrightness) {
+ mBrightness = brightness;
+ onBrightnessChangedLocked();
+ }
}
}
private void restartObserver() {
- mShouldObserveDisplayChange = checkShouldObserve(mDisplayBrightnessThresholds);
- mShouldObserveAmbientChange = checkShouldObserve(mAmbientBrightnessThresholds);
-
final ContentResolver cr = mContext.getContentResolver();
- if (mShouldObserveDisplayChange) {
- // Content Service does not check if an listener has already been registered.
- // To ensure only one listener is registered, force an unregistration first.
- cr.unregisterContentObserver(this);
- cr.registerContentObserver(mDisplayBrightnessSetting,
- false /*notifyDescendants*/, this, UserHandle.USER_SYSTEM);
+
+ if (mRefreshRateInLowZone > 0) {
+ mShouldObserveDisplayLowChange = hasValidThreshold(
+ mLowDisplayBrightnessThresholds);
+ mShouldObserveAmbientLowChange = hasValidThreshold(
+ mLowAmbientBrightnessThresholds);
} else {
- cr.unregisterContentObserver(this);
+ mShouldObserveDisplayLowChange = false;
+ mShouldObserveAmbientLowChange = false;
}
- if (mShouldObserveAmbientChange) {
+ if (mRefreshRateInHighZone > 0) {
+ mShouldObserveDisplayHighChange = hasValidThreshold(
+ mHighDisplayBrightnessThresholds);
+ mShouldObserveAmbientHighChange = hasValidThreshold(
+ mHighAmbientBrightnessThresholds);
+ } else {
+ mShouldObserveDisplayHighChange = false;
+ mShouldObserveAmbientHighChange = false;
+ }
+
+ if (mShouldObserveDisplayLowChange || mShouldObserveDisplayHighChange) {
+ // Content Service does not check if an listener has already been registered.
+ // To ensure only one listener is registered, force an unregistration first.
+ mInjector.unregisterBrightnessObserver(cr, this);
+ mInjector.registerBrightnessObserver(cr, this);
+ } else {
+ mInjector.unregisterBrightnessObserver(cr, this);
+ }
+
+ if (mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange) {
Resources resources = mContext.getResources();
String lightSensorType = resources.getString(
com.android.internal.R.string.config_displayLightSensorType);
@@ -1243,8 +1459,6 @@
mAmbientFilter = AmbientFilterFactory.createBrightnessFilter(TAG, res);
mLightSensor = lightSensor;
-
- onScreenOn(isDefaultDisplayOn());
}
} else {
mAmbientFilter = null;
@@ -1263,11 +1477,7 @@
* Checks to see if at least one value is positive, in which case it is necessary to listen
* to value changes.
*/
- private boolean checkShouldObserve(int[] a) {
- if (mRefreshRateInZone <= 0) {
- return false;
- }
-
+ private boolean hasValidThreshold(int[] a) {
for (int d: a) {
if (d >= 0) {
return true;
@@ -1277,13 +1487,13 @@
return false;
}
- private boolean isInsideZone(int brightness, float lux) {
- for (int i = 0; i < mDisplayBrightnessThresholds.length; i++) {
- int disp = mDisplayBrightnessThresholds[i];
- int ambi = mAmbientBrightnessThresholds[i];
+ private boolean isInsideLowZone(int brightness, float lux) {
+ for (int i = 0; i < mLowDisplayBrightnessThresholds.length; i++) {
+ int disp = mLowDisplayBrightnessThresholds[i];
+ int ambi = mLowAmbientBrightnessThresholds[i];
if (disp >= 0 && ambi >= 0) {
- if (brightness <= disp && mAmbientLux <= ambi) {
+ if (brightness <= disp && lux <= ambi) {
return true;
}
} else if (disp >= 0) {
@@ -1291,7 +1501,7 @@
return true;
}
} else if (ambi >= 0) {
- if (mAmbientLux <= ambi) {
+ if (lux <= ambi) {
return true;
}
}
@@ -1299,27 +1509,80 @@
return false;
}
- // TODO: brightnessfloat: make it use float not int
- private void onBrightnessChangedLocked() {
- int brightness = Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS, -1);
+ private boolean isInsideHighZone(int brightness, float lux) {
+ for (int i = 0; i < mHighDisplayBrightnessThresholds.length; i++) {
+ int disp = mHighDisplayBrightnessThresholds[i];
+ int ambi = mHighAmbientBrightnessThresholds[i];
+
+ if (disp >= 0 && ambi >= 0) {
+ if (brightness >= disp && lux >= ambi) {
+ return true;
+ }
+ } else if (disp >= 0) {
+ if (brightness >= disp) {
+ return true;
+ }
+ } else if (ambi >= 0) {
+ if (lux >= ambi) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+ private void onBrightnessChangedLocked() {
Vote vote = null;
- boolean insideZone = isInsideZone(brightness, mAmbientLux);
- if (insideZone) {
- vote = Vote.forRefreshRates(mRefreshRateInZone, mRefreshRateInZone);
+
+ if (mBrightness < 0) {
+ // Either the setting isn't available or we shouldn't be observing yet anyways.
+ // Either way, just bail out since there's nothing we can do here.
+ return;
+ }
+
+ boolean insideLowZone = hasValidLowZone() && isInsideLowZone(mBrightness, mAmbientLux);
+ if (insideLowZone) {
+ vote = Vote.forRefreshRates(mRefreshRateInLowZone, mRefreshRateInLowZone);
+ }
+
+ boolean insideHighZone = hasValidHighZone()
+ && isInsideHighZone(mBrightness, mAmbientLux);
+ if (insideHighZone) {
+ vote = Vote.forRefreshRates(mRefreshRateInHighZone, mRefreshRateInHighZone);
}
if (DEBUG) {
- Slog.d(TAG, "Display brightness " + brightness + ", ambient lux " + mAmbientLux +
- ", Vote " + vote);
+ Slog.d(TAG, "Display brightness " + mBrightness + ", ambient lux " + mAmbientLux
+ + ", Vote " + vote);
}
- updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, vote);
+ updateVoteLocked(Vote.PRIORITY_FLICKER, vote);
}
- private void onScreenOn(boolean on) {
- if (mScreenOn != on) {
- mScreenOn = on;
+ private boolean hasValidLowZone() {
+ return mRefreshRateInLowZone > 0
+ && (mShouldObserveDisplayLowChange || mShouldObserveAmbientLowChange);
+ }
+
+ private boolean hasValidHighZone() {
+ return mRefreshRateInHighZone > 0
+ && (mShouldObserveDisplayHighChange || mShouldObserveAmbientHighChange);
+ }
+
+ private void updateDefaultDisplayState() {
+ Display display = mContext.getSystemService(DisplayManager.class)
+ .getDisplay(Display.DEFAULT_DISPLAY);
+ if (display == null) {
+ return;
+ }
+
+ setDefaultDisplayState(display.getState());
+ }
+
+ @VisibleForTesting
+ public void setDefaultDisplayState(int state) {
+ if (mDefaultDisplayState != state) {
+ mDefaultDisplayState = state;
updateSensorStatus();
}
}
@@ -1329,8 +1592,8 @@
return;
}
- if (mShouldObserveAmbientChange && mScreenOn && !mLowPowerModeEnabled
- && mRefreshRateChangeable) {
+ if ((mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange)
+ && isDeviceActive() && !mLowPowerModeEnabled && mRefreshRateChangeable) {
mSensorManager.registerListener(mLightSensorListener,
mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
} else {
@@ -1339,19 +1602,20 @@
}
}
- private boolean isDefaultDisplayOn() {
- final Display display = mContext.getSystemService(DisplayManager.class)
- .getDisplay(Display.DEFAULT_DISPLAY);
- return display.getState() != Display.STATE_OFF
- && mContext.getSystemService(PowerManager.class).isInteractive();
+ private boolean isDeviceActive() {
+ mIsDeviceActive = mInjector.isDeviceInteractive(mContext);
+ return (mDefaultDisplayState == Display.STATE_ON)
+ && mIsDeviceActive;
}
private final class LightSensorEventListener implements SensorEventListener {
final private static int INJECT_EVENTS_INTERVAL_MS = LIGHT_SENSOR_RATE_MS;
private float mLastSensorData;
+ private long mTimestamp;
public void dumpLocked(PrintWriter pw) {
pw.println(" mLastSensorData: " + mLastSensorData);
+ pw.println(" mTimestamp: " + formatTimestamp(mTimestamp));
}
@Override
@@ -1361,23 +1625,34 @@
Slog.d(TAG, "On sensor changed: " + mLastSensorData);
}
- boolean zoneChanged = isDifferentZone(mLastSensorData, mAmbientLux);
- if (zoneChanged && mLastSensorData < mAmbientLux) {
- // Easier to see flicker at lower brightness environment. Forget the history to
- // get immediate response.
- mAmbientFilter.clear();
+ boolean lowZoneChanged = isDifferentZone(mLastSensorData, mAmbientLux,
+ mLowAmbientBrightnessThresholds);
+ boolean highZoneChanged = isDifferentZone(mLastSensorData, mAmbientLux,
+ mHighAmbientBrightnessThresholds);
+ if ((lowZoneChanged && mLastSensorData < mAmbientLux)
+ || (highZoneChanged && mLastSensorData > mAmbientLux)) {
+ // Easier to see flicker at lower brightness environment or high brightness
+ // environment. Forget the history to get immediate response.
+ if (mAmbientFilter != null) {
+ mAmbientFilter.clear();
+ }
}
long now = SystemClock.uptimeMillis();
- mAmbientFilter.addValue(now, mLastSensorData);
+ mTimestamp = System.currentTimeMillis();
+ if (mAmbientFilter != null) {
+ mAmbientFilter.addValue(now, mLastSensorData);
+ }
mHandler.removeCallbacks(mInjectSensorEventRunnable);
processSensorData(now);
- if (zoneChanged && mLastSensorData > mAmbientLux) {
+ if ((lowZoneChanged && mLastSensorData > mAmbientLux)
+ || (highZoneChanged && mLastSensorData < mAmbientLux)) {
// Sensor may not report new event if there is no brightness change.
// Need to keep querying the temporal filter for the latest estimation,
- // until enter in higher lux zone or is interrupted by a new sensor event.
+ // until sensor readout and filter estimation are in the same zone or
+ // is interrupted by a new sensor event.
mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS);
}
}
@@ -1391,18 +1666,26 @@
mHandler.removeCallbacks(mInjectSensorEventRunnable);
}
+ private String formatTimestamp(long time) {
+ SimpleDateFormat dateFormat =
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
+ return dateFormat.format(new Date(time));
+ }
+
private void processSensorData(long now) {
- mAmbientLux = mAmbientFilter.getEstimate(now);
+ if (mAmbientFilter != null) {
+ mAmbientLux = mAmbientFilter.getEstimate(now);
+ } else {
+ mAmbientLux = mLastSensorData;
+ }
synchronized (mLock) {
onBrightnessChangedLocked();
}
}
- private boolean isDifferentZone(float lux1, float lux2) {
- for (int z = 0; z < mAmbientBrightnessThresholds.length; z++) {
- final float boundary = mAmbientBrightnessThresholds[z];
-
+ private boolean isDifferentZone(float lux1, float lux2, int[] luxThresholds) {
+ for (final float boundary : luxThresholds) {
// Test each boundary. See if the current value and the new value are at
// different sides.
if ((lux1 <= boundary && lux2 > boundary)
@@ -1422,7 +1705,10 @@
processSensorData(now);
// Inject next event if there is a possible zone change.
- if (isDifferentZone(mLastSensorData, mAmbientLux)) {
+ if (isDifferentZone(mLastSensorData, mAmbientLux,
+ mLowAmbientBrightnessThresholds)
+ || isDifferentZone(mLastSensorData, mAmbientLux,
+ mHighAmbientBrightnessThresholds)) {
mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS);
}
}
@@ -1435,33 +1721,75 @@
}
public void startListening() {
- DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
BackgroundThread.getExecutor(), this);
}
/*
* Return null if no such property or wrong format (not comma separated integers).
*/
- public int[] getBrightnessThresholds() {
+ public int[] getLowDisplayBrightnessThresholds() {
return getIntArrayProperty(
DisplayManager.DeviceConfig.
- KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS);
+ KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS);
}
/*
* Return null if no such property or wrong format (not comma separated integers).
*/
- public int[] getAmbientThresholds() {
+ public int[] getLowAmbientBrightnessThresholds() {
return getIntArrayProperty(
DisplayManager.DeviceConfig.
- KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS);
+ KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS);
+ }
+
+ public int getRefreshRateInLowZone() {
+ int defaultRefreshRateInZone = mContext.getResources().getInteger(
+ R.integer.config_defaultRefreshRateInZone);
+
+ int refreshRate = mDeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE,
+ defaultRefreshRateInZone);
+
+ return refreshRate;
+ }
+
+ /*
+ * Return null if no such property or wrong format (not comma separated integers).
+ */
+ public int[] getHighDisplayBrightnessThresholds() {
+ return getIntArrayProperty(
+ DisplayManager.DeviceConfig
+ .KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS);
+ }
+
+ /*
+ * Return null if no such property or wrong format (not comma separated integers).
+ */
+ public int[] getHighAmbientBrightnessThresholds() {
+ return getIntArrayProperty(
+ DisplayManager.DeviceConfig
+ .KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS);
+ }
+
+ public int getRefreshRateInHighZone() {
+ int defaultRefreshRateInZone = mContext.getResources().getInteger(
+ R.integer.config_fixedRefreshRateInHighZone);
+
+ int refreshRate = mDeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE,
+ defaultRefreshRateInZone);
+
+ return refreshRate;
}
/*
* Return null if no such property
*/
public Float getDefaultPeakRefreshRate() {
- float defaultPeakRefreshRate = DeviceConfig.getFloat(
+ float defaultPeakRefreshRate = mDeviceConfig.getFloat(
DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_DEFAULT, -1);
@@ -1471,36 +1799,35 @@
return defaultPeakRefreshRate;
}
- public int getRefreshRateInZone() {
- int defaultRefreshRateInZone = mContext.getResources().getInteger(
- R.integer.config_defaultRefreshRateInZone);
-
- int refreshRate = DeviceConfig.getInt(
- DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
- DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_ZONE,
- defaultRefreshRateInZone);
-
- return refreshRate;
- }
-
@Override
public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
- int[] brightnessThresholds = getBrightnessThresholds();
- int[] ambientThresholds = getAmbientThresholds();
Float defaultPeakRefreshRate = getDefaultPeakRefreshRate();
- int refreshRateInZone = getRefreshRateInZone();
-
- mHandler.obtainMessage(MSG_BRIGHTNESS_THRESHOLDS_CHANGED,
- new Pair<int[], int[]>(brightnessThresholds, ambientThresholds))
- .sendToTarget();
mHandler.obtainMessage(MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED,
defaultPeakRefreshRate).sendToTarget();
- mHandler.obtainMessage(MSG_REFRESH_RATE_IN_ZONE_CHANGED, refreshRateInZone,
- 0).sendToTarget();
+
+ int[] lowDisplayBrightnessThresholds = getLowDisplayBrightnessThresholds();
+ int[] lowAmbientBrightnessThresholds = getLowAmbientBrightnessThresholds();
+ int refreshRateInLowZone = getRefreshRateInLowZone();
+
+ mHandler.obtainMessage(MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED,
+ new Pair<>(lowDisplayBrightnessThresholds, lowAmbientBrightnessThresholds))
+ .sendToTarget();
+ mHandler.obtainMessage(MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED, refreshRateInLowZone, 0)
+ .sendToTarget();
+
+ int[] highDisplayBrightnessThresholds = getHighDisplayBrightnessThresholds();
+ int[] highAmbientBrightnessThresholds = getHighAmbientBrightnessThresholds();
+ int refreshRateInHighZone = getRefreshRateInHighZone();
+
+ mHandler.obtainMessage(MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED,
+ new Pair<>(highDisplayBrightnessThresholds, highAmbientBrightnessThresholds))
+ .sendToTarget();
+ mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED, refreshRateInHighZone, 0)
+ .sendToTarget();
}
private int[] getIntArrayProperty(String prop) {
- String strArray = DeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, prop,
+ String strArray = mDeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, prop,
null);
if (strArray != null) {
@@ -1527,4 +1854,59 @@
}
}
+ interface Injector {
+ // TODO: brightnessfloat: change this to the float setting
+ Uri DISPLAY_BRIGHTNESS_URI = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
+ Uri PEAK_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
+
+ @NonNull
+ DeviceConfigInterface getDeviceConfig();
+
+ void registerBrightnessObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer);
+
+ void unregisterBrightnessObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer);
+
+ void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer);
+
+ boolean isDeviceInteractive(@NonNull Context context);
+ }
+
+ @VisibleForTesting
+ static class RealInjector implements Injector {
+
+ @Override
+ @NonNull
+ public DeviceConfigInterface getDeviceConfig() {
+ return DeviceConfigInterface.REAL;
+ }
+
+ @Override
+ public void registerBrightnessObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer) {
+ cr.registerContentObserver(DISPLAY_BRIGHTNESS_URI, false /*notifyDescendants*/,
+ observer, UserHandle.USER_SYSTEM);
+ }
+
+ @Override
+ public void unregisterBrightnessObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer) {
+ cr.unregisterContentObserver(observer);
+ }
+
+ @Override
+ public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer) {
+ cr.registerContentObserver(PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/,
+ observer, UserHandle.USER_SYSTEM);
+ }
+
+ @Override
+ public boolean isDeviceInteractive(@NonNull Context ctx) {
+ return ctx.getSystemService(PowerManager.class).isInteractive();
+ }
+ }
+
}
diff --git a/services/core/java/com/android/server/wm/utils/DeviceConfigInterface.java b/services/core/java/com/android/server/utils/DeviceConfigInterface.java
similarity index 90%
rename from services/core/java/com/android/server/wm/utils/DeviceConfigInterface.java
rename to services/core/java/com/android/server/utils/DeviceConfigInterface.java
index ab7e7f6..ff60903 100644
--- a/services/core/java/com/android/server/wm/utils/DeviceConfigInterface.java
+++ b/services/core/java/com/android/server/utils/DeviceConfigInterface.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.utils;
+package com.android.server.utils;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -54,6 +54,11 @@
boolean getBoolean(@NonNull String namespace, @NonNull String name, boolean defaultValue);
/**
+ * @see DeviceConfig#getFloat
+ */
+ float getFloat(@NonNull String namespace, @NonNull String name, float defaultValue);
+
+ /**
* @see DeviceConfig#addOnPropertiesChangedListener
*/
void addOnPropertiesChangedListener(@NonNull String namespace, @NonNull Executor executor,
@@ -96,6 +101,12 @@
}
@Override
+ public float getFloat(@NonNull String namespace, @NonNull String name,
+ float defaultValue) {
+ return DeviceConfig.getFloat(namespace, name, defaultValue);
+ }
+
+ @Override
public void addOnPropertiesChangedListener(String namespace, Executor executor,
DeviceConfig.OnPropertiesChangedListener listener) {
DeviceConfig.addOnPropertiesChangedListener(namespace, executor, listener);
diff --git a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java
index d9cf637..09ab004 100644
--- a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java
+++ b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java
@@ -27,7 +27,7 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
-import com.android.server.wm.utils.DeviceConfigInterface;
+import com.android.server.utils.DeviceConfigInterface;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/WindowManagerConstants.java b/services/core/java/com/android/server/wm/WindowManagerConstants.java
index b0c5dbc..a5ebf9a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerConstants.java
+++ b/services/core/java/com/android/server/wm/WindowManagerConstants.java
@@ -23,7 +23,7 @@
import android.provider.DeviceConfig;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.wm.utils.DeviceConfigInterface;
+import com.android.server.utils.DeviceConfigInterface;
import java.io.PrintWriter;
import java.util.Objects;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b7a2eb3..d9594a4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -282,8 +282,8 @@
import com.android.server.power.ShutdownThread;
import com.android.server.protolog.ProtoLogImpl;
import com.android.server.protolog.common.ProtoLog;
+import com.android.server.utils.DeviceConfigInterface;
import com.android.server.utils.PriorityDump;
-import com.android.server.wm.utils.DeviceConfigInterface;
import java.io.BufferedWriter;
import java.io.DataInputStream;
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 979f4e1..e57097e 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -48,7 +48,6 @@
// TODO: remove once Android migrates to JUnit 4.12,
// which provides assertThrows
"testng",
-
],
aidl: {
@@ -110,6 +109,7 @@
"utils/**/*.java",
"utils/**/*.kt",
"utils-mockito/**/*.kt",
+ ":services.core-sources-deviceconfig-interface",
],
static_libs: [
"junit",
@@ -126,6 +126,7 @@
"utils/**/*.java",
"utils/**/*.kt",
"utils-mockito/**/*.kt",
+ ":services.core-sources-deviceconfig-interface",
],
static_libs: [
"junit",
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index 43a396d..e202145 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -16,49 +16,100 @@
package com.android.server.display;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.verify;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE;
+import static com.android.server.display.DisplayModeDirector.Vote.PRIORITY_FLICKER;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.internal.verification.VerificationModeFactory.times;
+
+import android.annotation.NonNull;
+import android.content.ContentResolver;
import android.content.Context;
+import android.content.ContextWrapper;
+import android.database.ContentObserver;
+import android.hardware.Sensor;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
import android.os.Handler;
import android.os.Looper;
+import android.provider.DeviceConfig;
+import android.provider.Settings;
+import android.test.mock.MockContentResolver;
+import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.util.Preconditions;
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.internal.util.test.FakeSettingsProviderRule;
import com.android.server.display.DisplayModeDirector.BrightnessObserver;
import com.android.server.display.DisplayModeDirector.DesiredDisplayModeSpecs;
import com.android.server.display.DisplayModeDirector.Vote;
+import com.android.server.testutils.FakeDeviceConfigInterface;
import com.google.common.truth.Truth;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DisplayModeDirectorTest {
// The tolerance within which we consider something approximately equals.
+ private static final String TAG = "DisplayModeDirectorTest";
+ private static final boolean DEBUG = false;
private static final float FLOAT_TOLERANCE = 0.01f;
private Context mContext;
+ private FakesInjector mInjector;
+ private Handler mHandler;
+ @Rule
+ public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
+ final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext);
+ when(mContext.getContentResolver()).thenReturn(resolver);
+ mInjector = new FakesInjector();
+ mHandler = new Handler(Looper.getMainLooper());
}
private DisplayModeDirector createDirectorFromRefreshRateArray(
float[] refreshRates, int baseModeId) {
DisplayModeDirector director =
- new DisplayModeDirector(mContext, new Handler(Looper.getMainLooper()));
+ new DisplayModeDirector(mContext, mHandler, mInjector);
int displayId = 0;
Display.Mode[] modes = new Display.Mode[refreshRates.length];
for (int i = 0; i < refreshRates.length; i++) {
@@ -159,9 +210,9 @@
}
@Test
- public void testBrightnessHasLowerPriorityThanUser() {
- assertTrue(Vote.PRIORITY_LOW_BRIGHTNESS < Vote.PRIORITY_APP_REQUEST_REFRESH_RATE);
- assertTrue(Vote.PRIORITY_LOW_BRIGHTNESS < Vote.PRIORITY_APP_REQUEST_SIZE);
+ public void testFlickerHasLowerPriorityThanUser() {
+ assertTrue(PRIORITY_FLICKER < Vote.PRIORITY_APP_REQUEST_REFRESH_RATE);
+ assertTrue(PRIORITY_FLICKER < Vote.PRIORITY_APP_REQUEST_SIZE);
int displayId = 0;
DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
@@ -169,7 +220,7 @@
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(displayId, votes);
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90));
- votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
+ votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
director.injectVotesByDisplay(votesByDisplay);
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
@@ -177,7 +228,7 @@
votes.clear();
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90));
- votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(90, 90));
+ votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(90, 90));
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
@@ -185,7 +236,7 @@
votes.clear();
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90));
- votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
+ votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
@@ -193,7 +244,7 @@
votes.clear();
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 60));
- votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(90, 90));
+ votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(90, 90));
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
@@ -202,10 +253,10 @@
@Test
public void testAppRequestRefreshRateRange() {
- // Confirm that the app request range doesn't include low brightness or min refresh rate
- // settings, but does include everything else.
+ // Confirm that the app request range doesn't include flicker or min refresh rate settings,
+ // but does include everything else.
assertTrue(
- Vote.PRIORITY_LOW_BRIGHTNESS < Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
+ PRIORITY_FLICKER < Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
assertTrue(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE
< Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
assertTrue(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE
@@ -216,7 +267,7 @@
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(displayId, votes);
- votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
+ votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
director.injectVotesByDisplay(votesByDisplay);
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
@@ -302,4 +353,380 @@
verifyBrightnessObserverCall(director, 90, 90, 0, 90, 90);
verifyBrightnessObserverCall(director, 120, 90, 0, 120, 90);
}
+
+ @Test
+ public void testBrightnessObserverGetsUpdatedRefreshRatesForZone() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0);
+ SensorManager sensorManager = createMockSensorManager(createLightSensor());
+
+ final int initialRefreshRate = 60;
+ mInjector.getDeviceConfig().setRefreshRateInLowZone(initialRefreshRate);
+ director.start(sensorManager);
+ assertThat(director.getBrightnessObserver().getRefreshRateInLowZone())
+ .isEqualTo(initialRefreshRate);
+
+ final int updatedRefreshRate = 90;
+ mInjector.getDeviceConfig().setRefreshRateInLowZone(updatedRefreshRate);
+ // Need to wait for the property change to propagate to the main thread.
+ waitForIdleSync();
+ assertThat(director.getBrightnessObserver().getRefreshRateInLowZone())
+ .isEqualTo(updatedRefreshRate);
+ }
+
+ @Test
+ public void testBrightnessObserverThresholdsInZone() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0);
+ SensorManager sensorManager = createMockSensorManager(createLightSensor());
+
+ final int[] initialDisplayThresholds = { 10 };
+ final int[] initialAmbientThresholds = { 20 };
+
+ final FakeDeviceConfig config = mInjector.getDeviceConfig();
+ config.setLowDisplayBrightnessThresholds(initialDisplayThresholds);
+ config.setLowAmbientBrightnessThresholds(initialAmbientThresholds);
+ director.start(sensorManager);
+
+ assertThat(director.getBrightnessObserver().getLowDisplayBrightnessThresholds())
+ .isEqualTo(initialDisplayThresholds);
+ assertThat(director.getBrightnessObserver().getLowAmbientBrightnessThresholds())
+ .isEqualTo(initialAmbientThresholds);
+
+ final int[] updatedDisplayThresholds = { 9, 14 };
+ final int[] updatedAmbientThresholds = { -1, 19 };
+ config.setLowDisplayBrightnessThresholds(updatedDisplayThresholds);
+ config.setLowAmbientBrightnessThresholds(updatedAmbientThresholds);
+ // Need to wait for the property change to propagate to the main thread.
+ waitForIdleSync();
+ assertThat(director.getBrightnessObserver().getLowDisplayBrightnessThresholds())
+ .isEqualTo(updatedDisplayThresholds);
+ assertThat(director.getBrightnessObserver().getLowAmbientBrightnessThresholds())
+ .isEqualTo(updatedAmbientThresholds);
+ }
+
+ @Test
+ public void testLockFpsForLowZone() throws Exception {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+ setPeakRefreshRate(90);
+ director.getSettingsObserver().setDefaultRefreshRate(90);
+ director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+
+ final FakeDeviceConfig config = mInjector.getDeviceConfig();
+ config.setRefreshRateInLowZone(90);
+ config.setLowDisplayBrightnessThresholds(new int[] { 10 });
+ config.setLowAmbientBrightnessThresholds(new int[] { 20 });
+
+ Sensor lightSensor = createLightSensor();
+ SensorManager sensorManager = createMockSensorManager(lightSensor);
+
+ director.start(sensorManager);
+
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ Mockito.verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1)))
+ .registerListener(
+ listenerCaptor.capture(),
+ eq(lightSensor),
+ anyInt(),
+ any(Handler.class));
+ SensorEventListener listener = listenerCaptor.getValue();
+
+ setBrightness(10);
+ // Sensor reads 20 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 20 /*lux*/));
+
+ Vote vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
+ assertVoteForRefreshRateLocked(vote, 90 /*fps*/);
+
+ setBrightness(125);
+ // Sensor reads 1000 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 1000 /*lux*/));
+
+ vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
+ assertThat(vote).isNull();
+ }
+
+ @Test
+ public void testLockFpsForHighZone() throws Exception {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+ setPeakRefreshRate(90 /*fps*/);
+ director.getSettingsObserver().setDefaultRefreshRate(90);
+ director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+
+ final FakeDeviceConfig config = mInjector.getDeviceConfig();
+ config.setRefreshRateInHighZone(60);
+ config.setHighDisplayBrightnessThresholds(new int[] { 255 });
+ config.setHighAmbientBrightnessThresholds(new int[] { 8000 });
+
+ Sensor lightSensor = createLightSensor();
+ SensorManager sensorManager = createMockSensorManager(lightSensor);
+
+ director.start(sensorManager);
+
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ Mockito.verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1)))
+ .registerListener(
+ listenerCaptor.capture(),
+ eq(lightSensor),
+ anyInt(),
+ any(Handler.class));
+ SensorEventListener listener = listenerCaptor.getValue();
+
+ setBrightness(100);
+ // Sensor reads 2000 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 2000));
+
+ Vote vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
+ assertThat(vote).isNull();
+
+ setBrightness(255);
+ // Sensor reads 9000 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 9000));
+
+ vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
+ assertVoteForRefreshRateLocked(vote, 60 /*fps*/);
+ }
+
+ @Test
+ public void testSensorRegistration() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+ setPeakRefreshRate(90 /*fps*/);
+ director.getSettingsObserver().setDefaultRefreshRate(90);
+ director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+
+ Sensor lightSensor = createLightSensor();
+ SensorManager sensorManager = createMockSensorManager(lightSensor);
+
+ director.start(sensorManager);
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ Mockito.verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1)))
+ .registerListener(
+ listenerCaptor.capture(),
+ eq(lightSensor),
+ anyInt(),
+ any(Handler.class));
+
+ // Dispaly state changed from On to Doze
+ director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_DOZE);
+ Mockito.verify(sensorManager)
+ .unregisterListener(listenerCaptor.capture());
+
+ // Dispaly state changed from Doze to On
+ director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+ Mockito.verify(sensorManager, times(2))
+ .registerListener(
+ listenerCaptor.capture(),
+ eq(lightSensor),
+ anyInt(),
+ any(Handler.class));
+
+ }
+
+ private void assertVoteForRefreshRateLocked(Vote vote, float refreshRate) {
+ assertThat(vote).isNotNull();
+ final DisplayModeDirector.RefreshRateRange expectedRange =
+ new DisplayModeDirector.RefreshRateRange(refreshRate, refreshRate);
+ assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
+ }
+
+ private static class FakeDeviceConfig extends FakeDeviceConfigInterface {
+ @Override
+ public String getProperty(String namespace, String name) {
+ Preconditions.checkArgument(DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace));
+ return super.getProperty(namespace, name);
+ }
+
+ @Override
+ public void addOnPropertiesChangedListener(
+ String namespace,
+ Executor executor,
+ DeviceConfig.OnPropertiesChangedListener listener) {
+ Preconditions.checkArgument(DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace));
+ super.addOnPropertiesChangedListener(namespace, executor, listener);
+ }
+
+ void setRefreshRateInLowZone(int fps) {
+ putPropertyAndNotify(
+ DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_REFRESH_RATE_IN_LOW_ZONE,
+ String.valueOf(fps));
+ }
+
+ void setLowDisplayBrightnessThresholds(int[] brightnessThresholds) {
+ String thresholds = toPropertyValue(brightnessThresholds);
+
+ if (DEBUG) {
+ Slog.e(TAG, "Brightness Thresholds = " + thresholds);
+ }
+
+ putPropertyAndNotify(
+ DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS,
+ thresholds);
+ }
+
+ void setLowAmbientBrightnessThresholds(int[] ambientThresholds) {
+ String thresholds = toPropertyValue(ambientThresholds);
+
+ if (DEBUG) {
+ Slog.e(TAG, "Ambient Thresholds = " + thresholds);
+ }
+
+ putPropertyAndNotify(
+ DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS,
+ thresholds);
+ }
+
+ void setRefreshRateInHighZone(int fps) {
+ putPropertyAndNotify(
+ DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_REFRESH_RATE_IN_HIGH_ZONE,
+ String.valueOf(fps));
+ }
+
+ void setHighDisplayBrightnessThresholds(int[] brightnessThresholds) {
+ String thresholds = toPropertyValue(brightnessThresholds);
+
+ if (DEBUG) {
+ Slog.e(TAG, "Brightness Thresholds = " + thresholds);
+ }
+
+ putPropertyAndNotify(
+ DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS,
+ thresholds);
+ }
+
+ void setHighAmbientBrightnessThresholds(int[] ambientThresholds) {
+ String thresholds = toPropertyValue(ambientThresholds);
+
+ if (DEBUG) {
+ Slog.e(TAG, "Ambient Thresholds = " + thresholds);
+ }
+
+ putPropertyAndNotify(
+ DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS,
+ thresholds);
+ }
+
+ @NonNull
+ private static String toPropertyValue(@NonNull int[] intArray) {
+ return Arrays.stream(intArray)
+ .mapToObj(Integer::toString)
+ .collect(Collectors.joining(","));
+ }
+ }
+
+ private void setBrightness(int brightness) {
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS,
+ brightness);
+ mInjector.notifyBrightnessChanged();
+ waitForIdleSync();
+ }
+
+ private void setPeakRefreshRate(float fps) {
+ Settings.System.putFloat(mContext.getContentResolver(), Settings.System.PEAK_REFRESH_RATE,
+ fps);
+ mInjector.notifyPeakRefreshRateChanged();
+ waitForIdleSync();
+ }
+
+ private static SensorManager createMockSensorManager(Sensor... sensors) {
+ SensorManager sensorManager = Mockito.mock(SensorManager.class);
+ when(sensorManager.getSensorList(anyInt())).then((invocation) -> {
+ List<Sensor> requestedSensors = new ArrayList<>();
+ int type = invocation.getArgument(0);
+ for (Sensor sensor : sensors) {
+ if (sensor.getType() == type || type == Sensor.TYPE_ALL) {
+ requestedSensors.add(sensor);
+ }
+ }
+ return requestedSensors;
+ });
+
+ when(sensorManager.getDefaultSensor(anyInt())).then((invocation) -> {
+ int type = invocation.getArgument(0);
+ for (Sensor sensor : sensors) {
+ if (sensor.getType() == type) {
+ return sensor;
+ }
+ }
+ return null;
+ });
+ return sensorManager;
+ }
+
+ private static Sensor createLightSensor() {
+ try {
+ return TestUtils.createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT);
+ } catch (Exception e) {
+ // There's nothing we can do if this fails, just throw a RuntimeException so that we
+ // don't have to mark every function that might call this as throwing Exception
+ throw new RuntimeException("Failed to create a light sensor", e);
+ }
+ }
+
+ private void waitForIdleSync() {
+ mHandler.runWithScissors(() -> { }, 500 /*timeout*/);
+ }
+
+ static class FakesInjector implements DisplayModeDirector.Injector {
+ private final FakeDeviceConfig mDeviceConfig;
+ private ContentObserver mBrightnessObserver;
+ private ContentObserver mPeakRefreshRateObserver;
+
+ FakesInjector() {
+ mDeviceConfig = new FakeDeviceConfig();
+ }
+
+ @NonNull
+ public FakeDeviceConfig getDeviceConfig() {
+ return mDeviceConfig;
+ }
+
+ @Override
+ public void registerBrightnessObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer) {
+ if (mBrightnessObserver != null) {
+ throw new IllegalStateException("Tried to register a second brightness observer");
+ }
+ mBrightnessObserver = observer;
+ }
+
+ @Override
+ public void unregisterBrightnessObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer) {
+ mBrightnessObserver = null;
+ }
+
+ void notifyBrightnessChanged() {
+ if (mBrightnessObserver != null) {
+ mBrightnessObserver.dispatchChange(false /*selfChange*/, DISPLAY_BRIGHTNESS_URI);
+ }
+ }
+
+ @Override
+ public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer) {
+ mPeakRefreshRateObserver = observer;
+ }
+
+ void notifyPeakRefreshRateChanged() {
+ if (mPeakRefreshRateObserver != null) {
+ mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,
+ PEAK_REFRESH_RATE_URI);
+ }
+ }
+
+ @Override
+ public boolean isDeviceInteractive(@NonNull Context context) {
+ return true;
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/FakeDeviceConfigInterface.java b/services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java
similarity index 92%
rename from services/tests/wmtests/src/com/android/server/wm/utils/FakeDeviceConfigInterface.java
rename to services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java
index 2904a5b..a67f645 100644
--- a/services/tests/wmtests/src/com/android/server/wm/utils/FakeDeviceConfigInterface.java
+++ b/services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.utils;
+package com.android.server.testutils;
import android.annotation.NonNull;
import android.provider.DeviceConfig;
@@ -22,6 +22,7 @@
import android.util.Pair;
import com.android.internal.util.Preconditions;
+import com.android.server.utils.DeviceConfigInterface;
import java.lang.reflect.Constructor;
import java.util.HashMap;
@@ -122,6 +123,19 @@
}
@Override
+ public float getFloat(String namespace, String name, float defaultValue) {
+ String value = getProperty(namespace, name);
+ if (value == null) {
+ return defaultValue;
+ }
+ try {
+ return Float.parseFloat(value);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
+ @Override
public boolean getBoolean(String namespace, String name, boolean defaultValue) {
String value = getProperty(namespace, name);
return value != null ? Boolean.parseBoolean(value) : defaultValue;
diff --git a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java
index 56cb447..a85e1db 100644
--- a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java
@@ -31,7 +31,7 @@
import com.android.internal.R;
import com.android.internal.util.Preconditions;
-import com.android.server.wm.utils.FakeDeviceConfigInterface;
+import com.android.server.testutils.FakeDeviceConfigInterface;
import org.junit.After;
import org.junit.Test;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java
index 5210011..7a0ef0d7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java
@@ -32,7 +32,7 @@
import androidx.test.filters.SmallTest;
-import com.android.server.wm.utils.FakeDeviceConfigInterface;
+import com.android.server.testutils.FakeDeviceConfigInterface;
import org.junit.After;
import org.junit.Before;
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 757939d..6f10af1 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3928,6 +3928,13 @@
public static final String KEY_USE_LOWER_MTU_VALUE_IF_BOTH_RECEIVED =
"use_lower_mtu_value_if_both_received";
+ /**
+ * Indicates temporarily unmetered mobile data is supported by the carrier.
+ * @hide
+ */
+ public static final String KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL =
+ "network_temp_not_metered_supported_bool";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -4466,6 +4473,7 @@
sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false);
sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, "");
sDefaults.putBoolean(KEY_USE_LOWER_MTU_VALUE_IF_BOTH_RECEIVED, false);
+ sDefaults.putBoolean(KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL, false);
}
/**