Merge "Only need to dismiss stage if one of the task is closed." into udc-dev
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 3312294..9e59ee4 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -2547,7 +2547,7 @@
.setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
new AppOpInfo.Builder(OP_TURN_SCREEN_ON, OPSTR_TURN_SCREEN_ON, "TURN_SCREEN_ON")
.setPermission(Manifest.permission.TURN_SCREEN_ON)
- .setDefaultMode(AppOpsManager.MODE_ERRORED).build(),
+ .setDefaultMode(AppOpsManager.MODE_DEFAULT).build(),
new AppOpInfo.Builder(OP_GET_ACCOUNTS, OPSTR_GET_ACCOUNTS, "GET_ACCOUNTS")
.setPermission(Manifest.permission.GET_ACCOUNTS)
.setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 746dcb6..d8cedb8 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -44,6 +44,7 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -246,6 +247,7 @@
private boolean mBypassDnd;
private int mLockscreenVisibility = DEFAULT_VISIBILITY;
private Uri mSound = Settings.System.DEFAULT_NOTIFICATION_URI;
+ private boolean mSoundRestored = false;
private boolean mLights;
private int mLightColor = DEFAULT_LIGHT_COLOR;
private long[] mVibration;
@@ -929,8 +931,9 @@
/**
* @hide
*/
- public void populateFromXmlForRestore(XmlPullParser parser, Context context) {
- populateFromXml(XmlUtils.makeTyped(parser), true, context);
+ public void populateFromXmlForRestore(XmlPullParser parser, boolean pkgInstalled,
+ Context context) {
+ populateFromXml(XmlUtils.makeTyped(parser), true, pkgInstalled, context);
}
/**
@@ -938,14 +941,14 @@
*/
@SystemApi
public void populateFromXml(XmlPullParser parser) {
- populateFromXml(XmlUtils.makeTyped(parser), false, null);
+ populateFromXml(XmlUtils.makeTyped(parser), false, true, null);
}
/**
* If {@param forRestore} is true, {@param Context} MUST be non-null.
*/
private void populateFromXml(TypedXmlPullParser parser, boolean forRestore,
- @Nullable Context context) {
+ boolean pkgInstalled, @Nullable Context context) {
Preconditions.checkArgument(!forRestore || context != null,
"forRestore is true but got null context");
@@ -956,7 +959,8 @@
setLockscreenVisibility(safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY));
Uri sound = safeUri(parser, ATT_SOUND);
- setSound(forRestore ? restoreSoundUri(context, sound) : sound, safeAudioAttributes(parser));
+ setSound(forRestore ? restoreSoundUri(context, sound, pkgInstalled) : sound,
+ safeAudioAttributes(parser));
enableLights(safeBool(parser, ATT_LIGHTS, false));
setLightColor(safeInt(parser, ATT_LIGHT_COLOR, DEFAULT_LIGHT_COLOR));
@@ -978,8 +982,58 @@
setImportantConversation(safeBool(parser, ATT_IMP_CONVERSATION, false));
}
+ /**
+ * Returns whether the sound for this channel was successfully restored
+ * from backup.
+ * @return false if the sound was not restored successfully. true otherwise (default value)
+ * @hide
+ */
+ public boolean isSoundRestored() {
+ return mSoundRestored;
+ }
+
@Nullable
- private Uri restoreSoundUri(Context context, @Nullable Uri uri) {
+ private Uri getCanonicalizedSoundUri(ContentResolver contentResolver, @NonNull Uri uri) {
+ if (Settings.System.DEFAULT_NOTIFICATION_URI.equals(uri)) {
+ return uri;
+ }
+
+ if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(uri.getScheme())) {
+ try {
+ contentResolver.getResourceId(uri);
+ return uri;
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+ }
+
+ if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
+ return uri;
+ }
+
+ return contentResolver.canonicalize(uri);
+ }
+
+ @Nullable
+ private Uri getUncanonicalizedSoundUri(ContentResolver contentResolver, @NonNull Uri uri) {
+ if (Settings.System.DEFAULT_NOTIFICATION_URI.equals(uri)
+ || ContentResolver.SCHEME_ANDROID_RESOURCE.equals(uri.getScheme())
+ || ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
+ return uri;
+ }
+ return contentResolver.uncanonicalize(uri);
+ }
+
+ /**
+ * Restore/validate sound Uri from backup
+ * @param context The Context
+ * @param uri The sound Uri to restore
+ * @param pkgInstalled If the parent package is installed
+ * @return restored and validated Uri
+ * @hide
+ */
+ @Nullable
+ public Uri restoreSoundUri(Context context, @Nullable Uri uri, boolean pkgInstalled) {
if (uri == null || Uri.EMPTY.equals(uri)) {
return null;
}
@@ -991,12 +1045,22 @@
// the uri and in the case of not having the resource we end up with the default - better
// than broken. As a side effect we'll canonicalize already canonicalized uris, this is fine
// according to the docs because canonicalize method has to handle canonical uris as well.
- Uri canonicalizedUri = contentResolver.canonicalize(uri);
+ Uri canonicalizedUri = getCanonicalizedSoundUri(contentResolver, uri);
if (canonicalizedUri == null) {
- // We got a null because the uri in the backup does not exist here, so we return default
- return Settings.System.DEFAULT_NOTIFICATION_URI;
+ // Uri failed to restore with package installed
+ if (!mSoundRestored && pkgInstalled) {
+ mSoundRestored = true;
+ // We got a null because the uri in the backup does not exist here, so we return
+ // default
+ return Settings.System.DEFAULT_NOTIFICATION_URI;
+ } else {
+ // Flag as unrestored and try again later (on package install)
+ mSoundRestored = false;
+ return uri;
+ }
}
- return contentResolver.uncanonicalize(canonicalizedUri);
+ mSoundRestored = true;
+ return getUncanonicalizedSoundUri(contentResolver, canonicalizedUri);
}
/**
@@ -1019,7 +1083,7 @@
if (sound == null || Uri.EMPTY.equals(sound)) {
return null;
}
- Uri canonicalSound = context.getContentResolver().canonicalize(sound);
+ Uri canonicalSound = getCanonicalizedSoundUri(context.getContentResolver(), sound);
if (canonicalSound == null) {
// The content provider does not support canonical uris so we backup the default
return Settings.System.DEFAULT_NOTIFICATION_URI;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index a8a2ad1..7b68357 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -8394,8 +8394,7 @@
* <p>
* The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA} to be able to call this method; if it has
- * not, a security exception will be thrown, or the caller must hold the permission
- * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CAMERA}.
+ * not, a security exception will be thrown.
* <p>
* <b>Note</b>, this policy type is deprecated for legacy device admins since
* {@link android.os.Build.VERSION_CODES#Q}. On Android
@@ -8411,8 +8410,7 @@
the caller is not a device admin
* @param disabled Whether or not the camera should be disabled.
* @throws SecurityException if {@code admin} is not an active administrator or does not use
- * {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA} and the caller does not hold
- * the permisisons {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_CAMERA}.
+ * {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA}.
*/
@RequiresPermission(value = MANAGE_DEVICE_POLICY_CAMERA, conditional = true)
public void setCameraDisabled(@Nullable ComponentName admin, boolean disabled) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2efb265..3487b01 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4677,22 +4677,16 @@
"display_color_mode_vendor_hint";
/**
- * The user selected min refresh rate in frames per second.
- *
- * If this isn't set, 0 will be used.
+ * Whether or not the peak refresh rate should be forced. 0=no, 1=yes
* @hide
*/
- @Readable
- public static final String MIN_REFRESH_RATE = "min_refresh_rate";
+ public static final String FORCE_PEAK_REFRESH_RATE = "force_peak_refresh_rate";
/**
- * The user selected peak refresh rate in frames per second.
- *
- * If this isn't set, the system falls back to a device specific default.
+ * Whether or not the peak refresh rate should be used for some content. 0=no, 1=yes
* @hide
*/
- @Readable
- public static final String PEAK_REFRESH_RATE = "peak_refresh_rate";
+ public static final String SMOOTH_DISPLAY = "smooth_display";
/**
* The amount of time in milliseconds before the device goes to sleep or begins
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index e31adcf..f2373fb 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -341,6 +341,9 @@
@Nullable
public DisplayShape displayShape;
+ /**
+ * Refresh rate range limitation based on the current device layout
+ */
@Nullable
public SurfaceControl.RefreshRateRange layoutLimitedRefreshRate;
@@ -354,7 +357,7 @@
* RefreshRateRange limitation for @Temperature.ThrottlingStatus
*/
@NonNull
- public SparseArray<SurfaceControl.RefreshRateRange> refreshRateThermalThrottling =
+ public SparseArray<SurfaceControl.RefreshRateRange> thermalRefreshRateThrottling =
new SparseArray<>();
public static final @android.annotation.NonNull Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
@@ -434,7 +437,7 @@
&& Objects.equals(displayShape, other.displayShape)
&& Objects.equals(layoutLimitedRefreshRate, other.layoutLimitedRefreshRate)
&& BrightnessSynchronizer.floatEquals(hdrSdrRatio, other.hdrSdrRatio)
- && refreshRateThermalThrottling.contentEquals(other.refreshRateThermalThrottling);
+ && thermalRefreshRateThrottling.contentEquals(other.thermalRefreshRateThrottling);
}
@Override
@@ -491,7 +494,7 @@
displayShape = other.displayShape;
layoutLimitedRefreshRate = other.layoutLimitedRefreshRate;
hdrSdrRatio = other.hdrSdrRatio;
- refreshRateThermalThrottling = other.refreshRateThermalThrottling;
+ thermalRefreshRateThrottling = other.thermalRefreshRateThrottling;
}
public void readFromParcel(Parcel source) {
@@ -554,7 +557,7 @@
displayShape = source.readTypedObject(DisplayShape.CREATOR);
layoutLimitedRefreshRate = source.readTypedObject(SurfaceControl.RefreshRateRange.CREATOR);
hdrSdrRatio = source.readFloat();
- refreshRateThermalThrottling = source.readSparseArray(null,
+ thermalRefreshRateThrottling = source.readSparseArray(null,
SurfaceControl.RefreshRateRange.class);
}
@@ -616,7 +619,7 @@
dest.writeTypedObject(displayShape, flags);
dest.writeTypedObject(layoutLimitedRefreshRate, flags);
dest.writeFloat(hdrSdrRatio);
- dest.writeSparseArray(refreshRateThermalThrottling);
+ dest.writeSparseArray(thermalRefreshRateThrottling);
}
@Override
@@ -884,8 +887,8 @@
} else {
sb.append(hdrSdrRatio);
}
- sb.append(", refreshRateThermalThrottling ");
- sb.append(refreshRateThermalThrottling);
+ sb.append(", thermalRefreshRateThrottling ");
+ sb.append(thermalRefreshRateThrottling);
sb.append("}");
return sb.toString();
}
diff --git a/core/java/com/android/internal/display/RefreshRateSettingsUtils.java b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
new file mode 100644
index 0000000..39d8380
--- /dev/null
+++ b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2023 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.internal.display;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.Display;
+
+/**
+ * Constants and utility methods for refresh rate settings.
+ */
+public class RefreshRateSettingsUtils {
+
+ private static final String TAG = "RefreshRateSettingsUtils";
+
+ public static final float DEFAULT_REFRESH_RATE = 60f;
+
+ /**
+ * Find the highest refresh rate among all the modes of the default display.
+ * @param context The context
+ * @return The highest refresh rate
+ */
+ public static float findHighestRefreshRateForDefaultDisplay(Context context) {
+ final DisplayManager dm = context.getSystemService(DisplayManager.class);
+ final Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
+
+ if (display == null) {
+ Log.w(TAG, "No valid default display device");
+ return DEFAULT_REFRESH_RATE;
+ }
+
+ float maxRefreshRate = DEFAULT_REFRESH_RATE;
+ for (Display.Mode mode : display.getSupportedModes()) {
+ if (Math.round(mode.getRefreshRate()) > maxRefreshRate) {
+ maxRefreshRate = mode.getRefreshRate();
+ }
+ }
+ return maxRefreshRate;
+ }
+
+ /**
+ * Get the min refresh rate which is determined by
+ * {@link Settings.System.FORCE_PEAK_REFRESH_RATE}.
+ * @param context The context
+ * @return The min refresh rate
+ */
+ public static float getMinRefreshRate(Context context) {
+ final ContentResolver cr = context.getContentResolver();
+ int forcePeakRefreshRateSetting = Settings.System.getIntForUser(cr,
+ Settings.System.FORCE_PEAK_REFRESH_RATE, -1, cr.getUserId());
+ return forcePeakRefreshRateSetting == 1
+ ? findHighestRefreshRateForDefaultDisplay(context)
+ : 0;
+ }
+
+ /**
+ * Get the peak refresh rate which is determined by {@link Settings.System.SMOOTH_DISPLAY}.
+ * @param context The context
+ * @param defaultPeakRefreshRate The refresh rate to return if the setting doesn't have a value
+ * @return The peak refresh rate
+ */
+ public static float getPeakRefreshRate(Context context, float defaultPeakRefreshRate) {
+ final ContentResolver cr = context.getContentResolver();
+ int smoothDisplaySetting = Settings.System.getIntForUser(cr,
+ Settings.System.SMOOTH_DISPLAY, -1, cr.getUserId());
+ switch (smoothDisplaySetting) {
+ case 0:
+ return DEFAULT_REFRESH_RATE;
+ case 1:
+ return findHighestRefreshRateForDefaultDisplay(context);
+ default:
+ return defaultPeakRefreshRate;
+ }
+ }
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 11fcd1e..997a0c9 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2542,7 +2542,7 @@
<permission android:name="android.permission.TURN_SCREEN_ON"
android:label="@string/permlab_turnScreenOn"
android:description="@string/permdesc_turnScreenOn"
- android:protectionLevel="normal|appop" />
+ android:protectionLevel="signature|privileged|appop" />
<!-- ==================================================== -->
<!-- Permissions related to changing audio settings -->
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 56c3068..302c72e 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -42,7 +42,6 @@
import android.media.MediaCodecList;
import android.net.Uri;
import android.os.Build;
-import android.os.SystemProperties;
import android.os.Trace;
import android.system.ErrnoException;
import android.system.Os;
@@ -2069,47 +2068,67 @@
}
private static boolean sIsP010SupportedForAV1 = false;
- private static boolean sIsP010SupportedForAV1Initialized = false;
- private static final Object sIsP010SupportedForAV1Lock = new Object();
+ private static boolean sIsP010SupportedForHEVC = false;
+ private static boolean sIsP010SupportedFlagsInitialized = false;
+ private static final Object sIsP010SupportedLock = new Object();
/**
* Checks if the device supports decoding 10-bit AV1.
*/
@SuppressWarnings("AndroidFrameworkCompatChange") // This is not an app-visible API.
private static boolean isP010SupportedForAV1() {
- synchronized (sIsP010SupportedForAV1Lock) {
- if (sIsP010SupportedForAV1Initialized) {
+ synchronized (sIsP010SupportedLock) {
+ if (sIsP010SupportedFlagsInitialized) {
return sIsP010SupportedForAV1;
}
+ checkP010SupportforAV1HEVC();
+ return sIsP010SupportedForAV1;
+ }
+ }
- sIsP010SupportedForAV1Initialized = true;
- return sIsP010SupportedForAV1 = isP010SupportedforMime("video/av01");
+ /**
+ * Checks if the device supports decoding 10-bit HEVC.
+ * This method is called by JNI.
+ */
+ @SuppressWarnings("unused")
+ private static boolean isP010SupportedForHEVC() {
+ synchronized (sIsP010SupportedLock) {
+ if (sIsP010SupportedFlagsInitialized) {
+ return sIsP010SupportedForHEVC;
+ }
+ checkP010SupportforAV1HEVC();
+ return sIsP010SupportedForHEVC;
}
}
/**
* Checks if the device supports decoding 10-bit for the given mime type.
*/
- private static boolean isP010SupportedforMime(String mime) {
+ private static void checkP010SupportforAV1HEVC() {
MediaCodecList codecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
for (MediaCodecInfo mediaCodecInfo : codecList.getCodecInfos()) {
if (mediaCodecInfo.isEncoder()) {
continue;
}
for (String mediaType : mediaCodecInfo.getSupportedTypes()) {
- if (mediaType.equalsIgnoreCase(mime)) {
+ if (mediaType.equalsIgnoreCase("video/av01")
+ || mediaType.equalsIgnoreCase("video/hevc")) {
MediaCodecInfo.CodecCapabilities codecCapabilities =
mediaCodecInfo.getCapabilitiesForType(mediaType);
for (int i = 0; i < codecCapabilities.colorFormats.length; ++i) {
if (codecCapabilities.colorFormats[i]
== MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010) {
- return true;
+ if (mediaType.equalsIgnoreCase("video/av01")) {
+ sIsP010SupportedForAV1 = true;
+ } else {
+ sIsP010SupportedForHEVC = true;
+ }
}
}
}
}
}
- return false;
+ sIsP010SupportedFlagsInitialized = true;
}
/**
diff --git a/libs/hwui/jni/BitmapFactory.cpp b/libs/hwui/jni/BitmapFactory.cpp
index c57e6f0..38d17de 100644
--- a/libs/hwui/jni/BitmapFactory.cpp
+++ b/libs/hwui/jni/BitmapFactory.cpp
@@ -401,6 +401,14 @@
decodeColorType = kN32_SkColorType;
}
+ // b/276879147, fallback to RGBA_8888 when decoding HEIF and P010 is not supported.
+ if (decodeColorType == kRGBA_1010102_SkColorType &&
+ codec->getEncodedFormat() == SkEncodedImageFormat::kHEIF &&
+ env->CallStaticBooleanMethod(gImageDecoder_class,
+ gImageDecoder_isP010SupportedForHEVCMethodID) == JNI_FALSE) {
+ decodeColorType = kN32_SkColorType;
+ }
+
sk_sp<SkColorSpace> decodeColorSpace = codec->computeOutputColorSpace(
decodeColorType, prefColorSpace);
diff --git a/libs/hwui/jni/BitmapFactory.h b/libs/hwui/jni/BitmapFactory.h
index 45bffc4..a079cb4 100644
--- a/libs/hwui/jni/BitmapFactory.h
+++ b/libs/hwui/jni/BitmapFactory.h
@@ -1,8 +1,9 @@
#ifndef _ANDROID_GRAPHICS_BITMAP_FACTORY_H_
#define _ANDROID_GRAPHICS_BITMAP_FACTORY_H_
+#include <SkEncodedImageFormat.h>
+
#include "GraphicsJNI.h"
-#include "SkEncodedImageFormat.h"
extern jclass gOptions_class;
extern jfieldID gOptions_justBoundsFieldID;
@@ -26,6 +27,9 @@
extern jclass gBitmapConfig_class;
extern jmethodID gBitmapConfig_nativeToConfigMethodID;
+extern jclass gImageDecoder_class;
+extern jmethodID gImageDecoder_isP010SupportedForHEVCMethodID;
+
jstring getMimeTypeAsJavaString(JNIEnv*, SkEncodedImageFormat);
#endif // _ANDROID_GRAPHICS_BITMAP_FACTORY_H_
diff --git a/libs/hwui/jni/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp
index db1c188..6744c6c 100644
--- a/libs/hwui/jni/ImageDecoder.cpp
+++ b/libs/hwui/jni/ImageDecoder.cpp
@@ -25,6 +25,7 @@
#include <SkCodecAnimation.h>
#include <SkColorSpace.h>
#include <SkColorType.h>
+#include <SkEncodedImageFormat.h>
#include <SkImageInfo.h>
#include <SkRect.h>
#include <SkSize.h>
@@ -48,7 +49,8 @@
using namespace android;
-static jclass gImageDecoder_class;
+jclass gImageDecoder_class;
+jmethodID gImageDecoder_isP010SupportedForHEVCMethodID;
static jclass gSize_class;
static jclass gDecodeException_class;
static jclass gCanvas_class;
@@ -298,6 +300,14 @@
colorType = kN32_SkColorType;
}
+ // b/276879147, fallback to RGBA_8888 when decoding HEIF and P010 is not supported.
+ if (colorType == kRGBA_1010102_SkColorType &&
+ decoder->mCodec->getEncodedFormat() == SkEncodedImageFormat::kHEIF &&
+ env->CallStaticBooleanMethod(gImageDecoder_class,
+ gImageDecoder_isP010SupportedForHEVCMethodID) == JNI_FALSE) {
+ colorType = kN32_SkColorType;
+ }
+
if (!decoder->setOutColorType(colorType)) {
doThrowISE(env, "Failed to set out color type!");
return nullptr;
@@ -540,6 +550,8 @@
gImageDecoder_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder"));
gImageDecoder_constructorMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "<init>", "(JIIZZ)V");
gImageDecoder_postProcessMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "postProcessAndRelease", "(Landroid/graphics/Canvas;)I");
+ gImageDecoder_isP010SupportedForHEVCMethodID =
+ GetStaticMethodIDOrDie(env, gImageDecoder_class, "isP010SupportedForHEVC", "()Z");
gSize_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/util/Size"));
gSize_constructorMethodID = GetMethodIDOrDie(env, gSize_class, "<init>", "(II)V");
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index 6a5535d..e4cc9f1 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -100,5 +100,6 @@
Settings.System.CAMERA_FLASH_NOTIFICATION,
Settings.System.SCREEN_FLASH_NOTIFICATION,
Settings.System.SCREEN_FLASH_NOTIFICATION_COLOR,
+ Settings.System.SMOOTH_DISPLAY
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 85623b2..4b72063 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -226,5 +226,6 @@
VALIDATORS.put(System.CAMERA_FLASH_NOTIFICATION, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.SCREEN_FLASH_NOTIFICATION, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.SCREEN_FLASH_NOTIFICATION_COLOR, ANY_INTEGER_VALIDATOR);
+ VALIDATORS.put(System.SMOOTH_DISPLAY, BOOLEAN_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 284b06b..d1bd5e6 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -34,6 +34,7 @@
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static com.android.internal.accessibility.util.AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM;
+import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE;
import static com.android.providers.settings.SettingsState.FALLBACK_FILE_SUFFIX;
import static com.android.providers.settings.SettingsState.getTypeFromKey;
import static com.android.providers.settings.SettingsState.getUserIdFromKey;
@@ -3748,7 +3749,7 @@
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 218;
+ private static final int SETTINGS_VERSION = 219;
private final int mUserId;
@@ -5673,7 +5674,7 @@
providers.addAll(Arrays.asList(resources.getStringArray(resourceId)));
} catch (Resources.NotFoundException e) {
Slog.w(LOG_TAG,
- "Get default array Cred Provider not found: " + e.toString());
+ "Get default array Cred Provider not found: " + e.toString());
}
try {
final String storedValue = resources.getString(resourceId);
@@ -5682,7 +5683,7 @@
}
} catch (Resources.NotFoundException e) {
Slog.w(LOG_TAG,
- "Get default Cred Provider not found: " + e.toString());
+ "Get default Cred Provider not found: " + e.toString());
}
if (!providers.isEmpty()) {
@@ -5731,8 +5732,8 @@
final Setting currentSetting = secureSettings
.getSettingLocked(Settings.Secure.CREDENTIAL_SERVICE);
if (currentSetting.isNull()) {
- final int resourceId =
- com.android.internal.R.array.config_defaultCredentialProviderService;
+ final int resourceId = com.android.internal.R.array
+ .config_defaultCredentialProviderService;
final Resources resources = getContext().getResources();
// If the config has not be defined we might get an exception.
final List<String> providers = new ArrayList<>();
@@ -5740,7 +5741,7 @@
providers.addAll(Arrays.asList(resources.getStringArray(resourceId)));
} catch (Resources.NotFoundException e) {
Slog.w(LOG_TAG,
- "Get default array Cred Provider not found: " + e.toString());
+ "Get default array Cred Provider not found: " + e.toString());
}
if (!providers.isEmpty()) {
@@ -5839,6 +5840,47 @@
currentVersion = 218;
}
+ // v218: Convert Smooth Display and Force Peak Refresh Rate to a boolean
+ if (currentVersion == 218) {
+ final String peakRefreshRateSettingName = "peak_refresh_rate";
+ final String minRefreshRateSettingName = "min_refresh_rate";
+
+ final SettingsState systemSettings = getSystemSettingsLocked(userId);
+ final Setting peakRefreshRateSetting =
+ systemSettings.getSettingLocked(peakRefreshRateSettingName);
+ final Setting minRefreshRateSetting =
+ systemSettings.getSettingLocked(minRefreshRateSettingName);
+
+ float peakRefreshRate = DEFAULT_REFRESH_RATE;
+ float minRefreshRate = 0;
+ try {
+ if (!peakRefreshRateSetting.isNull()) {
+ peakRefreshRate = Float.parseFloat(peakRefreshRateSetting.getValue());
+ }
+ } catch (NumberFormatException e) {
+ // Do nothing. Overwrite with default value.
+ }
+ try {
+ if (!minRefreshRateSetting.isNull()) {
+ minRefreshRate = Float.parseFloat(minRefreshRateSetting.getValue());
+ }
+ } catch (NumberFormatException e) {
+ // Do nothing. Overwrite with default value.
+ }
+
+ systemSettings.deleteSettingLocked(peakRefreshRateSettingName);
+ systemSettings.deleteSettingLocked(minRefreshRateSettingName);
+
+ systemSettings.insertSettingLocked(Settings.System.SMOOTH_DISPLAY,
+ peakRefreshRate > DEFAULT_REFRESH_RATE ? "1" : "0", /* tag= */ null,
+ /* makeDefault= */ false, SettingsState.SYSTEM_PACKAGE_NAME);
+ systemSettings.insertSettingLocked(Settings.System.FORCE_PEAK_REFRESH_RATE,
+ minRefreshRate > 0 ? "1" : "0", /* tag= */ null,
+ /* makeDefault= */ false, SettingsState.SYSTEM_PACKAGE_NAME);
+
+ currentVersion = 219;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 706666c..36aa2ac 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -97,8 +97,7 @@
Settings.System.WHEN_TO_MAKE_WIFI_CALLS, // bug?
Settings.System.WINDOW_ORIENTATION_LISTENER_LOG, // used for debugging only
Settings.System.DESKTOP_MODE, // developer setting for internal prototyping
- Settings.System.MIN_REFRESH_RATE, // depends on hardware capabilities
- Settings.System.PEAK_REFRESH_RATE, // depends on hardware capabilities
+ Settings.System.FORCE_PEAK_REFRESH_RATE, // depends on hardware capabilities
Settings.System.SCREEN_BRIGHTNESS_FLOAT,
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,
Settings.System.MULTI_AUDIO_FOCUS_ENABLED // form-factor/OEM specific
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 24de487..4652ef1 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -982,6 +982,8 @@
</intent-filter>
</activity>
+ <service android:name=".notetask.NoteTaskControllerUpdateService" />
+
<activity
android:name=".notetask.shortcut.LaunchNoteTaskActivity"
android:exported="true"
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
index 86bd5f2..9d1dd1b 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
@@ -648,7 +648,7 @@
private const val DIGITS_PER_LINE = 2
// How much of "fraction" to spend on canceling the animation, if needed
- private const val ANIMATION_CANCELLATION_TIME = 0.4f
+ private const val ANIMATION_CANCELLATION_TIME = 0f
// Delays. Each digit's animation should have a slight delay, so we get a nice
// "stepping" effect. When moving right, the second digit of the hour should move first.
diff --git a/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java b/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java
index 12dd8f0..4c16d41c 100644
--- a/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java
@@ -16,6 +16,7 @@
import android.annotation.Nullable;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.util.AttributeSet;
@@ -23,21 +24,29 @@
import android.view.View;
import android.widget.FrameLayout;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
/**
* Custom {@link FrameLayout} that re-inflates when changes to {@link Configuration} happen.
* Currently supports changes to density, asset path, and locale.
*/
-public class AutoReinflateContainer extends FrameLayout implements
- ConfigurationController.ConfigurationListener {
+public class AutoReinflateContainer extends FrameLayout {
+
+ private static final Set<Integer> SUPPORTED_CHANGES = Set.of(
+ ActivityInfo.CONFIG_LOCALE,
+ ActivityInfo.CONFIG_UI_MODE,
+ ActivityInfo.CONFIG_ASSETS_PATHS,
+ ActivityInfo.CONFIG_DENSITY,
+ ActivityInfo.CONFIG_FONT_SCALE
+ );
private final List<InflateListener> mInflateListeners = new ArrayList<>();
private final int mLayout;
+ private final Configuration mLastConfig = new Configuration();
+
public AutoReinflateContainer(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
@@ -51,15 +60,14 @@
}
@Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- Dependency.get(ConfigurationController.class).addCallback(this);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- Dependency.get(ConfigurationController.class).removeCallback(this);
+ protected void onConfigurationChanged(Configuration newConfig) {
+ int diff = mLastConfig.updateFrom(newConfig);
+ for (int change: SUPPORTED_CHANGES) {
+ if ((diff & change) != 0) {
+ inflateLayout();
+ return;
+ }
+ }
}
protected void inflateLayoutImpl() {
@@ -80,26 +88,6 @@
listener.onInflated(getChildAt(0));
}
- @Override
- public void onDensityOrFontScaleChanged() {
- inflateLayout();
- }
-
- @Override
- public void onThemeChanged() {
- inflateLayout();
- }
-
- @Override
- public void onUiModeChanged() {
- inflateLayout();
- }
-
- @Override
- public void onLocaleListChanged() {
- inflateLayout();
- }
-
public interface InflateListener {
/**
* Called whenever a new view is inflated.
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index ef16a3a..aade71a 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -106,7 +106,6 @@
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.ExtensionController;
@@ -134,14 +133,14 @@
import com.android.systemui.util.leak.LeakReporter;
import com.android.systemui.util.sensors.AsyncSensorManager;
+import dagger.Lazy;
+
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Named;
-import dagger.Lazy;
-
/**
* Class to handle ugly dependencies throughout sysui until we determine the
* long-term dependency injection solution.
@@ -270,7 +269,6 @@
@Inject Lazy<NotificationShadeWindowController> mNotificationShadeWindowController;
@Inject Lazy<StatusBarWindowController> mTempStatusBarWindowController;
@Inject Lazy<DarkIconDispatcher> mDarkIconDispatcher;
- @Inject Lazy<ConfigurationController> mConfigurationController;
@Inject Lazy<StatusBarIconController> mStatusBarIconController;
@Inject Lazy<ScreenLifecycle> mScreenLifecycle;
@Inject Lazy<WakefulnessLifecycle> mWakefulnessLifecycle;
@@ -441,8 +439,6 @@
mProviders.put(DarkIconDispatcher.class, mDarkIconDispatcher::get);
- mProviders.put(ConfigurationController.class, mConfigurationController::get);
-
mProviders.put(StatusBarIconController.class, mStatusBarIconController::get);
mProviders.put(ScreenLifecycle.class, mScreenLifecycle::get);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 2d1b7ae..2925d8d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -792,7 +792,8 @@
// Translate up from the bottom.
surfaceBehindMatrix.setTranslate(
surfaceBehindRemoteAnimationTarget.localBounds.left.toFloat(),
- surfaceHeight * SURFACE_BEHIND_START_TRANSLATION_Y * (1f - amount)
+ surfaceBehindRemoteAnimationTarget.localBounds.top.toFloat() +
+ surfaceHeight * SURFACE_BEHIND_START_TRANSLATION_Y * (1f - amount)
)
// Scale up from a point at the center-bottom of the surface.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 7a2013e..93ddfba 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1610,8 +1610,9 @@
}
private void doKeyguardLaterForChildProfilesLocked() {
- UserManager um = UserManager.get(mContext);
- for (int profileId : um.getEnabledProfileIds(UserHandle.myUserId())) {
+ for (UserInfo profile : mUserTracker.getUserProfiles()) {
+ if (!profile.isEnabled()) continue;
+ final int profileId = profile.id;
if (mLockPatternUtils.isSeparateProfileChallengeEnabled(profileId)) {
long userTimeout = getLockTimeout(profileId);
if (userTimeout == 0) {
@@ -1634,8 +1635,9 @@
}
private void doKeyguardForChildProfilesLocked() {
- UserManager um = UserManager.get(mContext);
- for (int profileId : um.getEnabledProfileIds(UserHandle.myUserId())) {
+ for (UserInfo profile : mUserTracker.getUserProfiles()) {
+ if (!profile.isEnabled()) continue;
+ final int profileId = profile.id;
if (mLockPatternUtils.isSeparateProfileChallengeEnabled(profileId)) {
lockProfile(profileId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index aab898e..8aec0c6 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -284,7 +284,15 @@
/** @see OnRoleHoldersChangedListener */
fun onRoleHoldersChanged(roleName: String, user: UserHandle) {
- if (roleName == ROLE_NOTES) updateNoteTaskAsUser(user)
+ if (roleName != ROLE_NOTES) return
+
+ if (user == userTracker.userHandle) {
+ updateNoteTaskAsUser(user)
+ } else {
+ // TODO(b/278729185): Replace fire and forget service with a bounded service.
+ val intent = NoteTaskControllerUpdateService.createIntent(context)
+ context.startServiceAsUser(intent, user)
+ }
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskControllerUpdateService.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskControllerUpdateService.kt
new file mode 100644
index 0000000..26b35cc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskControllerUpdateService.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 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.systemui.notetask
+
+import android.content.Context
+import android.content.Intent
+import androidx.lifecycle.LifecycleService
+import javax.inject.Inject
+
+/**
+ * A fire & forget service for updating note task shortcuts.
+ *
+ * The main use is to update shortcuts in different user by launching it using `startServiceAsUser`.
+ * The service will open with access to a context from that user, trigger
+ * [NoteTaskController.updateNoteTaskAsUser] and [stopSelf] immediately.
+ *
+ * The fire and forget approach was created due to its simplicity but may use unnecessary resources
+ * by recreating the services. We will investigate its impacts and consider to move to a bounded
+ * services - the implementation is more complex as a bounded service is asynchronous by default.
+ *
+ * TODO(b/278729185): Replace fire and forget service with a bounded service.
+ */
+@InternalNoteTaskApi
+class NoteTaskControllerUpdateService
+@Inject
+constructor(
+ val controller: NoteTaskController,
+) : LifecycleService() {
+
+ override fun onCreate() {
+ super.onCreate()
+ // TODO(b/278729185): Replace fire and forget service with a bounded service.
+ controller.updateNoteTaskAsUser(user)
+ stopSelf()
+ }
+
+ companion object {
+ fun createIntent(context: Context): Intent =
+ Intent(context, NoteTaskControllerUpdateService::class.java)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
index 1839dfd..a166393 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
@@ -14,9 +14,12 @@
* limitations under the License.
*/
+@file:OptIn(InternalNoteTaskApi::class)
+
package com.android.systemui.notetask
import android.app.Activity
+import android.app.Service
import android.app.role.RoleManager
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
@@ -34,6 +37,9 @@
@Module(includes = [NoteTaskQuickAffordanceModule::class])
interface NoteTaskModule {
+ @[Binds IntoMap ClassKey(NoteTaskControllerUpdateService::class)]
+ fun NoteTaskControllerUpdateService.bindNoteTaskControllerUpdateService(): Service
+
@[Binds IntoMap ClassKey(LaunchNoteTaskActivity::class)]
fun LaunchNoteTaskActivity.bindNoteTaskLauncherActivity(): Activity
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt
index b445000..5850a84 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt
@@ -47,19 +47,36 @@
viewsIdToTranslate =
setOf(
ViewIdToTranslate(R.id.quick_settings_panel, START, filterShade),
- ViewIdToTranslate(R.id.notification_stack_scroller, END, filterShade),
- ViewIdToTranslate(R.id.statusIcons, END, filterShade),
- ViewIdToTranslate(R.id.privacy_container, END, filterShade),
- ViewIdToTranslate(R.id.batteryRemainingIcon, END, filterShade),
- ViewIdToTranslate(R.id.carrier_group, END, filterShade),
- ViewIdToTranslate(R.id.clock, START, filterShade),
- ViewIdToTranslate(R.id.date, START, filterShade)),
+ ViewIdToTranslate(R.id.notification_stack_scroller, END, filterShade)),
progressProvider = progressProvider)
}
+ private val translateAnimatorStatusBar by lazy {
+ UnfoldConstantTranslateAnimator(
+ viewsIdToTranslate =
+ setOf(
+ ViewIdToTranslate(R.id.statusIcons, END, filterShade),
+ ViewIdToTranslate(R.id.privacy_container, END, filterShade),
+ ViewIdToTranslate(R.id.batteryRemainingIcon, END, filterShade),
+ ViewIdToTranslate(R.id.carrier_group, END, filterShade),
+ ViewIdToTranslate(R.id.clock, START, filterShade),
+ ViewIdToTranslate(R.id.date, START, filterShade)
+ ),
+ progressProvider = progressProvider
+ )
+ }
+
fun setup(root: ViewGroup) {
val translationMax =
context.resources.getDimensionPixelSize(R.dimen.notification_side_paddings).toFloat()
translateAnimator.init(root, translationMax)
+ val splitShadeStatusBarViewGroup: ViewGroup? =
+ root.findViewById(R.id.split_shade_status_bar)
+ if (splitShadeStatusBarViewGroup != null) {
+ translateAnimatorStatusBar.init(
+ splitShadeStatusBarViewGroup,
+ translationMax
+ )
+ }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
index 7dc622b..55f221d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
@@ -620,6 +620,38 @@
}
}
+ // region onRoleHoldersChanged
+ @Test
+ fun onRoleHoldersChanged_notNotesRole_doNothing() {
+ val user = UserHandle.of(0)
+
+ createNoteTaskController(isEnabled = true).onRoleHoldersChanged("NOT_NOTES", user)
+
+ verifyZeroInteractions(context)
+ }
+
+ @Test
+ fun onRoleHoldersChanged_notesRole_sameUser_shouldUpdateShortcuts() {
+ val user = userTracker.userHandle
+ val controller = spy(createNoteTaskController())
+ doNothing().whenever(controller).updateNoteTaskAsUser(any())
+
+ controller.onRoleHoldersChanged(ROLE_NOTES, user)
+
+ verify(controller).updateNoteTaskAsUser(user)
+ }
+
+ @Test
+ fun onRoleHoldersChanged_notesRole_differentUser_shouldUpdateShortcutsInUserProcess() {
+ // FakeUserTracker will default to UserHandle.SYSTEM.
+ val user = UserHandle.CURRENT
+
+ createNoteTaskController(isEnabled = true).onRoleHoldersChanged(ROLE_NOTES, user)
+
+ verify(context).startServiceAsUser(any(), eq(user))
+ }
+ // endregion
+
// region updateNoteTaskAsUser
@Test
fun updateNoteTaskAsUser_withNotesRole_withShortcuts_shouldUpdateShortcuts() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationControllerTest.kt
index db6fc13..38a666e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationControllerTest.kt
@@ -37,6 +37,7 @@
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
+import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -54,10 +55,12 @@
@Mock private lateinit var parent: ViewGroup
+ @Mock private lateinit var splitShadeStatusBar: ViewGroup
+
@Mock private lateinit var statusBarStateController: StatusBarStateController
private lateinit var underTest: NotificationPanelUnfoldAnimationController
- private lateinit var progressListener: TransitionProgressListener
+ private lateinit var progressListeners: List<TransitionProgressListener>
private var xTranslationMax = 0f
@Before
@@ -73,10 +76,13 @@
statusBarStateController,
progressProvider
)
+ whenever(parent.findViewById<ViewGroup>(R.id.split_shade_status_bar)).thenReturn(
+ splitShadeStatusBar
+ )
underTest.setup(parent)
- verify(progressProvider).addCallback(capture(progressListenerCaptor))
- progressListener = progressListenerCaptor.value
+ verify(progressProvider, atLeastOnce()).addCallback(capture(progressListenerCaptor))
+ progressListeners = progressListenerCaptor.allValues
}
@Test
@@ -86,16 +92,16 @@
val view = View(context)
whenever(parent.findViewById<View>(R.id.quick_settings_panel)).thenReturn(view)
- progressListener.onTransitionStarted()
+ onTransitionStarted()
assertThat(view.translationX).isZero()
- progressListener.onTransitionProgress(0f)
+ onTransitionProgress(0f)
assertThat(view.translationX).isZero()
- progressListener.onTransitionProgress(0.5f)
+ onTransitionProgress(0.5f)
assertThat(view.translationX).isZero()
- progressListener.onTransitionFinished()
+ onTransitionFinished()
assertThat(view.translationX).isZero()
}
@@ -106,16 +112,16 @@
val view = View(context)
whenever(parent.findViewById<View>(R.id.quick_settings_panel)).thenReturn(view)
- progressListener.onTransitionStarted()
+ onTransitionStarted()
assertThat(view.translationX).isZero()
- progressListener.onTransitionProgress(0f)
+ onTransitionProgress(0f)
assertThat(view.translationX).isEqualTo(xTranslationMax)
- progressListener.onTransitionProgress(0.5f)
+ onTransitionProgress(0.5f)
assertThat(view.translationX).isEqualTo(0.5f * xTranslationMax)
- progressListener.onTransitionFinished()
+ onTransitionFinished()
assertThat(view.translationX).isZero()
}
@@ -126,16 +132,88 @@
val view = View(context)
whenever(parent.findViewById<View>(R.id.quick_settings_panel)).thenReturn(view)
- progressListener.onTransitionStarted()
+ onTransitionStarted()
assertThat(view.translationX).isZero()
- progressListener.onTransitionProgress(0f)
+ onTransitionProgress(0f)
assertThat(view.translationX).isEqualTo(xTranslationMax)
- progressListener.onTransitionProgress(0.5f)
+ onTransitionProgress(0.5f)
assertThat(view.translationX).isEqualTo(0.5f * xTranslationMax)
- progressListener.onTransitionFinished()
+ onTransitionFinished()
assertThat(view.translationX).isZero()
}
+
+ @Test
+ fun whenInKeyguardState_statusBarViewDoesNotMove() {
+ whenever(statusBarStateController.getState()).thenReturn(KEYGUARD)
+
+ val view = View(context)
+ whenever(splitShadeStatusBar.findViewById<View>(R.id.date)).thenReturn(view)
+
+ onTransitionStarted()
+ assertThat(view.translationX).isZero()
+
+ onTransitionProgress(0f)
+ assertThat(view.translationX).isZero()
+
+ onTransitionProgress(0.5f)
+ assertThat(view.translationX).isZero()
+
+ onTransitionFinished()
+ assertThat(view.translationX).isZero()
+ }
+
+ @Test
+ fun whenInShadeState_statusBarViewDoesMove() {
+ whenever(statusBarStateController.getState()).thenReturn(SHADE)
+
+ val view = View(context)
+ whenever(splitShadeStatusBar.findViewById<View>(R.id.date)).thenReturn(view)
+
+ onTransitionStarted()
+ assertThat(view.translationX).isZero()
+
+ onTransitionProgress(0f)
+ assertThat(view.translationX).isEqualTo(xTranslationMax)
+
+ onTransitionProgress(0.5f)
+ assertThat(view.translationX).isEqualTo(0.5f * xTranslationMax)
+
+ onTransitionFinished()
+ assertThat(view.translationX).isZero()
+ }
+
+ @Test
+ fun whenInShadeLockedState_statusBarViewDoesMove() {
+ whenever(statusBarStateController.getState()).thenReturn(SHADE_LOCKED)
+
+ val view = View(context)
+ whenever(splitShadeStatusBar.findViewById<View>(R.id.date)).thenReturn(view)
+ onTransitionStarted()
+ assertThat(view.translationX).isZero()
+
+ onTransitionProgress(0f)
+ assertThat(view.translationX).isEqualTo(xTranslationMax)
+
+ onTransitionProgress(0.5f)
+ assertThat(view.translationX).isEqualTo(0.5f * xTranslationMax)
+
+ onTransitionFinished()
+ assertThat(view.translationX).isZero()
+ }
+
+ private fun onTransitionStarted() {
+ progressListeners.forEach { it.onTransitionStarted() }
+ }
+
+ private fun onTransitionProgress(progress: Float) {
+ progressListeners.forEach { it.onTransitionProgress(progress) }
+ }
+
+ private fun onTransitionFinished() {
+ progressListeners.forEach { it.onTransitionFinished() }
+ }
+
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 780e0c5..6fda56c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -116,7 +116,6 @@
.thenReturn(TEST_AUTO_DISMISS_TIME);
when(mVSProvider.isReorderingAllowed()).thenReturn(true);
mDependency.injectMockDependency(NotificationShadeWindowController.class);
- mDependency.injectMockDependency(ConfigurationController.class);
super.setUp();
mHeadsUpManager = new TestableHeadsUpManagerPhone(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java
index 71ac7c4..683136d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java
@@ -45,6 +45,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.Map;
import java.util.function.Consumer;
@@ -53,16 +55,18 @@
@SmallTest
public class ExtensionControllerImplTest extends SysuiTestCase {
+ @Mock
+ private ConfigurationController mConfigurationController;
+
private PluginManager mPluginManager;
private TunerService mTunerService;
private ExtensionController mExtensionController;
- private ConfigurationController mConfigurationController;
@Before
public void setup() {
+ MockitoAnnotations.initMocks(this);
mPluginManager = mDependency.injectMockDependency(PluginManager.class);
mTunerService = mDependency.injectMockDependency(TunerService.class);
- mConfigurationController = mDependency.injectMockDependency(ConfigurationController.class);
mExtensionController = new ExtensionControllerImpl(
mContext,
mock(LeakDetector.class),
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index a021174..ca482dc 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -2396,7 +2396,6 @@
mHbmData.timeWindowMillis = hbmTiming.getTimeWindowSecs_all().longValue() * 1000;
mHbmData.timeMaxMillis = hbmTiming.getTimeMaxSecs_all().longValue() * 1000;
mHbmData.timeMinMillis = hbmTiming.getTimeMinSecs_all().longValue() * 1000;
- mHbmData.thermalStatusLimit = convertThermalStatus(hbm.getThermalStatusLimit_all());
mHbmData.allowInLowPowerMode = hbm.getAllowInLowPowerMode_all();
final RefreshRateRange rr = hbm.getRefreshRate_all();
if (rr != null) {
@@ -2972,9 +2971,6 @@
/** Brightness level at which we transition from normal to high-brightness. */
public float transitionPoint;
- /** Enable HBM only if the thermal status is not higher than this. */
- public @PowerManager.ThermalStatus int thermalStatusLimit;
-
/** Whether HBM is allowed when {@code Settings.Global.LOW_POWER_MODE} is active. */
public boolean allowInLowPowerMode;
@@ -2993,15 +2989,13 @@
HighBrightnessModeData() {}
HighBrightnessModeData(float minimumLux, float transitionPoint, long timeWindowMillis,
- long timeMaxMillis, long timeMinMillis,
- @PowerManager.ThermalStatus int thermalStatusLimit, boolean allowInLowPowerMode,
+ long timeMaxMillis, long timeMinMillis, boolean allowInLowPowerMode,
float minimumHdrPercentOfScreen) {
this.minimumLux = minimumLux;
this.transitionPoint = transitionPoint;
this.timeWindowMillis = timeWindowMillis;
this.timeMaxMillis = timeMaxMillis;
this.timeMinMillis = timeMinMillis;
- this.thermalStatusLimit = thermalStatusLimit;
this.allowInLowPowerMode = allowInLowPowerMode;
this.minimumHdrPercentOfScreen = minimumHdrPercentOfScreen;
}
@@ -3016,7 +3010,6 @@
other.timeMaxMillis = timeMaxMillis;
other.timeMinMillis = timeMinMillis;
other.transitionPoint = transitionPoint;
- other.thermalStatusLimit = thermalStatusLimit;
other.allowInLowPowerMode = allowInLowPowerMode;
other.minimumHdrPercentOfScreen = minimumHdrPercentOfScreen;
}
@@ -3029,7 +3022,6 @@
+ ", timeWindow: " + timeWindowMillis + "ms"
+ ", timeMax: " + timeMaxMillis + "ms"
+ ", timeMin: " + timeMinMillis + "ms"
- + ", thermalStatusLimit: " + thermalStatusLimit
+ ", allowInLowPowerMode: " + allowInLowPowerMode
+ ", minimumHdrPercentOfScreen: " + minimumHdrPercentOfScreen
+ "} ";
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index f1efec0..78c5f0e 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -2828,6 +2828,7 @@
pw.println(" mDisplayId=" + mDisplayId);
pw.println(" mLeadDisplayId=" + mLeadDisplayId);
pw.println(" mLightSensor=" + mLightSensor);
+ pw.println(" mDisplayBrightnessFollowers=" + mDisplayBrightnessFollowers);
pw.println();
pw.println("Display Power Controller Locked State:");
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 59e112e..a76f907 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -2222,6 +2222,7 @@
pw.println(" mDisplayId=" + mDisplayId);
pw.println(" mLeadDisplayId=" + mLeadDisplayId);
pw.println(" mLightSensor=" + mLightSensor);
+ pw.println(" mDisplayBrightnessFollowers=" + mDisplayBrightnessFollowers);
pw.println();
pw.println("Display Power Controller Locked State:");
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
index ca208ac..11160a5 100644
--- a/services/core/java/com/android/server/display/HighBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -22,13 +22,8 @@
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
-import android.os.IThermalEventListener;
-import android.os.IThermalService;
import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
-import android.os.Temperature;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.MathUtils;
@@ -75,7 +70,6 @@
private final Runnable mHbmChangeCallback;
private final Runnable mRecalcRunnable;
private final Clock mClock;
- private final SkinThermalStatusObserver mSkinThermalStatusObserver;
private final Context mContext;
private final SettingsObserver mSettingsObserver;
private final Injector mInjector;
@@ -100,10 +94,8 @@
private int mHbmMode = BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
private boolean mIsHdrLayerPresent = false;
-
// mMaxDesiredHdrSdrRatio should only be applied when there is a valid backlight->nits mapping
private float mMaxDesiredHdrSdrRatio = DEFAULT_MAX_DESIRED_HDR_SDR_RATIO;
- private boolean mIsThermalStatusWithinLimit = true;
private boolean mIsBlockedByLowPowerMode = false;
private int mWidth;
private int mHeight;
@@ -138,7 +130,6 @@
mBrightnessMax = brightnessMax;
mHbmChangeCallback = hbmChangeCallback;
mHighBrightnessModeMetadata = hbmMetadata;
- mSkinThermalStatusObserver = new SkinThermalStatusObserver(mInjector, mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
mRecalcRunnable = this::recalculateTimeAllowance;
mHdrListener = new HdrListener();
@@ -261,7 +252,6 @@
void stop() {
registerHdrListener(null /*displayToken*/);
- mSkinThermalStatusObserver.stopObserving();
mSettingsObserver.stopObserving();
}
@@ -278,15 +268,10 @@
mDisplayStatsId = displayUniqueId.hashCode();
unregisterHdrListener();
- mSkinThermalStatusObserver.stopObserving();
mSettingsObserver.stopObserving();
if (deviceSupportsHbm()) {
registerHdrListener(displayToken);
recalculateTimeAllowance();
- if (mHbmData.thermalStatusLimit > PowerManager.THERMAL_STATUS_NONE) {
- mIsThermalStatusWithinLimit = true;
- mSkinThermalStatusObserver.startObserving();
- }
if (!mHbmData.allowInLowPowerMode) {
mIsBlockedByLowPowerMode = false;
mSettingsObserver.startObserving();
@@ -327,7 +312,6 @@
pw.println(" mIsTimeAvailable= " + mIsTimeAvailable);
pw.println(" mRunningStartTimeMillis="
+ TimeUtils.formatUptime(mHighBrightnessModeMetadata.getRunningStartTimeMillis()));
- pw.println(" mIsThermalStatusWithinLimit=" + mIsThermalStatusWithinLimit);
pw.println(" mIsBlockedByLowPowerMode=" + mIsBlockedByLowPowerMode);
pw.println(" width*height=" + mWidth + "*" + mHeight);
pw.println(" mEvents=");
@@ -344,8 +328,6 @@
}
lastStartTime = dumpHbmEvent(pw, event);
}
-
- mSkinThermalStatusObserver.dump(pw);
}
private long dumpHbmEvent(PrintWriter pw, HbmEvent event) {
@@ -367,7 +349,7 @@
// See {@link #getHdrBrightnessValue}.
return !mIsHdrLayerPresent
&& (mIsAutoBrightnessEnabled && mIsTimeAvailable && mIsInAllowedAmbientRange
- && mIsThermalStatusWithinLimit && !mIsBlockedByLowPowerMode);
+ && !mIsBlockedByLowPowerMode);
}
private boolean deviceSupportsHbm() {
@@ -469,7 +451,6 @@
+ ", isAutoBrightnessEnabled: " + mIsAutoBrightnessEnabled
+ ", mIsTimeAvailable: " + mIsTimeAvailable
+ ", mIsInAllowedAmbientRange: " + mIsInAllowedAmbientRange
- + ", mIsThermalStatusWithinLimit: " + mIsThermalStatusWithinLimit
+ ", mIsBlockedByLowPowerMode: " + mIsBlockedByLowPowerMode
+ ", mBrightness: " + mBrightness
+ ", mUnthrottledBrightness: " + mUnthrottledBrightness
@@ -499,13 +480,12 @@
}
private void updateHbmStats(int newMode) {
- final float transitionPoint = mHbmData.transitionPoint;
int state = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF;
if (newMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
- && getHdrBrightnessValue() > transitionPoint) {
+ && getHdrBrightnessValue() > mHbmData.transitionPoint) {
state = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_HDR;
} else if (newMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT
- && mBrightness > transitionPoint) {
+ && mBrightness > mHbmData.transitionPoint) {
state = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT;
}
if (state == mHbmStatsState) {
@@ -519,16 +499,6 @@
final boolean newHbmSv =
(state == FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT);
if (oldHbmSv && !newHbmSv) {
- // HighBrightnessModeController (HBMC) currently supports throttling from two sources:
- // 1. Internal, received from HBMC.SkinThermalStatusObserver.notifyThrottling()
- // 2. External, received from HBMC.onBrightnessChanged()
- // TODO(b/216373254): Deprecate internal throttling source
- final boolean internalThermalThrottling = !mIsThermalStatusWithinLimit;
- final boolean externalThermalThrottling =
- mUnthrottledBrightness > transitionPoint && // We would've liked HBM brightness...
- mBrightness <= transitionPoint && // ...but we got NBM, because of...
- mThrottlingReason == BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL; // ...thermals.
-
// If more than one conditions are flipped and turn off HBM sunlight
// visibility, only one condition will be reported to make it simple.
if (!mIsAutoBrightnessEnabled && mIsAutoBrightnessOffByState) {
@@ -541,7 +511,7 @@
reason = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_LUX_DROP;
} else if (!mIsTimeAvailable) {
reason = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_TIME_LIMIT;
- } else if (internalThermalThrottling || externalThermalThrottling) {
+ } else if (isThermalThrottlingActive()) {
reason = FrameworkStatsLog
.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_THERMAL_LIMIT;
} else if (mIsHdrLayerPresent) {
@@ -561,6 +531,14 @@
mHbmStatsState = state;
}
+ @VisibleForTesting
+ boolean isThermalThrottlingActive() {
+ // We would've liked HBM, but we got NBM (normal brightness mode) because of thermals.
+ return mUnthrottledBrightness > mHbmData.transitionPoint
+ && mBrightness <= mHbmData.transitionPoint
+ && mThrottlingReason == BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL;
+ }
+
private String hbmStatsStateToString(int hbmStatsState) {
switch (hbmStatsState) {
case FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF:
@@ -635,82 +613,6 @@
}
}
- private final class SkinThermalStatusObserver extends IThermalEventListener.Stub {
- private final Injector mInjector;
- private final Handler mHandler;
-
- private IThermalService mThermalService;
- private boolean mStarted;
-
- SkinThermalStatusObserver(Injector injector, Handler handler) {
- mInjector = injector;
- mHandler = handler;
- }
-
- @Override
- public void notifyThrottling(Temperature temp) {
- if (DEBUG) {
- Slog.d(TAG, "New thermal throttling status "
- + ", current thermal status = " + temp.getStatus()
- + ", threshold = " + mHbmData.thermalStatusLimit);
- }
- mHandler.post(() -> {
- mIsThermalStatusWithinLimit = temp.getStatus() <= mHbmData.thermalStatusLimit;
- // This recalculates HbmMode and runs mHbmChangeCallback if the mode has changed
- updateHbmMode();
- });
- }
-
- void startObserving() {
- if (mStarted) {
- if (DEBUG) {
- Slog.d(TAG, "Thermal status observer already started");
- }
- return;
- }
- mThermalService = mInjector.getThermalService();
- if (mThermalService == null) {
- Slog.w(TAG, "Could not observe thermal status. Service not available");
- return;
- }
- try {
- // We get a callback immediately upon registering so there's no need to query
- // for the current value.
- mThermalService.registerThermalEventListenerWithType(this, Temperature.TYPE_SKIN);
- mStarted = true;
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to register thermal status listener", e);
- }
- }
-
- void stopObserving() {
- mIsThermalStatusWithinLimit = true;
- if (!mStarted) {
- if (DEBUG) {
- Slog.d(TAG, "Stop skipped because thermal status observer not started");
- }
- return;
- }
- try {
- mThermalService.unregisterThermalEventListener(this);
- mStarted = false;
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to unregister thermal status listener", e);
- }
- mThermalService = null;
- }
-
- void dump(PrintWriter writer) {
- writer.println(" SkinThermalStatusObserver:");
- writer.println(" mStarted: " + mStarted);
- if (mThermalService != null) {
- writer.println(" ThermalService available");
- } else {
- writer.println(" ThermalService not available");
- }
- }
- }
-
private final class SettingsObserver extends ContentObserver {
private final Uri mLowPowerModeSetting = Settings.Global.getUriFor(
Settings.Global.LOW_POWER_MODE);
@@ -766,11 +668,6 @@
return SystemClock::uptimeMillis;
}
- public IThermalService getThermalService() {
- return IThermalService.Stub.asInterface(
- ServiceManager.getService(Context.THERMAL_SERVICE));
- }
-
public void reportHbmStateChange(int display, int state, int reason) {
FrameworkStatsLog.write(
FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED, display, state, reason);
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index dab00d8..0b6d1c8 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -181,6 +181,19 @@
*/
private String mThermalBrightnessThrottlingDataId;
+ /**
+ * Refresh rate range limitation based on the current device layout
+ */
+ @Nullable
+ private SurfaceControl.RefreshRateRange mLayoutLimitedRefreshRate;
+
+ /**
+ * RefreshRateRange limitation for @Temperature.ThrottlingStatus
+ */
+ @NonNull
+ private SparseArray<SurfaceControl.RefreshRateRange> mThermalRefreshRateThrottling =
+ new SparseArray<>();
+
public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
mDisplayId = displayId;
mLayerStack = layerStack;
@@ -339,24 +352,24 @@
*/
public void updateLayoutLimitedRefreshRateLocked(
@Nullable SurfaceControl.RefreshRateRange layoutLimitedRefreshRate) {
- if (!Objects.equals(layoutLimitedRefreshRate, mBaseDisplayInfo.layoutLimitedRefreshRate)) {
- mBaseDisplayInfo.layoutLimitedRefreshRate = layoutLimitedRefreshRate;
- mInfo.set(null);
+ if (!Objects.equals(layoutLimitedRefreshRate, mLayoutLimitedRefreshRate)) {
+ mLayoutLimitedRefreshRate = layoutLimitedRefreshRate;
+ mDirty = true;
}
}
/**
- * Updates refreshRateThermalThrottling
+ * Updates thermalRefreshRateThrottling
*
- * @param refreshRanges new refreshRateThermalThrottling ranges limited by layout or default
+ * @param refreshRanges new thermalRefreshRateThrottling ranges limited by layout or default
*/
public void updateThermalRefreshRateThrottling(
@Nullable SparseArray<SurfaceControl.RefreshRateRange> refreshRanges) {
if (refreshRanges == null) {
refreshRanges = new SparseArray<>();
}
- if (!mBaseDisplayInfo.refreshRateThermalThrottling.contentEquals(refreshRanges)) {
- mBaseDisplayInfo.refreshRateThermalThrottling = refreshRanges;
- mInfo.set(null);
+ if (!mThermalRefreshRateThrottling.contentEquals(refreshRanges)) {
+ mThermalRefreshRateThrottling = refreshRanges;
+ mDirty = true;
}
}
@@ -499,6 +512,9 @@
mBaseDisplayInfo.removeMode = Display.REMOVE_MODE_DESTROY_CONTENT;
}
+ mBaseDisplayInfo.layoutLimitedRefreshRate = mLayoutLimitedRefreshRate;
+ mBaseDisplayInfo.thermalRefreshRateThrottling = mThermalRefreshRateThrottling;
+
mPrimaryDisplayDeviceInfo = deviceInfo;
mInfo.set(null);
mDirty = false;
@@ -952,6 +968,8 @@
pw.println("mDisplayGroupName=" + mDisplayGroupName);
pw.println("mThermalBrightnessThrottlingDataId=" + mThermalBrightnessThrottlingDataId);
pw.println("mLeadDisplayId=" + mLeadDisplayId);
+ pw.println("mLayoutLimitedRefreshRate=" + mLayoutLimitedRefreshRate);
+ pw.println("mThermalRefreshRateThrottling=" + mThermalRefreshRateThrottling);
}
@Override
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index 0189294..06b7698 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -65,6 +65,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.display.BrightnessSynchronizer;
+import com.android.internal.display.RefreshRateSettingsUtils;
import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
import com.android.server.display.DisplayDeviceConfig;
@@ -1171,7 +1172,7 @@
public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 2;
// SETTING_MIN_RENDER_FRAME_RATE is used to propose a lower bound of the render frame rate.
- // It votes [MIN_REFRESH_RATE, Float.POSITIVE_INFINITY]
+ // It votes [minRefreshRate, Float.POSITIVE_INFINITY]
public static final int PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE = 3;
// APP_REQUEST_RENDER_FRAME_RATE_RANGE is used to for internal apps to limit the render
@@ -1376,10 +1377,10 @@
@VisibleForTesting
final class SettingsObserver extends ContentObserver {
- private final Uri mPeakRefreshRateSetting =
- Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
- private final Uri mMinRefreshRateSetting =
- Settings.System.getUriFor(Settings.System.MIN_REFRESH_RATE);
+ private final Uri mSmoothDisplaySetting =
+ Settings.System.getUriFor(Settings.System.SMOOTH_DISPLAY);
+ private final Uri mForcePeakRefreshRateSetting =
+ Settings.System.getUriFor(Settings.System.FORCE_PEAK_REFRESH_RATE);
private final Uri mLowPowerModeSetting =
Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE);
private final Uri mMatchContentFrameRateSetting =
@@ -1415,9 +1416,8 @@
public void observe() {
final ContentResolver cr = mContext.getContentResolver();
- mInjector.registerPeakRefreshRateObserver(cr, this);
- cr.registerContentObserver(mMinRefreshRateSetting, false /*notifyDescendants*/, this,
- UserHandle.USER_SYSTEM);
+ mInjector.registerSmoothDisplayObserver(cr, this);
+ mInjector.registerForcePeakRefreshRateObserver(cr, this);
cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this,
UserHandle.USER_SYSTEM);
cr.registerContentObserver(mMatchContentFrameRateSetting, false /*notifyDescendants*/,
@@ -1459,8 +1459,8 @@
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
synchronized (mLock) {
- if (mPeakRefreshRateSetting.equals(uri)
- || mMinRefreshRateSetting.equals(uri)) {
+ if (mSmoothDisplaySetting.equals(uri)
+ || mForcePeakRefreshRateSetting.equals(uri)) {
updateRefreshRateSettingLocked();
} else if (mLowPowerModeSetting.equals(uri)) {
updateLowPowerModeSettingLocked();
@@ -1515,12 +1515,9 @@
}
private void updateRefreshRateSettingLocked() {
- final ContentResolver cr = mContext.getContentResolver();
- float minRefreshRate = Settings.System.getFloatForUser(cr,
- Settings.System.MIN_REFRESH_RATE, 0f, cr.getUserId());
- float peakRefreshRate = Settings.System.getFloatForUser(cr,
- Settings.System.PEAK_REFRESH_RATE, mDefaultPeakRefreshRate, cr.getUserId());
- updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate);
+ updateRefreshRateSettingLocked(RefreshRateSettingsUtils.getMinRefreshRate(mContext),
+ RefreshRateSettingsUtils.getPeakRefreshRate(mContext, mDefaultPeakRefreshRate),
+ mDefaultRefreshRate);
}
private void updateRefreshRateSettingLocked(
@@ -1708,14 +1705,13 @@
}
public void observe() {
- DisplayManager dm = mContext.getSystemService(DisplayManager.class);
- dm.registerDisplayListener(this, mHandler);
+ mInjector.registerDisplayListener(this, mHandler);
// Populate existing displays
SparseArray<Display.Mode[]> modes = new SparseArray<>();
SparseArray<Display.Mode> defaultModes = new SparseArray<>();
DisplayInfo info = new DisplayInfo();
- Display[] displays = dm.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
+ Display[] displays = mInjector.getDisplays();
for (Display d : displays) {
final int displayId = d.getDisplayId();
d.getDisplayInfo(info);
@@ -1754,17 +1750,9 @@
updateLayoutLimitedFrameRate(displayId, displayInfo);
}
- @Nullable
private DisplayInfo getDisplayInfo(int displayId) {
- Display d = mContext.getSystemService(DisplayManager.class).getDisplay(displayId);
- if (d == null) {
- // We can occasionally get a display added or changed event for a display that was
- // subsequently removed, which means this returns null. Check this case and bail
- // out early; if it gets re-attached we'll eventually get another call back for it.
- return null;
- }
DisplayInfo info = new DisplayInfo();
- d.getDisplayInfo(info);
+ mInjector.getDisplayInfo(displayId, info);
return info;
}
@@ -2435,8 +2423,7 @@
}
private void updateDefaultDisplayState() {
- Display display = mContext.getSystemService(DisplayManager.class)
- .getDisplay(Display.DEFAULT_DISPLAY);
+ Display display = mInjector.getDisplay(Display.DEFAULT_DISPLAY);
if (display == null) {
return;
}
@@ -2753,8 +2740,7 @@
sensorManager.addProximityActiveListener(BackgroundThread.getExecutor(), this);
synchronized (mSensorObserverLock) {
- for (Display d : mDisplayManager.getDisplays(
- DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) {
+ for (Display d : mInjector.getDisplays()) {
mDozeStateByDisplay.put(d.getDisplayId(), mInjector.isDozeState(d));
}
}
@@ -2765,8 +2751,7 @@
}
private void recalculateVotesLocked() {
- final Display[] displays = mDisplayManager.getDisplays(
- DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
+ final Display[] displays = mInjector.getDisplays();
for (Display d : displays) {
int displayId = d.getDisplayId();
Vote vote = null;
@@ -2797,7 +2782,7 @@
@Override
public void onDisplayAdded(int displayId) {
- boolean isDozeState = mInjector.isDozeState(mDisplayManager.getDisplay(displayId));
+ boolean isDozeState = mInjector.isDozeState(mInjector.getDisplay(displayId));
synchronized (mSensorObserverLock) {
mDozeStateByDisplay.put(displayId, isDozeState);
recalculateVotesLocked();
@@ -2809,7 +2794,7 @@
boolean wasDozeState = mDozeStateByDisplay.get(displayId);
synchronized (mSensorObserverLock) {
mDozeStateByDisplay.put(displayId,
- mInjector.isDozeState(mDisplayManager.getDisplay(displayId)));
+ mInjector.isDozeState(mInjector.getDisplay(displayId)));
if (wasDozeState != mDozeStateByDisplay.get(displayId)) {
recalculateVotesLocked();
}
@@ -3165,17 +3150,27 @@
}
interface Injector {
- Uri PEAK_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
+ Uri SMOOTH_DISPLAY_URI = Settings.System.getUriFor(Settings.System.SMOOTH_DISPLAY);
+ Uri FORCE_PEAK_REFRESH_RATE_URI =
+ Settings.System.getUriFor(Settings.System.FORCE_PEAK_REFRESH_RATE);
@NonNull
DeviceConfigInterface getDeviceConfig();
- void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
+ void registerSmoothDisplayObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer);
+
+ void registerForcePeakRefreshRateObserver(@NonNull ContentResolver cr,
@NonNull ContentObserver observer);
void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener,
+ Handler handler);
+
+ void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener,
Handler handler, long flags);
+ Display getDisplay(int displayId);
+
Display[] getDisplays();
boolean getDisplayInfo(int displayId, DisplayInfo displayInfo);
@@ -3205,19 +3200,37 @@
}
@Override
- public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
+ public void registerSmoothDisplayObserver(@NonNull ContentResolver cr,
@NonNull ContentObserver observer) {
- cr.registerContentObserver(PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/,
+ cr.registerContentObserver(SMOOTH_DISPLAY_URI, false /*notifyDescendants*/,
observer, UserHandle.USER_SYSTEM);
}
@Override
+ public void registerForcePeakRefreshRateObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer) {
+ cr.registerContentObserver(FORCE_PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/,
+ observer, UserHandle.USER_SYSTEM);
+ }
+
+ @Override
+ public void registerDisplayListener(DisplayManager.DisplayListener listener,
+ Handler handler) {
+ getDisplayManager().registerDisplayListener(listener, handler);
+ }
+
+ @Override
public void registerDisplayListener(DisplayManager.DisplayListener listener,
Handler handler, long flags) {
getDisplayManager().registerDisplayListener(listener, handler, flags);
}
@Override
+ public Display getDisplay(int displayId) {
+ return getDisplayManager().getDisplay(displayId);
+ }
+
+ @Override
public Display[] getDisplays() {
return getDisplayManager().getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
}
@@ -3225,10 +3238,13 @@
@Override
public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) {
Display display = getDisplayManager().getDisplay(displayId);
- if (display != null) {
- return display.getDisplayInfo(displayInfo);
+ if (display == null) {
+ // We can occasionally get a display added or changed event for a display that was
+ // subsequently removed, which means this returns null. Check this case and bail
+ // out early; if it gets re-attached we'll eventually get another call back for it.
+ return false;
}
- return false;
+ return display.getDisplayInfo(displayInfo);
}
@Override
diff --git a/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java b/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java
index c04735d..8a3b329 100644
--- a/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java
+++ b/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java
@@ -138,7 +138,7 @@
for (Display d : displays) {
final int displayId = d.getDisplayId();
d.getDisplayInfo(info);
- localMap.put(displayId, info.refreshRateThermalThrottling);
+ localMap.put(displayId, info.thermalRefreshRateThrottling);
}
synchronized (mThermalObserverLock) {
for (int i = 0; i < size; i++) {
@@ -154,7 +154,7 @@
DisplayInfo displayInfo = new DisplayInfo();
mInjector.getDisplayInfo(displayId, displayInfo);
SparseArray<SurfaceControl.RefreshRateRange> throttlingMap =
- displayInfo.refreshRateThermalThrottling;
+ displayInfo.thermalRefreshRateThrottling;
synchronized (mThermalObserverLock) {
mThermalThrottlingByDisplay.put(displayId, throttlingMap);
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index f733199..2460ce5 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -48,6 +48,7 @@
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.metrics.LogMaker;
+import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.UserHandle;
@@ -60,6 +61,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IntArray;
+import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -387,7 +389,8 @@
NotificationChannel channel = new NotificationChannel(
id, channelName, channelImportance);
if (forRestore) {
- channel.populateFromXmlForRestore(parser, mContext);
+ final boolean pkgInstalled = r.uid != UNKNOWN_UID;
+ channel.populateFromXmlForRestore(parser, pkgInstalled, mContext);
} else {
channel.populateFromXml(parser);
}
@@ -2412,6 +2415,21 @@
mRestoredWithoutUids.remove(unrestoredPackageKey(pkg, changeUserId));
synchronized (mPackagePreferences) {
mPackagePreferences.put(packagePreferencesKey(r.pkg, r.uid), r);
+
+ // Try to restore any unrestored sound resources
+ for (NotificationChannel channel : r.channels.values()) {
+ if (!channel.isSoundRestored()) {
+ Uri uri = channel.getSound();
+ Uri restoredUri = channel.restoreSoundUri(mContext, uri, true);
+ if (Settings.System.DEFAULT_NOTIFICATION_URI.equals(
+ restoredUri)) {
+ Log.w(TAG,
+ "Could not restore sound: " + uri + " for channel: "
+ + channel);
+ }
+ channel.setSound(restoredUri, channel.getAudioAttributes());
+ }
+ }
}
if (r.migrateToPm) {
try {
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index 064be7c..39cd888 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -745,6 +745,9 @@
applyPackageFilter(snapshot, remainingPredicate, result, remainingPkgSettings, sortTemp,
packageManagerService);
+ // Make sure the system server isn't in the result, because it can never be dexopted here.
+ result.removeIf(pkgSetting -> PLATFORM_PACKAGE_NAME.equals(pkgSetting.getPackageName()));
+
if (debug) {
Log.i(TAG, "Packages to be dexopted: " + packagesToString(result));
Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgSettings));
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index eea6720..ef7d413 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -24,6 +24,7 @@
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
import static com.android.server.LocalManagerRegistry.ManagerNotFoundException;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import android.accounts.IAccountManager;
import android.annotation.NonNull;
@@ -1954,6 +1955,8 @@
List<String> packageNames = null;
if (allPackages) {
packageNames = mInterface.getAllPackages();
+ // Compiling the system server is only supported from odrefresh, so skip it.
+ packageNames.removeIf(packageName -> PLATFORM_PACKAGE_NAME.equals(packageName));
} else {
String packageName = getNextArg();
if (packageName == null) {
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 85c601f..dbd9e4b 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -107,6 +107,12 @@
private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE;
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
+ private static final int MAX_RAPID_ACTIVITY_LAUNCH_COUNT = 500;
+ private static final long RAPID_ACTIVITY_LAUNCH_MS = 300;
+ private static final long RESET_RAPID_ACTIVITY_LAUNCH_MS = 5 * RAPID_ACTIVITY_LAUNCH_MS;
+
+ private int mRapidActivityLaunchCount;
+
// all about the first app in the process
final ApplicationInfo mInfo;
final String mName;
@@ -538,7 +544,8 @@
return mLastActivityLaunchTime > 0;
}
- void setLastActivityLaunchTime(long launchTime) {
+ void setLastActivityLaunchTime(ActivityRecord r) {
+ long launchTime = r.lastLaunchTime;
if (launchTime <= mLastActivityLaunchTime) {
if (launchTime < mLastActivityLaunchTime) {
Slog.w(TAG,
@@ -547,9 +554,29 @@
}
return;
}
+ updateRapidActivityLaunch(r, launchTime, mLastActivityLaunchTime);
mLastActivityLaunchTime = launchTime;
}
+ void updateRapidActivityLaunch(ActivityRecord r, long launchTime, long lastLaunchTime) {
+ if (mInstrumenting || mDebugging || lastLaunchTime <= 0) {
+ return;
+ }
+
+ final long diff = lastLaunchTime - launchTime;
+ if (diff < RAPID_ACTIVITY_LAUNCH_MS) {
+ mRapidActivityLaunchCount++;
+ } else if (diff >= RESET_RAPID_ACTIVITY_LAUNCH_MS) {
+ mRapidActivityLaunchCount = 0;
+ }
+
+ if (mRapidActivityLaunchCount > MAX_RAPID_ACTIVITY_LAUNCH_COUNT) {
+ Slog.w(TAG, "Killing " + mPid + " because of rapid activity launch");
+ r.getRootTask().moveTaskToBack(r.getTask());
+ mAtm.mH.post(() -> mAtm.mAmInternal.killProcess(mName, mUid, "rapidActivityLaunch"));
+ }
+ }
+
void setLastActivityFinishTimeIfNeeded(long finishTime) {
if (finishTime <= mLastActivityFinishTime || !hasActivityInVisibleTask()) {
return;
@@ -696,7 +723,7 @@
void addActivityIfNeeded(ActivityRecord r) {
// even if we already track this activity, note down that it has been launched
- setLastActivityLaunchTime(r.lastLaunchTime);
+ setLastActivityLaunchTime(r);
if (mActivities.contains(r)) {
return;
}
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 981844c..f96ca58 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -153,12 +153,6 @@
<xs:annotation name="nullable"/>
<xs:annotation name="final"/>
</xs:element>
- <!-- The highest (most severe) thermal status at which high-brightness-mode is allowed
- to operate. -->
- <xs:element name="thermalStatusLimit" type="thermalStatus" minOccurs="0" maxOccurs="1">
- <xs:annotation name="nonnull"/>
- <xs:annotation name="final"/>
- </xs:element>
<xs:element name="allowInLowPowerMode" type="xs:boolean" minOccurs="0" maxOccurs="1">
<xs:annotation name="nonnull"/>
<xs:annotation name="final"/>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index 8cb4837..ad6434e 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -156,7 +156,6 @@
method @NonNull public final java.math.BigDecimal getMinimumLux_all();
method @Nullable public final com.android.server.display.config.RefreshRateRange getRefreshRate_all();
method @Nullable public final com.android.server.display.config.SdrHdrRatioMap getSdrHdrRatioMap_all();
- method @NonNull public final com.android.server.display.config.ThermalStatus getThermalStatusLimit_all();
method public com.android.server.display.config.HbmTiming getTiming_all();
method @NonNull public final java.math.BigDecimal getTransitionPoint_all();
method public final void setAllowInLowPowerMode_all(@NonNull boolean);
@@ -165,7 +164,6 @@
method public final void setMinimumLux_all(@NonNull java.math.BigDecimal);
method public final void setRefreshRate_all(@Nullable com.android.server.display.config.RefreshRateRange);
method public final void setSdrHdrRatioMap_all(@Nullable com.android.server.display.config.SdrHdrRatioMap);
- method public final void setThermalStatusLimit_all(@NonNull com.android.server.display.config.ThermalStatus);
method public void setTiming_all(com.android.server.display.config.HbmTiming);
method public final void setTransitionPoint_all(@NonNull java.math.BigDecimal);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 4d739d2..f6bc93a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5865,8 +5865,7 @@
// would allow bypassing of the maximum time to lock.
mInjector.settingsGlobalPutInt(Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
}
- getPowerManagerInternal().setMaximumScreenOffTimeoutFromDeviceAdmin(
- UserHandle.USER_SYSTEM, timeMs);
+ getPowerManagerInternal().setMaximumScreenOffTimeoutFromDeviceAdmin(parentId, timeMs);
});
}
@@ -9199,9 +9198,15 @@
MANAGE_DEVICE_POLICY_CAMERA,
caller.getPackageName(),
getProfileParentUserIfRequested(userId, parent));
-
- setBackwardCompatibleUserRestriction(
- caller, enforcingAdmin, UserManager.DISALLOW_CAMERA, disabled, parent);
+ try {
+ setBackwardCompatibleUserRestriction(
+ caller, enforcingAdmin, UserManager.DISALLOW_CAMERA, disabled, parent);
+ } catch (IllegalStateException e) {
+ throw new IllegalStateException(
+ "Please use addUserRestriction or addUserRestrictionGlobally using the key"
+ + " UserManager.DISALLOW_CAMERA to disable the camera locally or"
+ + " globally, respectively");
+ }
} else {
Objects.requireNonNull(who, "ComponentName is null");
if (parent) {
@@ -15465,11 +15470,13 @@
int userId = caller.getUserId();
synchronized (getLockObject()) {
- Preconditions.checkCallAuthorization(isUserAffiliatedWithDeviceLocked(userId),
- "Admin " + who
- + " is neither the device owner or affiliated user's profile owner.");
- if (isManagedProfile(userId)) {
- throw new SecurityException("Managed profile cannot disable status bar");
+ if (!isPermissionCheckFlagEnabled()) {
+ Preconditions.checkCallAuthorization(isUserAffiliatedWithDeviceLocked(userId),
+ "Admin " + who + " is neither the device owner or affiliated "
+ + "user's profile owner.");
+ if (isManagedProfile(userId)) {
+ throw new SecurityException("Managed profile cannot disable status bar");
+ }
}
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_STATUS_BAR_DISABLED);
@@ -15522,16 +15529,23 @@
@Override
public boolean isStatusBarDisabled(String callerPackage) {
final CallerIdentity caller = getCallerIdentity(callerPackage);
- Preconditions.checkCallAuthorization(
- isProfileOwner(caller) || isDefaultDeviceOwner(caller));
+ if (isPermissionCheckFlagEnabled()) {
+ enforceCanQuery(
+ MANAGE_DEVICE_POLICY_STATUS_BAR, caller.getPackageName(), caller.getUserId());
+ } else {
+ Preconditions.checkCallAuthorization(
+ isProfileOwner(caller) || isDefaultDeviceOwner(caller));
+ }
int userId = caller.getUserId();
synchronized (getLockObject()) {
- Preconditions.checkCallAuthorization(isUserAffiliatedWithDeviceLocked(userId),
- "Admin " + callerPackage
- + " is neither the device owner or affiliated user's profile owner.");
- if (isManagedProfile(userId)) {
- throw new SecurityException("Managed profile cannot disable status bar");
+ if (!isPermissionCheckFlagEnabled()) {
+ Preconditions.checkCallAuthorization(isUserAffiliatedWithDeviceLocked(userId),
+ "Admin " + callerPackage
+ + " is neither the device owner or affiliated user's profile owner.");
+ if (isManagedProfile(userId)) {
+ throw new SecurityException("Managed profile cannot disable status bar");
+ }
}
DevicePolicyData policy = getUserData(userId);
return policy.mStatusBarDisabled;
@@ -22753,6 +22767,7 @@
MANAGE_DEVICE_POLICY_AUTOFILL,
MANAGE_DEVICE_POLICY_BLUETOOTH,
MANAGE_DEVICE_POLICY_CALLS,
+ MANAGE_DEVICE_POLICY_CAMERA,
MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
MANAGE_DEVICE_POLICY_DISPLAY,
MANAGE_DEVICE_POLICY_FACTORY_RESET,
@@ -22788,7 +22803,6 @@
MANAGE_DEVICE_POLICY_ACROSS_USERS,
MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
MANAGE_DEVICE_POLICY_APPS_CONTROL,
- MANAGE_DEVICE_POLICY_CAMERA,
MANAGE_DEVICE_POLICY_CERTIFICATES,
MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE,
MANAGE_DEVICE_POLICY_DEFAULT_SMS,
@@ -22816,7 +22830,6 @@
private static final List<String> ADDITIONAL_PROFILE_OWNER_ON_USER_0_PERMISSIONS =
List.of(
MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
- MANAGE_DEVICE_POLICY_CAMERA,
MANAGE_DEVICE_POLICY_DISPLAY,
MANAGE_DEVICE_POLICY_FUN,
MANAGE_DEVICE_POLICY_LOCK_TASK,
@@ -22827,7 +22840,6 @@
MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
MANAGE_DEVICE_POLICY_SAFE_BOOT,
MANAGE_DEVICE_POLICY_SMS,
- MANAGE_DEVICE_POLICY_STATUS_BAR,
MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS,
MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
MANAGE_DEVICE_POLICY_USERS,
@@ -22848,7 +22860,9 @@
* All the additional permissions granted to a Profile Owner on an affiliated user.
*/
private static final List<String> ADDITIONAL_AFFILIATED_PROFILE_OWNER_ON_USER_PERMISSIONS =
- List.of();
+ List.of(
+ MANAGE_DEVICE_POLICY_STATUS_BAR
+ );
/**
* Combination of {@link PROFILE_OWNER_PERMISSIONS} and
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java b/services/tests/mockingservicestests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java
new file mode 100644
index 0000000..17fba9f
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2023 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.server.display;
+
+import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+import android.hardware.display.DisplayManager;
+import android.provider.Settings;
+import android.testing.TestableContext;
+import android.view.Display;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.display.RefreshRateSettingsUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RefreshRateSettingsUtilsTest {
+
+ @Rule
+ public final TestableContext mContext = new TestableContext(
+ InstrumentationRegistry.getInstrumentation().getContext());
+
+ @Mock
+ private DisplayManager mDisplayManagerMock;
+ @Mock
+ private Display mDisplayMock;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext.addMockSystemService(DisplayManager.class, mDisplayManagerMock);
+
+ Display.Mode[] modes = new Display.Mode[] {
+ new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+ /* refreshRate= */ 60),
+ new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+ /* refreshRate= */ 120),
+ new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+ /* refreshRate= */ 90)
+ };
+
+ when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
+ when(mDisplayMock.getSupportedModes()).thenReturn(modes);
+ }
+
+ @Test
+ public void testFindHighestRefreshRateForDefaultDisplay() {
+ when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null);
+ assertEquals(DEFAULT_REFRESH_RATE,
+ RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
+ /* delta= */ 0);
+
+ when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
+ assertEquals(120,
+ RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
+ /* delta= */ 0);
+ }
+
+ @Test
+ public void testGetMinRefreshRate() {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.FORCE_PEAK_REFRESH_RATE, -1);
+ assertEquals(0, RefreshRateSettingsUtils.getMinRefreshRate(mContext), /* delta= */ 0);
+
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.FORCE_PEAK_REFRESH_RATE, 0);
+ assertEquals(0, RefreshRateSettingsUtils.getMinRefreshRate(mContext), /* delta= */ 0);
+
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.FORCE_PEAK_REFRESH_RATE, 1);
+ assertEquals(120, RefreshRateSettingsUtils.getMinRefreshRate(mContext), /* delta= */ 0);
+ }
+
+ @Test
+ public void testGetPeakRefreshRate() {
+ float defaultPeakRefreshRate = 100;
+
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.SMOOTH_DISPLAY, -1);
+ assertEquals(defaultPeakRefreshRate,
+ RefreshRateSettingsUtils.getPeakRefreshRate(mContext, defaultPeakRefreshRate),
+ /* delta= */ 0);
+
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.SMOOTH_DISPLAY, 0);
+ assertEquals(DEFAULT_REFRESH_RATE,
+ RefreshRateSettingsUtils.getPeakRefreshRate(mContext, defaultPeakRefreshRate),
+ /* delta= */ 0);
+
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.SMOOTH_DISPLAY, 1);
+ assertEquals(120,
+ RefreshRateSettingsUtils.getPeakRefreshRate(mContext, defaultPeakRefreshRate),
+ /* delta= */ 0);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 16aadac..d85db64b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3267,31 +3267,31 @@
reset(getServices().settings);
dpm.setMaximumTimeToLock(admin1, 0);
- verifyScreenTimeoutCall(null, UserHandle.USER_SYSTEM);
+ verifyScreenTimeoutCall(null, CALLER_USER_HANDLE);
verifyStayOnWhilePluggedCleared(false);
reset(getServices().powerManagerInternal);
reset(getServices().settings);
dpm.setMaximumTimeToLock(admin1, 1);
- verifyScreenTimeoutCall(1L, UserHandle.USER_SYSTEM);
+ verifyScreenTimeoutCall(1L, CALLER_USER_HANDLE);
verifyStayOnWhilePluggedCleared(true);
reset(getServices().powerManagerInternal);
reset(getServices().settings);
dpm.setMaximumTimeToLock(admin2, 10);
- verifyScreenTimeoutCall(null, UserHandle.USER_SYSTEM);
+ verifyScreenTimeoutCall(null, CALLER_USER_HANDLE);
verifyStayOnWhilePluggedCleared(false);
reset(getServices().powerManagerInternal);
reset(getServices().settings);
dpm.setMaximumTimeToLock(admin1, 5);
- verifyScreenTimeoutCall(5L, UserHandle.USER_SYSTEM);
+ verifyScreenTimeoutCall(5L, CALLER_USER_HANDLE);
verifyStayOnWhilePluggedCleared(true);
reset(getServices().powerManagerInternal);
reset(getServices().settings);
dpm.setMaximumTimeToLock(admin2, 4);
- verifyScreenTimeoutCall(4L, UserHandle.USER_SYSTEM);
+ verifyScreenTimeoutCall(4L, CALLER_USER_HANDLE);
verifyStayOnWhilePluggedCleared(true);
reset(getServices().powerManagerInternal);
reset(getServices().settings);
@@ -3301,20 +3301,20 @@
reset(getServices().settings);
dpm.setMaximumTimeToLock(admin2, Long.MAX_VALUE);
- verifyScreenTimeoutCall(Long.MAX_VALUE, UserHandle.USER_SYSTEM);
+ verifyScreenTimeoutCall(Long.MAX_VALUE, CALLER_USER_HANDLE);
verifyStayOnWhilePluggedCleared(true);
reset(getServices().powerManagerInternal);
reset(getServices().settings);
dpm.setMaximumTimeToLock(admin2, 10);
- verifyScreenTimeoutCall(10L, UserHandle.USER_SYSTEM);
+ verifyScreenTimeoutCall(10L, CALLER_USER_HANDLE);
verifyStayOnWhilePluggedCleared(true);
reset(getServices().powerManagerInternal);
reset(getServices().settings);
// There's no restriction; should be set to MAX.
dpm.setMaximumTimeToLock(admin2, 0);
- verifyScreenTimeoutCall(Long.MAX_VALUE, UserHandle.USER_SYSTEM);
+ verifyScreenTimeoutCall(Long.MAX_VALUE, CALLER_USER_HANDLE);
verifyStayOnWhilePluggedCleared(false);
}
diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
index 3b10db4..e2a66f0 100644
--- a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
@@ -16,8 +16,6 @@
package com.android.server.display;
-import static android.hardware.display.BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
-import static android.hardware.display.BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL;
import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR;
import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT;
@@ -29,6 +27,8 @@
import static com.android.server.display.HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.anyFloat;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
@@ -39,14 +39,10 @@
import android.content.Context;
import android.content.ContextWrapper;
+import android.hardware.display.BrightnessInfo;
import android.os.Binder;
import android.os.Handler;
-import android.os.IThermalEventListener;
-import android.os.IThermalService;
import android.os.Message;
-import android.os.PowerManager;
-import android.os.Temperature;
-import android.os.Temperature.ThrottlingStatus;
import android.os.test.TestLooper;
import android.test.mock.MockContentResolver;
import android.util.MathUtils;
@@ -66,8 +62,6 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -80,7 +74,6 @@
private static final long TIME_WINDOW_MILLIS = 55 * 1000;
private static final long TIME_ALLOWED_IN_WINDOW_MILLIS = 12 * 1000;
private static final long TIME_MINIMUM_AVAILABLE_TO_ENABLE_MILLIS = 5 * 1000;
- private static final int THERMAL_STATUS_LIMIT = PowerManager.THERMAL_STATUS_SEVERE;
private static final boolean ALLOW_IN_LOW_POWER_MODE = false;
private static final float DEFAULT_MIN = 0.01f;
@@ -102,17 +95,13 @@
@Rule
public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
- @Mock IThermalService mThermalServiceMock;
@Mock Injector mInjectorMock;
@Mock HighBrightnessModeController.HdrBrightnessDeviceConfig mHdrBrightnessDeviceConfigMock;
- @Captor ArgumentCaptor<IThermalEventListener> mThermalEventListenerCaptor;
-
private static final HighBrightnessModeData DEFAULT_HBM_DATA =
new HighBrightnessModeData(MINIMUM_LUX, TRANSITION_POINT, TIME_WINDOW_MILLIS,
TIME_ALLOWED_IN_WINDOW_MILLIS, TIME_MINIMUM_AVAILABLE_TO_ENABLE_MILLIS,
- THERMAL_STATUS_LIMIT, ALLOW_IN_LOW_POWER_MODE,
- HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT);
+ ALLOW_IN_LOW_POWER_MODE, HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT);
@Before
public void setUp() {
@@ -125,8 +114,6 @@
mContextSpy = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
when(mContextSpy.getContentResolver()).thenReturn(resolver);
-
- when(mInjectorMock.getThermalService()).thenReturn(mThermalServiceMock);
}
/////////////////
@@ -321,34 +308,14 @@
}
@Test
- public void testNoHbmInHighThermalState() throws Exception {
+ public void testHbmIsNotTurnedOffInHighThermalState() throws Exception {
final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
- verify(mThermalServiceMock).registerThermalEventListenerWithType(
- mThermalEventListenerCaptor.capture(), eq(Temperature.TYPE_SKIN));
- final IThermalEventListener listener = mThermalEventListenerCaptor.getValue();
+ // Disabled thermal throttling
+ hbmc.onBrightnessChanged(/*brightness=*/ 1f, /*unthrottledBrightness*/ 1f,
+ BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE);
- // Set the thermal status too high.
- listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_CRITICAL));
-
- // Try to go into HBM mode but fail
- hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
- hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
- advanceTime(10);
-
- assertEquals(HIGH_BRIGHTNESS_MODE_OFF, hbmc.getHighBrightnessMode());
- }
-
- @Test
- public void testHbmTurnsOffInHighThermalState() throws Exception {
- final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
-
- verify(mThermalServiceMock).registerThermalEventListenerWithType(
- mThermalEventListenerCaptor.capture(), eq(Temperature.TYPE_SKIN));
- final IThermalEventListener listener = mThermalEventListenerCaptor.getValue();
-
- // Set the thermal status tolerable
- listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_LIGHT));
+ assertFalse(hbmc.isThermalThrottlingActive());
// Try to go into HBM mode
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
@@ -357,15 +324,19 @@
assertEquals(HIGH_BRIGHTNESS_MODE_SUNLIGHT, hbmc.getHighBrightnessMode());
- // Set the thermal status too high and verify we're off.
- listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_CRITICAL));
+ // Enable thermal throttling
+ hbmc.onBrightnessChanged(/*brightness=*/ TRANSITION_POINT - 0.01f,
+ /*unthrottledBrightness*/ 1f, BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL);
advanceTime(10);
- assertEquals(HIGH_BRIGHTNESS_MODE_OFF, hbmc.getHighBrightnessMode());
+ assertEquals(HIGH_BRIGHTNESS_MODE_SUNLIGHT, hbmc.getHighBrightnessMode());
+ assertTrue(hbmc.isThermalThrottlingActive());
- // Set the thermal status low again and verify we're back on.
- listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_SEVERE));
+ // Disabled thermal throttling
+ hbmc.onBrightnessChanged(/*brightness=*/ 1f, /*unthrottledBrightness*/ 1f,
+ BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE);
advanceTime(1);
assertEquals(HIGH_BRIGHTNESS_MODE_SUNLIGHT, hbmc.getHighBrightnessMode());
+ assertFalse(hbmc.isThermalThrottlingActive());
}
@Test
@@ -578,33 +549,6 @@
anyInt());
}
- // Test reporting of thermal throttling when triggered by HighBrightnessModeController's
- // internal thermal throttling.
- @Test
- public void testHbmStats_InternalThermalOff() throws Exception {
- final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
- final int displayStatsId = mDisplayUniqueId.hashCode();
-
- verify(mThermalServiceMock).registerThermalEventListenerWithType(
- mThermalEventListenerCaptor.capture(), eq(Temperature.TYPE_SKIN));
- final IThermalEventListener thermListener = mThermalEventListenerCaptor.getValue();
-
- hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
- hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
- hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT + 0.01f);
- advanceTime(1);
- verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
-
- thermListener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_CRITICAL));
- advanceTime(10);
- assertEquals(HIGH_BRIGHTNESS_MODE_OFF, hbmc.getHighBrightnessMode());
- verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_THERMAL_LIMIT));
- }
-
// Test reporting of thermal throttling when triggered externally through
// HighBrightnessModeController.onBrightnessChanged()
@Test
@@ -617,14 +561,16 @@
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
// Brightness is unthrottled, HBM brightness granted
- hbmc.onBrightnessChanged(hbmBrightness, hbmBrightness, BRIGHTNESS_MAX_REASON_NONE);
+ hbmc.onBrightnessChanged(hbmBrightness, hbmBrightness,
+ BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE);
advanceTime(1);
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
// Brightness is thermally throttled, HBM brightness denied (NBM brightness granted)
- hbmc.onBrightnessChanged(nbmBrightness, hbmBrightness, BRIGHTNESS_MAX_REASON_THERMAL);
+ hbmc.onBrightnessChanged(nbmBrightness, hbmBrightness,
+ BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL);
advanceTime(1);
// We expect HBM mode to remain set to sunlight, indicating that HBMC *allows* this mode.
// However, we expect the HBM state reported by HBMC to be off, since external thermal
@@ -784,11 +730,7 @@
mTestLooper.dispatchAll();
}
- private Temperature getSkinTemp(@ThrottlingStatus int status) {
- return new Temperature(30.0f, Temperature.TYPE_SKIN, "test_skin_temp", status);
- }
-
private void hbmcOnBrightnessChanged(HighBrightnessModeController hbmc, float brightness) {
- hbmc.onBrightnessChanged(brightness, brightness, BRIGHTNESS_MAX_REASON_NONE);
+ hbmc.onBrightnessChanged(brightness, brightness, BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
index ff89be7..5ea3029 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
@@ -17,6 +17,8 @@
package com.android.server.display;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
@@ -26,6 +28,7 @@
import android.app.PropertyInvalidatedCache;
import android.graphics.Point;
+import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.Surface;
@@ -47,6 +50,7 @@
private static final int LAYER_STACK = 0;
private static final int DISPLAY_WIDTH = 100;
private static final int DISPLAY_HEIGHT = 200;
+ private static final int MODE_ID = 1;
private LogicalDisplay mLogicalDisplay;
private DisplayDevice mDisplayDevice;
@@ -65,6 +69,9 @@
mDisplayDeviceInfo.height = DISPLAY_HEIGHT;
mDisplayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
mDisplayDeviceInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
+ mDisplayDeviceInfo.modeId = MODE_ID;
+ mDisplayDeviceInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID,
+ DISPLAY_WIDTH, DISPLAY_HEIGHT, /* refreshRate= */ 60)};
when(mDisplayDevice.getDisplayDeviceInfoLocked()).thenReturn(mDisplayDeviceInfo);
// Disable binder caches in this process.
@@ -168,14 +175,34 @@
}
@Test
- public void testLayoutLimitedRefreshRateNotClearedAfterUpdate() {
- SurfaceControl.RefreshRateRange refreshRateRange = new SurfaceControl.RefreshRateRange(1,
- 2);
- mLogicalDisplay.updateLayoutLimitedRefreshRateLocked(refreshRateRange);
- mLogicalDisplay.updateDisplayGroupIdLocked(1);
+ public void testUpdateLayoutLimitedRefreshRate() {
+ SurfaceControl.RefreshRateRange layoutLimitedRefreshRate =
+ new SurfaceControl.RefreshRateRange(0, 120);
+ DisplayInfo info1 = mLogicalDisplay.getDisplayInfoLocked();
+ mLogicalDisplay.updateLayoutLimitedRefreshRateLocked(layoutLimitedRefreshRate);
+ DisplayInfo info2 = mLogicalDisplay.getDisplayInfoLocked();
+ // Display info should only be updated when updateLocked is called
+ assertEquals(info2, info1);
- DisplayInfo result = mLogicalDisplay.getDisplayInfoLocked();
+ mLogicalDisplay.updateLocked(mDeviceRepo);
+ DisplayInfo info3 = mLogicalDisplay.getDisplayInfoLocked();
+ assertNotEquals(info3, info2);
+ assertEquals(layoutLimitedRefreshRate, info3.layoutLimitedRefreshRate);
+ }
- assertEquals(refreshRateRange, result.layoutLimitedRefreshRate);
+ @Test
+ public void testUpdateRefreshRateThermalThrottling() {
+ SparseArray<SurfaceControl.RefreshRateRange> refreshRanges = new SparseArray<>();
+ refreshRanges.put(0, new SurfaceControl.RefreshRateRange(0, 120));
+ DisplayInfo info1 = mLogicalDisplay.getDisplayInfoLocked();
+ mLogicalDisplay.updateThermalRefreshRateThrottling(refreshRanges);
+ DisplayInfo info2 = mLogicalDisplay.getDisplayInfoLocked();
+ // Display info should only be updated when updateLocked is called
+ assertEquals(info2, info1);
+
+ mLogicalDisplay.updateLocked(mDeviceRepo);
+ DisplayInfo info3 = mLogicalDisplay.getDisplayInfoLocked();
+ assertNotEquals(info3, info2);
+ assertTrue(refreshRanges.contentEquals(info3.thermalRefreshRateThrottling));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
index 6907145..4cfcee5 100644
--- a/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
@@ -84,6 +84,7 @@
import com.android.internal.R;
import com.android.internal.display.BrightnessSynchronizer;
+import com.android.internal.display.RefreshRateSettingsUtils;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.Preconditions;
import com.android.internal.util.test.FakeSettingsProvider;
@@ -126,7 +127,8 @@
private static final String TAG = "DisplayModeDirectorTest";
private static final boolean DEBUG = false;
private static final float FLOAT_TOLERANCE = 0.01f;
- private static final int DISPLAY_ID = 0;
+ private static final int DISPLAY_ID = Display.DEFAULT_DISPLAY;
+ private static final int MODE_ID = 1;
private static final float TRANSITION_POINT = 0.763f;
private static final float HBM_TRANSITION_POINT_INVALID = Float.POSITIVE_INFINITY;
@@ -158,6 +160,9 @@
LocalServices.addService(SensorManagerInternal.class, mSensorManagerInternalMock);
LocalServices.removeServiceForTest(DisplayManagerInternal.class);
LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock);
+
+ clearSmoothDisplaySetting();
+ clearForcePeakRefreshRateSetting();
}
private DisplayModeDirector createDirectorFromRefreshRateArray(
@@ -919,7 +924,6 @@
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);
@@ -927,6 +931,7 @@
config.setRefreshRateInLowZone(90);
config.setLowDisplayBrightnessThresholds(new int[] { 10 });
config.setLowAmbientBrightnessThresholds(new int[] { 20 });
+ config.setDefaultPeakRefreshRate(90);
Sensor lightSensor = createLightSensor();
SensorManager sensorManager = createMockSensorManager(lightSensor);
@@ -977,7 +982,6 @@
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);
@@ -985,6 +989,7 @@
config.setRefreshRateInHighZone(60);
config.setHighDisplayBrightnessThresholds(new int[] { 255 });
config.setHighAmbientBrightnessThresholds(new int[] { 8000 });
+ config.setDefaultPeakRefreshRate(90);
Sensor lightSensor = createLightSensor();
SensorManager sensorManager = createMockSensorManager(lightSensor);
@@ -1032,16 +1037,123 @@
}
@Test
+ public void testSmoothDisplay() {
+ float defaultRefreshRate = 60;
+ int defaultPeakRefreshRate = 100;
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+ director.getSettingsObserver().setDefaultRefreshRate(defaultRefreshRate);
+ director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+
+ final FakeDeviceConfig config = mInjector.getDeviceConfig();
+ config.setDefaultPeakRefreshRate(defaultPeakRefreshRate);
+
+ Sensor lightSensor = createLightSensor();
+ SensorManager sensorManager = createMockSensorManager(lightSensor);
+ director.start(sensorManager);
+
+ // Default value of the setting
+
+ Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
+ defaultPeakRefreshRate);
+ vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
+ Float.POSITIVE_INFINITY);
+ vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
+ defaultRefreshRate);
+
+ setSmoothDisplayEnabled(false);
+
+ vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
+ RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE);
+ vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
+ Float.POSITIVE_INFINITY);
+ vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
+ defaultRefreshRate);
+
+ setSmoothDisplayEnabled(true);
+
+ vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
+ RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext));
+ vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
+ Float.POSITIVE_INFINITY);
+ vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
+ defaultRefreshRate);
+ }
+
+ @Test
+ public void testForcePeakRefreshRate() {
+ float defaultRefreshRate = 60;
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+ director.getSettingsObserver().setDefaultRefreshRate(defaultRefreshRate);
+ director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+
+ Sensor lightSensor = createLightSensor();
+ SensorManager sensorManager = createMockSensorManager(lightSensor);
+ director.start(sensorManager);
+
+ setForcePeakRefreshRateEnabled(false);
+ setSmoothDisplayEnabled(false);
+
+ Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
+ RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE);
+ vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0,
+ /* frameRateHigh= */ Float.POSITIVE_INFINITY);
+ vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
+ defaultRefreshRate);
+
+ setForcePeakRefreshRateEnabled(true);
+
+ vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
+ RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext));
+ vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */
+ RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
+ /* frameRateHigh= */ Float.POSITIVE_INFINITY);
+ vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
+ defaultRefreshRate);
+ }
+
+ @Test
public void testSensorRegistration() {
// First, configure brightness zones or DMD won't register for sensor data.
final FakeDeviceConfig config = mInjector.getDeviceConfig();
config.setRefreshRateInHighZone(60);
config.setHighDisplayBrightnessThresholds(new int[] { 255 });
config.setHighAmbientBrightnessThresholds(new int[] { 8000 });
+ config.setDefaultPeakRefreshRate(90);
DisplayModeDirector director =
createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
- setPeakRefreshRate(90 /*fps*/);
director.getSettingsObserver().setDefaultRefreshRate(90);
director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
@@ -2417,10 +2529,10 @@
config.setRefreshRateInHighZone(60);
config.setHighDisplayBrightnessThresholds(new int[] { 255 });
config.setHighAmbientBrightnessThresholds(new int[] { 8000 });
+ config.setDefaultPeakRefreshRate(90);
DisplayModeDirector director =
createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
- setPeakRefreshRate(90 /*fps*/);
director.getSettingsObserver().setDefaultRefreshRate(90);
director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
@@ -2533,6 +2645,33 @@
assertNull(vote);
}
+ @Test
+ public void testUpdateLayoutLimitedRefreshRate() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[]{60.0f, 90.0f}, 0);
+ director.start(createMockSensorManager());
+
+ ArgumentCaptor<DisplayListener> displayListenerCaptor =
+ ArgumentCaptor.forClass(DisplayListener.class);
+ verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(),
+ any(Handler.class));
+ DisplayListener displayListener = displayListenerCaptor.getValue();
+
+ float refreshRate = 60;
+ mInjector.mDisplayInfo.layoutLimitedRefreshRate =
+ new RefreshRateRange(refreshRate, refreshRate);
+ displayListener.onDisplayChanged(DISPLAY_ID);
+
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_LAYOUT_LIMITED_FRAME_RATE);
+ assertVoteForPhysicalRefreshRate(vote, /* refreshRate= */ refreshRate);
+
+ mInjector.mDisplayInfo.layoutLimitedRefreshRate = null;
+ displayListener.onDisplayChanged(DISPLAY_ID);
+
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_LAYOUT_LIMITED_FRAME_RATE);
+ assertNull(vote);
+ }
+
private Temperature getSkinTemp(@Temperature.ThrottlingStatus int status) {
return new Temperature(30.0f, Temperature.TYPE_SKIN, "test_skin_temp", status);
}
@@ -2671,10 +2810,30 @@
listener.onDisplayChanged(DISPLAY_ID);
}
- private void setPeakRefreshRate(float fps) {
- Settings.System.putFloat(mContext.getContentResolver(), Settings.System.PEAK_REFRESH_RATE,
- fps);
- mInjector.notifyPeakRefreshRateChanged();
+ private void setSmoothDisplayEnabled(boolean enabled) {
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.SMOOTH_DISPLAY,
+ enabled ? 1 : 0);
+ mInjector.notifySmoothDisplaySettingChanged();
+ waitForIdleSync();
+ }
+
+ private void clearSmoothDisplaySetting() {
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.SMOOTH_DISPLAY, -1);
+ mInjector.notifySmoothDisplaySettingChanged();
+ waitForIdleSync();
+ }
+
+ private void setForcePeakRefreshRateEnabled(boolean enabled) {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.FORCE_PEAK_REFRESH_RATE, enabled ? 1 : 0);
+ mInjector.notifyForcePeakRefreshRateSettingChanged();
+ waitForIdleSync();
+ }
+
+ private void clearForcePeakRefreshRateSetting() {
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.FORCE_PEAK_REFRESH_RATE, -1);
+ mInjector.notifySmoothDisplaySettingChanged();
waitForIdleSync();
}
@@ -2719,11 +2878,19 @@
public static class FakesInjector implements DisplayModeDirector.Injector {
private final FakeDeviceConfig mDeviceConfig;
+ private final DisplayInfo mDisplayInfo;
+ private final Display mDisplay;
private ContentObserver mBrightnessObserver;
- private ContentObserver mPeakRefreshRateObserver;
+ private ContentObserver mSmoothDisplaySettingObserver;
+ private ContentObserver mForcePeakRefreshRateSettingObserver;
FakesInjector() {
mDeviceConfig = new FakeDeviceConfig();
+ mDisplayInfo = new DisplayInfo();
+ mDisplayInfo.defaultModeId = MODE_ID;
+ mDisplayInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID,
+ 800, 600, /* refreshRate= */ 60)};
+ mDisplay = createDisplay(DISPLAY_ID);
}
@NonNull
@@ -2732,22 +2899,37 @@
}
@Override
- public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
+ public void registerSmoothDisplayObserver(@NonNull ContentResolver cr,
@NonNull ContentObserver observer) {
- mPeakRefreshRateObserver = observer;
+ mSmoothDisplaySettingObserver = observer;
}
@Override
+ public void registerForcePeakRefreshRateObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer) {
+ mForcePeakRefreshRateSettingObserver = observer;
+ }
+
+ @Override
+ public void registerDisplayListener(DisplayListener listener, Handler handler) {}
+
+ @Override
public void registerDisplayListener(DisplayListener listener, Handler handler, long flag) {}
@Override
+ public Display getDisplay(int displayId) {
+ return mDisplay;
+ }
+
+ @Override
public Display[] getDisplays() {
- return new Display[] { createDisplay(DISPLAY_ID) };
+ return new Display[] { mDisplay };
}
@Override
public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) {
- return false;
+ displayInfo.copyFrom(mDisplayInfo);
+ return true;
}
@Override
@@ -2771,14 +2953,21 @@
}
protected Display createDisplay(int id) {
- return new Display(DisplayManagerGlobal.getInstance(), id, new DisplayInfo(),
+ return new Display(DisplayManagerGlobal.getInstance(), id, mDisplayInfo,
ApplicationProvider.getApplicationContext().getResources());
}
- void notifyPeakRefreshRateChanged() {
- if (mPeakRefreshRateObserver != null) {
- mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,
- PEAK_REFRESH_RATE_URI);
+ void notifySmoothDisplaySettingChanged() {
+ if (mSmoothDisplaySettingObserver != null) {
+ mSmoothDisplaySettingObserver.dispatchChange(false /*selfChange*/,
+ SMOOTH_DISPLAY_URI);
+ }
+ }
+
+ void notifyForcePeakRefreshRateSettingChanged() {
+ if (mForcePeakRefreshRateSettingObserver != null) {
+ mForcePeakRefreshRateSettingObserver.dispatchChange(false /*selfChange*/,
+ FORCE_PEAK_REFRESH_RATE_URI);
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java b/services/tests/servicestests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java
index fd1889c..13540d6 100644
--- a/services/tests/servicestests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java
@@ -253,7 +253,7 @@
public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) {
SparseArray<SurfaceControl.RefreshRateRange> config = mOverriddenConfig.get(displayId);
if (config != null) {
- displayInfo.refreshRateThermalThrottling = config;
+ displayInfo.thermalRefreshRateThrottling = config;
return true;
}
return false;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 94f52bb..5dbc6ab 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -40,7 +40,6 @@
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MAX;
import static android.app.NotificationManager.IMPORTANCE_NONE;
-import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS;
import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
@@ -5312,7 +5311,7 @@
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(baos.toByteArray())), null);
NotificationChannel restored = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
- restored.populateFromXmlForRestore(parser, getContext());
+ restored.populateFromXmlForRestore(parser, true, getContext());
assertNull(restored.getSound());
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index f6d10b9..c78b03e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -140,6 +140,7 @@
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
@@ -170,6 +171,12 @@
Uri.parse("content://" + TEST_AUTHORITY
+ "/internal/audio/media/10?title=Test&canonical=1");
+ private static final Uri ANDROID_RES_SOUND_URI =
+ Uri.parse("android.resource://" + TEST_AUTHORITY + "/raw/test");
+
+ private static final Uri FILE_SOUND_URI =
+ Uri.parse("file://" + TEST_AUTHORITY + "/product/media/test.ogg");
+
@Mock PermissionHelper mPermissionHelper;
@Mock RankingHandler mHandler;
@Mock PackageManager mPm;
@@ -1338,6 +1345,57 @@
assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound());
}
+ /**
+ * Test sound Uri restore retry behavior when channel is restored before package
+ * and then package is installed.
+ */
+ @Test
+ public void testRestoreXml_withNonExistentCanonicalizedSoundUriAndMissingPackage()
+ throws Exception {
+ // canonicalization returns CANONICAL_SOUND_URI for getSoundForBackup (backup part)
+ doReturn(CANONICAL_SOUND_URI)
+ .when(mTestIContentProvider).canonicalize(any(), eq(SOUND_URI));
+
+ NotificationChannel channel =
+ new NotificationChannel("id", "name", IMPORTANCE_LOW);
+ channel.setSound(SOUND_URI, mAudioAttributes);
+ mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
+ USER_SYSTEM, channel.getId());
+
+ // canonicalization / uncanonicalization returns null for the restore part
+ doReturn(null)
+ .when(mTestIContentProvider).canonicalize(any(), eq(CANONICAL_SOUND_URI));
+ doReturn(null)
+ .when(mTestIContentProvider).uncanonicalize(any(), any());
+
+ // simulate package not installed
+ when(mPm.getPackageUidAsUser(PKG_N_MR1, USER_SYSTEM)).thenReturn(UNKNOWN_UID);
+ when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenThrow(
+ new PackageManager.NameNotFoundException());
+
+ loadStreamXml(baos, true, USER_SYSTEM);
+
+ // 1st restore pass fails
+ NotificationChannel actualChannel = mHelper.getNotificationChannel(
+ PKG_N_MR1, UNKNOWN_UID, channel.getId(), false);
+ // sound is CANONICAL_SOUND_URI, unchanged from backup
+ assertEquals(CANONICAL_SOUND_URI, actualChannel.getSound());
+ // sound is flagged as not restored
+ assertFalse(actualChannel.isSoundRestored());
+
+ // package is "installed"
+ when(mPm.getPackageUidAsUser(PKG_N_MR1, USER_SYSTEM)).thenReturn(UID_N_MR1);
+
+ // Trigger 2nd restore pass
+ mHelper.onPackagesChanged(false, USER_SYSTEM, new String[]{PKG_N_MR1},
+ new int[]{UID_N_MR1});
+
+ // sound is flagged as restored and set to default URI
+ assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound());
+ assertTrue(actualChannel.isSoundRestored());
+ }
+
/**
* Although we don't make backups with uncanonicalized uris anymore, we used to, so we have to
@@ -1363,7 +1421,9 @@
backupWithUncanonicalizedSoundUri.getBytes(), true, USER_SYSTEM);
NotificationChannel actualChannel = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, id, false);
+
assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound());
+ assertTrue(actualChannel.isSoundRestored());
}
@Test
@@ -1389,6 +1449,73 @@
}
@Test
+ public void testBackupRestoreXml_withAndroidResourceSoundUri() throws Exception {
+ // Mock ContentResolver.getResourceId:
+ // throw exception on restore 1st pass => simulate app not installed yet
+ // then return a valid resource on package update => sim. app installed
+ ContentResolver contentResolver = mock(ContentResolver.class);
+ when(mContext.getContentResolver()).thenReturn(contentResolver);
+ ContentResolver.OpenResourceIdResult resId = mock(
+ ContentResolver.OpenResourceIdResult.class);
+ when(contentResolver.getResourceId(ANDROID_RES_SOUND_URI)).thenReturn(resId).thenThrow(
+ new FileNotFoundException("")).thenReturn(resId);
+
+ mHelper = new PreferencesHelper(mContext, mPm, mHandler, mMockZenModeHelper,
+ mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false);
+
+ NotificationChannel channel =
+ new NotificationChannel("id", "name", IMPORTANCE_LOW);
+ channel.setSound(ANDROID_RES_SOUND_URI, mAudioAttributes);
+ mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
+ USER_SYSTEM, channel.getId());
+
+ // simulate package not installed
+ when(mPm.getPackageUidAsUser(PKG_N_MR1, USER_SYSTEM)).thenReturn(UNKNOWN_UID);
+ when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenThrow(
+ new PackageManager.NameNotFoundException());
+
+ loadStreamXml(baos, true, USER_SYSTEM);
+
+ NotificationChannel actualChannel = mHelper.getNotificationChannel(
+ PKG_N_MR1, UNKNOWN_UID, channel.getId(), false);
+ // sound is ANDROID_RES_SOUND_URI, unchanged from backup
+ assertEquals(ANDROID_RES_SOUND_URI, actualChannel.getSound());
+ // sound is flagged as not restored
+ assertFalse(actualChannel.isSoundRestored());
+
+ // package is "installed"
+ when(mPm.getPackageUidAsUser(PKG_N_MR1, USER_SYSTEM)).thenReturn(UID_N_MR1);
+
+ // Trigger 2nd restore pass
+ mHelper.onPackagesChanged(false, USER_SYSTEM, new String[]{PKG_N_MR1},
+ new int[]{UID_N_MR1});
+
+ // sound is flagged as restored
+ assertEquals(ANDROID_RES_SOUND_URI, actualChannel.getSound());
+ assertTrue(actualChannel.isSoundRestored());
+ }
+
+ @Test
+ public void testBackupRestoreXml_withFileResourceSoundUri() throws Exception {
+ NotificationChannel channel =
+ new NotificationChannel("id", "name", IMPORTANCE_LOW);
+ channel.setSound(FILE_SOUND_URI, mAudioAttributes);
+ mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
+ USER_SYSTEM, channel.getId());
+
+ loadStreamXml(baos, true, USER_SYSTEM);
+
+ NotificationChannel actualChannel = mHelper.getNotificationChannel(
+ PKG_N_MR1, UID_N_MR1, channel.getId(), false);
+ // sound is FILE_SOUND_URI, unchanged from backup
+ assertEquals(FILE_SOUND_URI, actualChannel.getSound());
+ // sound is flagged as restored
+ assertTrue(actualChannel.isSoundRestored());
+ }
+
+ @Test
public void testChannelXml_backup() throws Exception {
NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");