Merge "Accept touches within sensor bounds during ellipse detection" into udc-dev
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index 051dde0..b732da2 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -127,6 +127,7 @@
private BroadcastWaiter mBroadcastWaiter;
private UserSwitchWaiter mUserSwitchWaiter;
private String mUserSwitchTimeoutMs;
+ private String mDisableUserSwitchingDialogAnimations;
private final BenchmarkRunner mRunner = new BenchmarkRunner();
@Rule
@@ -153,16 +154,17 @@
Log.w(TAG, "WARNING: Tests are being run from user " + mAm.getCurrentUser()
+ " rather than the system user");
}
- mUserSwitchTimeoutMs = setSystemProperty("debug.usercontroller.user_switch_timeout_ms",
- "100000");
- if (TextUtils.isEmpty(mUserSwitchTimeoutMs)) {
- mUserSwitchTimeoutMs = "invalid";
- }
+ mUserSwitchTimeoutMs = setSystemProperty(
+ "debug.usercontroller.user_switch_timeout_ms", "100000");
+ mDisableUserSwitchingDialogAnimations = setSystemProperty(
+ "debug.usercontroller.disable_user_switching_dialog_animations", "true");
}
@After
public void tearDown() throws Exception {
setSystemProperty("debug.usercontroller.user_switch_timeout_ms", mUserSwitchTimeoutMs);
+ setSystemProperty("debug.usercontroller.disable_user_switching_dialog_animations",
+ mDisableUserSwitchingDialogAnimations);
mBroadcastWaiter.close();
mUserSwitchWaiter.close();
for (int userId : mUsersToRemove) {
@@ -1538,7 +1540,7 @@
private String setSystemProperty(String name, String value) throws Exception {
final String oldValue = ShellHelper.runShellCommand("getprop " + name);
assertEquals("", ShellHelper.runShellCommand("setprop " + name + " " + value));
- return oldValue;
+ return TextUtils.firstNotEmpty(oldValue, "invalid");
}
private void waitForBroadcastIdle() {
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/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index d62e15a..3249b41 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -174,6 +174,9 @@
ActivityTaskManager.RootTaskInfo getFocusedRootTaskInfo();
Rect getTaskBounds(int taskId);
+ /** Focuses the top task on a display if it isn't already focused. Used for Recents. */
+ void focusTopTask(int displayId);
+
void cancelRecentsAnimation(boolean restoreHomeRootTaskPosition);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES)")
void updateLockTaskPackages(int userId, in String[] packages);
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/hardware/camera2/impl/CameraExtensionJpegProcessor.java b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
index 7701125..875550a 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
@@ -46,6 +46,7 @@
public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl {
public final static String TAG = "CameraExtensionJpeg";
private final static int JPEG_QUEUE_SIZE = 1;
+ private final static int JPEG_APP_SEGMENT_SIZE = 64 * 1024;
private final Handler mHandler;
private final HandlerThread mHandlerThread;
@@ -243,9 +244,10 @@
private void initializePipeline() throws RemoteException {
if ((mFormat != -1) && (mOutputSurface != null) && (mResolution != null) &&
(mYuvReader == null)) {
- // Jpeg/blobs are expected to be configured with (w*h)x1
+ // Jpeg/blobs are expected to be configured with (w*h)x1.5 + 64k Jpeg APP1 segment
mOutputWriter = ImageWriter.newInstance(mOutputSurface, 1 /*maxImages*/,
- ImageFormat.JPEG, mResolution.width * mResolution.height, 1);
+ ImageFormat.JPEG,
+ (mResolution.width * mResolution.height * 3)/2 + JPEG_APP_SEGMENT_SIZE, 1);
mYuvReader = ImageReader.newInstance(mResolution.width, mResolution.height, mFormat,
JPEG_QUEUE_SIZE);
mYuvReader.setOnImageAvailableListener(
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/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java
index 82571db..e9bb28c 100644
--- a/core/java/android/service/dreams/DreamManagerInternal.java
+++ b/core/java/android/service/dreams/DreamManagerInternal.java
@@ -84,6 +84,19 @@
*
* @param keepDreaming True if the current dream should continue when undocking.
*/
- void onKeepDreamingWhenUnpluggingChanged(boolean keepDreaming);
+ default void onKeepDreamingWhenUnpluggingChanged(boolean keepDreaming) {
+ }
+
+ /**
+ * Called when dreaming has started.
+ */
+ default void onDreamingStarted() {
+ }
+
+ /**
+ * Called when dreaming has stopped.
+ */
+ default void onDreamingStopped() {
+ }
}
}
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/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index 77f3b1d..dd4f964 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.graphics.Rect;
import android.view.inputmethod.InputMethodManager;
+import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
@@ -305,6 +306,9 @@
mImm.startStylusHandwriting(view);
mState.mHasInitiatedHandwriting = true;
mState.mShouldInitHandwriting = false;
+ if (view instanceof TextView) {
+ ((TextView) view).hideHint();
+ }
}
/**
@@ -323,6 +327,9 @@
mState.mHasInitiatedHandwriting = true;
mState.mShouldInitHandwriting = false;
}
+ if (view instanceof TextView) {
+ ((TextView) view).hideHint();
+ }
return true;
}
return false;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index bc6a3b5..99deac4 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -220,6 +220,7 @@
long newParentNativeObject);
private static native void nativeSetBuffer(long transactionObj, long nativeObject,
HardwareBuffer buffer, long fencePtr, Consumer<SyncFence> releaseCallback);
+ private static native void nativeUnsetBuffer(long transactionObj, long nativeObject);
private static native void nativeSetBufferTransform(long transactionObj, long nativeObject,
int transform);
private static native void nativeSetDataSpace(long transactionObj, long nativeObject,
@@ -3664,6 +3665,22 @@
}
/**
+ * Unsets the buffer for the SurfaceControl in the current Transaction. This will not clear
+ * the buffer being rendered, but resets the buffer state in the Transaction only. The call
+ * will also invoke the release callback.
+ *
+ * Note, this call is different from passing a null buffer to
+ * {@link SurfaceControl.Transaction#setBuffer} which will release the last displayed
+ * buffer.
+ *
+ * @hide
+ */
+ public Transaction unsetBuffer(SurfaceControl sc) {
+ nativeUnsetBuffer(mNativeObject, sc.mNativeObject);
+ return this;
+ }
+
+ /**
* Updates the HardwareBuffer displayed for the SurfaceControl.
*
* Note that the buffer must be allocated with {@link HardwareBuffer#USAGE_COMPOSER_OVERLAY}
@@ -3682,7 +3699,8 @@
* until all presentation fences have signaled, ensuring the transaction remains consistent.
*
* @param sc The SurfaceControl to update
- * @param buffer The buffer to be displayed
+ * @param buffer The buffer to be displayed. Pass in a null buffer to release the last
+ * displayed buffer.
* @param fence The presentation fence. If null or invalid, this is equivalent to
* {@link #setBuffer(SurfaceControl, HardwareBuffer)}
* @return this
@@ -3846,14 +3864,14 @@
* 100 nits and a max display brightness of 200 nits, this should
* be set to 2.0f.
*
- * Default value is 1.0f.
+ * <p>Default value is 1.0f.
*
- * Transfer functions that encode their own brightness ranges,
+ * <p>Transfer functions that encode their own brightness ranges,
* such as HLG or PQ, should also set this to 1.0f and instead
* communicate extended content brightness information via
* metadata such as CTA861_3 or SMPTE2086.
*
- * Must be finite && >= 1.0f
+ * <p>Must be finite && >= 1.0f
*
* @param desiredRatio The desired hdr/sdr ratio. This can be used to communicate the max
* desired brightness range. This is similar to the "max luminance"
@@ -3862,13 +3880,17 @@
* may not be able to, or may choose not to, deliver the
* requested range.
*
- * If unspecified, the system will attempt to provide the best range
- * it can for the given ambient conditions & device state. However,
- * voluntarily reducing the requested range can help improve battery
- * life as well as can improve quality by ensuring greater bit depth
- * is allocated to the luminance range in use.
+ * <p>While requesting a large desired ratio will result in the most
+ * dynamic range, voluntarily reducing the requested range can help
+ * improve battery life as well as can improve quality by ensuring
+ * greater bit depth is allocated to the luminance range in use.
*
- * Must be finite && >= 1.0f
+ * <p>Default value is 1.0f and indicates that extended range brightness
+ * is not being used, so the resulting SDR or HDR behavior will be
+ * determined entirely by the dataspace being used (ie, typically SDR
+ * however PQ or HLG transfer functions will still result in HDR)
+ *
+ * <p>Must be finite && >= 1.0f
* @return this
**/
public @NonNull Transaction setExtendedRangeBrightness(@NonNull SurfaceControl sc,
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 6bd9538..c0ac04c 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -647,11 +647,18 @@
boolean mForceNextWindowRelayout;
CountDownLatch mWindowDrawCountDown;
- // Whether we have used applyTransactionOnDraw to schedule an RT
- // frame callback consuming a passed in transaction. In this case
- // we also need to schedule a commit callback so we can observe
- // if the draw was skipped, and the BBQ pending transactions.
+ /**
+ * Value to indicate whether someone has called {@link #applyTransactionOnDraw}before the
+ * traversal. This is used to determine whether a RT frame callback needs to be registered to
+ * merge the transaction with the next frame. The value is cleared after the VRI has run a
+ * traversal pass.
+ */
boolean mHasPendingTransactions;
+ /**
+ * The combined transactions passed in from {@link #applyTransactionOnDraw}
+ */
+ private Transaction mPendingTransaction = new Transaction();
+
boolean mIsDrawing;
int mLastSystemUiVisibility;
@@ -4548,9 +4555,13 @@
}
private void registerCallbackForPendingTransactions() {
+ Transaction t = new Transaction();
+ t.merge(mPendingTransaction);
+
registerRtFrameCallback(new FrameDrawingCallback() {
@Override
public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) {
+ mergeWithNextTransaction(t, frame);
if ((syncResult
& (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) {
mBlastBufferQueue.applyPendingTransactions(frame);
@@ -8780,6 +8791,9 @@
mActiveSurfaceSyncGroup.markSyncReady();
mActiveSurfaceSyncGroup = null;
}
+ if (mHasPendingTransactions) {
+ mPendingTransaction.apply();
+ }
WindowManagerGlobal.getInstance().doRemoveView(this);
}
@@ -11114,12 +11128,11 @@
} else {
// Copy and clear the passed in transaction for thread safety. The new transaction is
// accessed on the render thread.
- var localTransaction = new Transaction();
- localTransaction.merge(t);
+ mPendingTransaction.merge(t);
mHasPendingTransactions = true;
- registerRtFrameCallback(frame -> {
- mergeWithNextTransaction(localTransaction, frame);
- });
+ // Schedule the traversal to ensure there's an attempt to draw a frame and apply the
+ // pending transactions. This is also where the registerFrameCallback will be scheduled.
+ scheduleTraversals();
}
return true;
}
@@ -11260,6 +11273,10 @@
if (DEBUG_BLAST) {
Log.d(mTag, "registerCallbacksForSync syncBuffer=" + syncBuffer);
}
+
+ Transaction t = new Transaction();
+ t.merge(mPendingTransaction);
+
mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() {
@Override
public void onFrameDraw(long frame) {
@@ -11273,6 +11290,7 @@
+ frame + ".");
}
+ mergeWithNextTransaction(t, frame);
// If the syncResults are SYNC_LOST_SURFACE_REWARD_IF_FOUND or
// SYNC_CONTEXT_IS_STOPPED it means nothing will draw. There's no need to set up
// any blast sync or commit callback, and the code should directly call
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index 13ac329..fa0052c 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -840,6 +840,7 @@
mAnchorId = AccessibilityNodeInfo.UNDEFINED_NODE_ID;
mTitle = null;
mTransitionTime = 0;
+ mLocales = LocaleList.getEmptyLocaleList();
}
/**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3fbb505..34fe935 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -806,6 +806,7 @@
private CharSequence mHint;
@UnsupportedAppUsage
private Layout mHintLayout;
+ private boolean mHideHint;
private MovementMethod mMovement;
@@ -7180,6 +7181,8 @@
sendOnTextChanged(text, 0, oldlen, textLength);
onTextChanged(text, 0, oldlen, textLength);
+ mHideHint = false;
+
if (a11yTextChangeType == AccessibilityUtils.TEXT) {
notifyViewAccessibilityStateChangedIfNeeded(
AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT);
@@ -7338,6 +7341,7 @@
}
private void setHintInternal(CharSequence hint) {
+ mHideHint = false;
mHint = TextUtils.stringOrSpannedString(hint);
if (mLayout != null) {
@@ -7379,6 +7383,19 @@
}
/**
+ * Temporarily hides the hint text until the text is modified, or the hint text is modified, or
+ * the view gains or loses focus.
+ *
+ * @hide
+ */
+ public void hideHint() {
+ if (isShowingHint()) {
+ mHideHint = true;
+ invalidate();
+ }
+ }
+
+ /**
* Returns if the text is constrained to a single horizontally scrolling line ignoring new
* line characters instead of letting it wrap onto multiple lines.
*
@@ -8974,7 +8991,7 @@
Layout layout = mLayout;
- if (mHint != null && mText.length() == 0) {
+ if (mHint != null && !mHideHint && mText.length() == 0) {
if (mHintTextColor != null) {
color = mCurHintTextColor;
}
@@ -11293,7 +11310,7 @@
}
private boolean isShowingHint() {
- return TextUtils.isEmpty(mText) && !TextUtils.isEmpty(mHint);
+ return TextUtils.isEmpty(mText) && !TextUtils.isEmpty(mHint) && !mHideHint;
}
/**
@@ -12437,6 +12454,7 @@
sendOnTextChanged(buffer, start, before, after);
onTextChanged(buffer, start, before, after);
+ mHideHint = false;
clearGesturePreviewHighlight();
}
@@ -12577,6 +12595,8 @@
return;
}
+ mHideHint = false;
+
if (mEditor != null) mEditor.onFocusChanged(focused, direction);
if (focused) {
diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java
index d4ff794..57cc38c 100644
--- a/core/java/com/android/internal/app/AssistUtils.java
+++ b/core/java/com/android/internal/app/AssistUtils.java
@@ -57,6 +57,8 @@
public static final int INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS = 5;
/** value for INVOCATION_TYPE_KEY: long press on physical power button */
public static final int INVOCATION_TYPE_POWER_BUTTON_LONG_PRESS = 6;
+ /** value for INVOCATION_TYPE_KEY: press on physcial assistant button */
+ public static final int INVOCATION_TYPE_ASSIST_BUTTON = 7;
private final Context mContext;
private final IVoiceInteractionManagerService mVoiceInteractionManagerService;
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/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 0a0785e..80f540c 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -36,6 +36,7 @@
import android.os.Handler;
import android.os.Trace;
import android.text.TextUtils;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
import android.view.Choreographer;
@@ -43,7 +44,9 @@
import android.view.SurfaceControl;
import android.view.SurfaceControl.JankData.JankType;
import android.view.ThreadedRenderer;
+import android.view.View;
import android.view.ViewRootImpl;
+import android.view.WindowCallbacks;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor.Configuration;
@@ -686,6 +689,14 @@
}
}
+ ThreadedRendererWrapper getThreadedRenderer() {
+ return mRendererWrapper;
+ }
+
+ ViewRootWrapper getViewRoot() {
+ return mViewRoot;
+ }
+
private boolean shouldTriggerPerfetto(int missedFramesCount, int maxFrameTimeNanos) {
boolean overMissedFramesThreshold = mTraceThresholdMissedFrames != -1
&& missedFramesCount >= mTraceThresholdMissedFrames;
@@ -798,6 +809,28 @@
public SurfaceControl getSurfaceControl() {
return mViewRoot.getSurfaceControl();
}
+
+ void requestInvalidateRootRenderNode() {
+ mViewRoot.requestInvalidateRootRenderNode();
+ }
+
+ void addWindowCallbacks(WindowCallbacks windowCallbacks) {
+ mViewRoot.addWindowCallbacks(windowCallbacks);
+ }
+
+ void removeWindowCallbacks(WindowCallbacks windowCallbacks) {
+ mViewRoot.removeWindowCallbacks(windowCallbacks);
+ }
+
+ View getView() {
+ return mViewRoot.getView();
+ }
+
+ int dipToPx(int dip) {
+ final DisplayMetrics displayMetrics =
+ mViewRoot.mContext.getResources().getDisplayMetrics();
+ return (int) (displayMetrics.density * dip + 0.5f);
+ }
}
public static class SurfaceControlWrapper {
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 4b9e77e..c769fb9 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -97,6 +97,7 @@
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION;
import android.Manifest;
+import android.annotation.ColorInt;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
@@ -104,6 +105,7 @@
import android.annotation.WorkerThread;
import android.app.ActivityThread;
import android.content.Context;
+import android.graphics.Color;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerExecutor;
@@ -143,6 +145,14 @@
* adb shell device_config put interaction_jank_monitor enabled true
* adb shell device_config put interaction_jank_monitor sampling_interval 1
*
+ * On debuggable builds, an overlay can be used to display the name of the
+ * currently running cuj using:
+ *
+ * adb shell device_config put interaction_jank_monitor debug_overlay_enabled true
+ *
+ * NOTE: The overlay will interfere with metrics, so it should only be used
+ * for understanding which UI events correspeond to which CUJs.
+ *
* @hide
*/
public class InteractionJankMonitor {
@@ -159,6 +169,7 @@
"trace_threshold_missed_frames";
private static final String SETTINGS_THRESHOLD_FRAME_TIME_MILLIS_KEY =
"trace_threshold_frame_time_millis";
+ private static final String SETTINGS_DEBUG_OVERLAY_ENABLED_KEY = "debug_overlay_enabled";
/** Default to being enabled on debug builds. */
private static final boolean DEFAULT_ENABLED = Build.IS_DEBUGGABLE;
/** Default to collecting data for all CUJs. */
@@ -166,6 +177,7 @@
/** Default to triggering trace if 3 frames are missed OR a frame takes at least 64ms */
private static final int DEFAULT_TRACE_THRESHOLD_MISSED_FRAMES = 3;
private static final int DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS = 64;
+ private static final boolean DEFAULT_DEBUG_OVERLAY_ENABLED = false;
@VisibleForTesting
public static final int MAX_LENGTH_OF_CUJ_NAME = 80;
@@ -343,6 +355,9 @@
private final HandlerThread mWorker;
private final DisplayResolutionTracker mDisplayResolutionTracker;
private final Object mLock = new Object();
+ private @ColorInt int mDebugBgColor = Color.CYAN;
+ private double mDebugYOffset = 0.1;
+ private InteractionMonitorDebugOverlay mDebugOverlay;
private volatile boolean mEnabled = DEFAULT_ENABLED;
private int mSamplingInterval = DEFAULT_SAMPLING_INTERVAL;
@@ -533,7 +548,7 @@
if (needRemoveTasks(action, session)) {
getTracker(session.getCuj()).getHandler().runWithScissors(() -> {
removeTimeout(session.getCuj());
- removeTracker(session.getCuj());
+ removeTracker(session.getCuj(), session.getReason());
}, EXECUTOR_TASK_TIMEOUT);
}
}
@@ -699,7 +714,7 @@
if (tracker == null) return false;
// if the end call doesn't return true, another thread is handling end of the cuj.
if (tracker.end(REASON_END_NORMAL)) {
- removeTracker(cujType);
+ removeTracker(cujType, REASON_END_NORMAL);
}
return true;
}
@@ -750,7 +765,7 @@
if (tracker == null) return false;
// if the cancel call doesn't return true, another thread is handling cancel of the cuj.
if (tracker.cancel(reason)) {
- removeTracker(cujType);
+ removeTracker(cujType, reason);
}
return true;
}
@@ -758,6 +773,13 @@
private void putTracker(@CujType int cuj, @NonNull FrameTracker tracker) {
synchronized (mLock) {
mRunningTrackers.put(cuj, tracker);
+ if (mDebugOverlay != null) {
+ mDebugOverlay.onTrackerAdded(cuj, tracker.getViewRoot());
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Added tracker for " + getNameOfCuj(cuj)
+ + ". mRunningTrackers=" + listNamesOfCujs(mRunningTrackers));
+ }
}
}
@@ -767,9 +789,16 @@
}
}
- private void removeTracker(@CujType int cuj) {
+ private void removeTracker(@CujType int cuj, int reason) {
synchronized (mLock) {
mRunningTrackers.remove(cuj);
+ if (mDebugOverlay != null) {
+ mDebugOverlay.onTrackerRemoved(cuj, reason, mRunningTrackers);
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Removed tracker for " + getNameOfCuj(cuj)
+ + ". mRunningTrackers=" + listNamesOfCujs(mRunningTrackers));
+ }
}
}
@@ -782,6 +811,16 @@
mTraceThresholdFrameTimeMillis = properties.getInt(
SETTINGS_THRESHOLD_FRAME_TIME_MILLIS_KEY,
DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS);
+ // Never allow the debug overlay to be used on user builds
+ boolean debugOverlayEnabled = Build.IS_DEBUGGABLE && properties.getBoolean(
+ SETTINGS_DEBUG_OVERLAY_ENABLED_KEY,
+ DEFAULT_DEBUG_OVERLAY_ENABLED);
+ if (debugOverlayEnabled && mDebugOverlay == null) {
+ mDebugOverlay = new InteractionMonitorDebugOverlay(mDebugBgColor, mDebugYOffset);
+ } else if (!debugOverlayEnabled && mDebugOverlay != null) {
+ mDebugOverlay.dispose();
+ mDebugOverlay = null;
+ }
// The memory visibility is powered by the volatile field, mEnabled.
mEnabled = properties.getBoolean(SETTINGS_ENABLED_KEY, DEFAULT_ENABLED);
}
@@ -822,6 +861,39 @@
}
/**
+ * Configures the debug overlay used for displaying interaction names on the screen while they
+ * occur.
+ *
+ * @param bgColor the background color of the box used to display the CUJ names
+ * @param yOffset number between 0 and 1 to indicate where the top of the box should be relative
+ * to the height of the screen
+ */
+ public void configDebugOverlay(@ColorInt int bgColor, double yOffset) {
+ mDebugBgColor = bgColor;
+ mDebugYOffset = yOffset;
+ }
+
+ /**
+ * A helper method for getting a string representation of all running CUJs. For example,
+ * "(LOCKSCREEN_TRANSITION_FROM_AOD, IME_INSETS_ANIMATION)"
+ */
+ private static String listNamesOfCujs(SparseArray<FrameTracker> trackers) {
+ if (!DEBUG) {
+ return null;
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append('(');
+ for (int i = 0; i < trackers.size(); i++) {
+ sb.append(getNameOfCuj(trackers.keyAt(i)));
+ if (i < trackers.size() - 1) {
+ sb.append(", ");
+ }
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+
+ /**
* A helper method to translate CUJ type to CUJ name.
*
* @param cujType the cuj type defined in this file
diff --git a/core/java/com/android/internal/jank/InteractionMonitorDebugOverlay.java b/core/java/com/android/internal/jank/InteractionMonitorDebugOverlay.java
new file mode 100644
index 0000000..99b9f2f
--- /dev/null
+++ b/core/java/com/android/internal/jank/InteractionMonitorDebugOverlay.java
@@ -0,0 +1,240 @@
+/*
+ * 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.jank;
+
+import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL;
+
+import android.annotation.ColorInt;
+import android.app.ActivityThread;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RecordingCanvas;
+import android.graphics.Rect;
+import android.os.Trace;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.view.WindowCallbacks;
+
+import com.android.internal.jank.FrameTracker.Reasons;
+import com.android.internal.jank.InteractionJankMonitor.CujType;
+
+/**
+ * An overlay that uses WindowCallbacks to draw the names of all running CUJs to the window
+ * associated with one of the CUJs being tracked. There's no guarantee which window it will
+ * draw to. NOTE: sometimes the CUJ names will remain displayed on the screen longer than they
+ * are actually running.
+ * <p>
+ * CUJ names will be drawn as follows:
+ * <ul>
+ * <li> Normal text indicates the CUJ is currently running
+ * <li> Grey text indicates the CUJ ended normally and is no longer running
+ * <li> Red text with a strikethrough indicates the CUJ was canceled or ended abnormally
+ * </ul>
+ */
+class InteractionMonitorDebugOverlay implements WindowCallbacks {
+ private static final int REASON_STILL_RUNNING = -1000;
+ // Sparse array where the key in the CUJ and the value is the session status, or null if
+ // it's currently running
+ private final SparseIntArray mRunningCujs = new SparseIntArray();
+ private FrameTracker.ViewRootWrapper mViewRoot = null;
+ private final Paint mDebugPaint;
+ private final Paint.FontMetrics mDebugFontMetrics;
+ // Used to display the overlay in a different color and position for different processes.
+ // Otherwise, two overlays will overlap and be difficult to read.
+ private final int mBgColor;
+ private final double mYOffset;
+ private final String mPackageName;
+
+ InteractionMonitorDebugOverlay(@ColorInt int bgColor, double yOffset) {
+ mBgColor = bgColor;
+ mYOffset = yOffset;
+ mDebugPaint = new Paint();
+ mDebugPaint.setAntiAlias(false);
+ mDebugFontMetrics = new Paint.FontMetrics();
+ final Context context = ActivityThread.currentApplication();
+ mPackageName = context.getPackageName();
+ }
+
+ void dispose() {
+ if (mViewRoot != null) {
+ mViewRoot.removeWindowCallbacks(this);
+ forceRedraw();
+ }
+ mViewRoot = null;
+ }
+
+ private boolean attachViewRootIfNeeded(FrameTracker.ViewRootWrapper viewRoot) {
+ if (mViewRoot == null && viewRoot != null) {
+ mViewRoot = viewRoot;
+ viewRoot.addWindowCallbacks(this);
+ forceRedraw();
+ return true;
+ }
+ return false;
+ }
+
+ private float getWidthOfLongestCujName(int cujFontSize) {
+ mDebugPaint.setTextSize(cujFontSize);
+ float maxLength = 0;
+ for (int i = 0; i < mRunningCujs.size(); i++) {
+ String cujName = InteractionJankMonitor.getNameOfCuj(mRunningCujs.keyAt(i));
+ float textLength = mDebugPaint.measureText(cujName);
+ if (textLength > maxLength) {
+ maxLength = textLength;
+ }
+ }
+ return maxLength;
+ }
+
+ private float getTextHeight(int textSize) {
+ mDebugPaint.setTextSize(textSize);
+ mDebugPaint.getFontMetrics(mDebugFontMetrics);
+ return mDebugFontMetrics.descent - mDebugFontMetrics.ascent;
+ }
+
+ private int dipToPx(int dip) {
+ if (mViewRoot != null) {
+ return mViewRoot.dipToPx(dip);
+ } else {
+ return dip;
+ }
+ }
+
+ private void forceRedraw() {
+ if (mViewRoot != null) {
+ mViewRoot.requestInvalidateRootRenderNode();
+ mViewRoot.getView().invalidate();
+ }
+ }
+
+ void onTrackerRemoved(@CujType int removedCuj, @Reasons int reason,
+ SparseArray<FrameTracker> runningTrackers) {
+ mRunningCujs.put(removedCuj, reason);
+ // If REASON_STILL_RUNNING is not in mRunningCujs, then all CUJs have ended
+ if (mRunningCujs.indexOfValue(REASON_STILL_RUNNING) < 0) {
+ mRunningCujs.clear();
+ dispose();
+ } else {
+ boolean needsNewViewRoot = true;
+ if (mViewRoot != null) {
+ // Check to see if this viewroot is still associated with one of the running
+ // trackers
+ for (int i = 0; i < runningTrackers.size(); i++) {
+ if (mViewRoot.equals(
+ runningTrackers.valueAt(i).getViewRoot())) {
+ needsNewViewRoot = false;
+ break;
+ }
+ }
+ }
+ if (needsNewViewRoot) {
+ dispose();
+ for (int i = 0; i < runningTrackers.size(); i++) {
+ if (attachViewRootIfNeeded(runningTrackers.valueAt(i).getViewRoot())) {
+ break;
+ }
+ }
+ } else {
+ forceRedraw();
+ }
+ }
+ }
+
+ void onTrackerAdded(@CujType int addedCuj, FrameTracker.ViewRootWrapper viewRoot) {
+ // Use REASON_STILL_RUNNING (not technically one of the '@Reasons') to indicate the CUJ
+ // is still running
+ mRunningCujs.put(addedCuj, REASON_STILL_RUNNING);
+ attachViewRootIfNeeded(viewRoot);
+ forceRedraw();
+ }
+
+ @Override
+ public void onWindowSizeIsChanging(Rect newBounds, boolean fullscreen,
+ Rect systemInsets, Rect stableInsets) {
+ }
+
+ @Override
+ public void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen,
+ Rect systemInsets, Rect stableInsets) {
+ }
+
+ @Override
+ public void onWindowDragResizeEnd() {
+ }
+
+ @Override
+ public boolean onContentDrawn(int offsetX, int offsetY, int sizeX, int sizeY) {
+ return false;
+ }
+
+ @Override
+ public void onRequestDraw(boolean reportNextDraw) {
+ }
+
+ @Override
+ public void onPostDraw(RecordingCanvas canvas) {
+ Trace.beginSection("InteractionJankMonitor#drawDebug");
+ final int padding = dipToPx(5);
+ final int h = canvas.getHeight();
+ final int w = canvas.getWidth();
+ // Draw sysui CUjs near the bottom of the screen so they don't overlap with the shade,
+ // and draw launcher CUJs near the top of the screen so they don't overlap with gestures
+ final int dy = (int) (h * mYOffset);
+ int packageNameFontSize = dipToPx(12);
+ int cujFontSize = dipToPx(18);
+ final float cujNameTextHeight = getTextHeight(cujFontSize);
+ final float packageNameTextHeight = getTextHeight(packageNameFontSize);
+ float maxLength = getWidthOfLongestCujName(cujFontSize);
+
+ final int dx = (int) ((w - maxLength) / 2f);
+ canvas.translate(dx, dy);
+ // Draw background rectangle for displaying the text showing the CUJ name
+ mDebugPaint.setColor(mBgColor);
+ canvas.drawRect(
+ -padding * 2, // more padding on top so we can draw the package name
+ -padding,
+ padding * 2 + maxLength,
+ padding * 2 + packageNameTextHeight + cujNameTextHeight * mRunningCujs.size(),
+ mDebugPaint);
+ mDebugPaint.setTextSize(packageNameFontSize);
+ mDebugPaint.setColor(Color.BLACK);
+ mDebugPaint.setStrikeThruText(false);
+ canvas.translate(0, packageNameTextHeight);
+ canvas.drawText("package:" + mPackageName, 0, 0, mDebugPaint);
+ mDebugPaint.setTextSize(cujFontSize);
+ // Draw text for CUJ names
+ for (int i = 0; i < mRunningCujs.size(); i++) {
+ int status = mRunningCujs.valueAt(i);
+ if (status == REASON_STILL_RUNNING) {
+ mDebugPaint.setColor(Color.BLACK);
+ mDebugPaint.setStrikeThruText(false);
+ } else if (status == REASON_END_NORMAL) {
+ mDebugPaint.setColor(Color.GRAY);
+ mDebugPaint.setStrikeThruText(false);
+ } else {
+ // Cancelled, or otherwise ended for a bad reason
+ mDebugPaint.setColor(Color.RED);
+ mDebugPaint.setStrikeThruText(true);
+ }
+ String cujName = InteractionJankMonitor.getNameOfCuj(mRunningCujs.keyAt(i));
+ canvas.translate(0, cujNameTextHeight);
+ canvas.drawText(cujName, 0, 0, mDebugPaint);
+ }
+ Trace.endSection();
+ }
+}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 8e96ac1..193099b 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -616,6 +616,12 @@
genReleaseCallback(env, releaseCallback));
}
+static void nativeUnsetBuffer(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
+ transaction->unsetBuffer(ctrl);
+}
+
static void nativeSetBufferTransform(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jint transform) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
@@ -2198,6 +2204,8 @@
(void*)nativeSetGeometry },
{"nativeSetBuffer", "(JJLandroid/hardware/HardwareBuffer;JLjava/util/function/Consumer;)V",
(void*)nativeSetBuffer },
+ {"nativeUnsetBuffer", "(JJ)V", (void*)nativeUnsetBuffer },
+
{"nativeSetBufferTransform", "(JJI)V", (void*) nativeSetBufferTransform},
{"nativeSetDataSpace", "(JJI)V",
(void*)nativeSetDataSpace },
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/core/res/res/drawable/loading_spinner.xml b/core/res/res/drawable/loading_spinner.xml
new file mode 100644
index 0000000..49603d8
--- /dev/null
+++ b/core/res/res/drawable/loading_spinner.xml
@@ -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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="230dp" android:width="230dp" android:viewportHeight="230"
+ android:viewportWidth="230">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_0_G" android:translateX="100.621"
+ android:translateY="102.621">
+ <path android:name="_R_G_L_0_G_D_0_P_0" android:strokeColor="#ffffff"
+ android:strokeLineCap="round" android:strokeLineJoin="round"
+ android:strokeWidth="8" android:strokeAlpha="1" android:trimPathStart="0"
+ android:trimPathEnd="0" android:trimPathOffset="0"
+ android:pathData=" M14.38 -93.62 C72.88,-93.62 120.38,-46.12 120.38,12.38 C120.38,70.88 72.88,118.38 14.38,118.38 C-44.12,118.38 -91.62,70.88 -91.62,12.38 C-91.62,-46.12 -44.12,-93.62 14.38,-93.62c "/>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="trimPathEnd" android:duration="350"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0.4,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="517"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
\ No newline at end of file
diff --git a/core/res/res/layout/user_switching_dialog.xml b/core/res/res/layout/user_switching_dialog.xml
index 2e041f5..496179a 100644
--- a/core/res/res/layout/user_switching_dialog.xml
+++ b/core/res/res/layout/user_switching_dialog.xml
@@ -14,17 +14,48 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/content"
+ android:background="?attr/colorBackground"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/message"
- style="?attr/textAppearanceListItem"
- android:background="?attr/colorSurface"
+ <LinearLayout
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
android:gravity="center"
- android:drawablePadding="12dp"
- android:drawableTint="?attr/textColorPrimary"
- android:paddingStart="?attr/dialogPreferredPadding"
- android:paddingEnd="?attr/dialogPreferredPadding"
- android:paddingTop="24dp"
- android:paddingBottom="24dp" />
+ android:orientation="vertical"
+ android:paddingBottom="77dp">
+
+ <RelativeLayout
+ android:layout_width="242dp"
+ android:layout_height="242dp"
+ android:layout_gravity="center">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="26dp" />
+
+ <ImageView
+ android:id="@+id/progress_circular"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="6dp"
+ android:src="@drawable/loading_spinner" />
+
+ </RelativeLayout>
+
+ <TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/message"
+ style="?attr/textAppearanceListItem"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="20sp"
+ android:textAlignment="center"
+ android:drawableTint="?attr/textColorPrimary" />
+
+ </LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5544701..c5f7ea6 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1917,7 +1917,8 @@
<string name="config_defaultNetworkRecommendationProviderPackage" translatable="false"></string>
<!-- The package name of the default search selector app. Must be granted the POST_NOTIFICATIONS
- permission.
+ permission, and notifications from this app must be given the notification flag
+ FLAG_NO_DISMISS if the notification requests FLAG_ONGOING_EVENT.
-->
<string name="config_defaultSearchSelectorPackageName" translatable="false"></string>
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 3ea1592..34b4c51 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -91,8 +91,8 @@
":BstatsTestApp",
":BinderDeathRecipientHelperApp1",
":BinderDeathRecipientHelperApp2",
+ ":com.android.cts.helpers.aosp",
],
- required: ["com.android.cts.helpers.aosp"],
}
// Rules to copy all the test apks to the intermediate raw resource directory
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
index 8ae6381..c0125af 100644
--- a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
@@ -23,14 +23,20 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.Instrumentation;
import android.content.Context;
+import android.graphics.Canvas;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.HandwritingInitiator;
@@ -38,7 +44,9 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
+import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -47,6 +55,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
/**
* Tests for {@link HandwritingInitiator}
@@ -543,6 +552,111 @@
assertThat(mHandwritingInitiator.mConnectedView.get()).isEqualTo(mTestView1);
}
+ @Test
+ public void startHandwriting_hidesHint() {
+ EditText editText =
+ new EditText(InstrumentationRegistry.getInstrumentation().getTargetContext());
+ editText.setHint("hint");
+ editText.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+
+ verifyEditTextDrawsText(editText, "hint");
+
+ mHandwritingInitiator.onTouchEvent(createStylusEvent(ACTION_DOWN, 0, 0, 0));
+ mHandwritingInitiator.startHandwriting(editText);
+
+ verifyEditTextDrawsText(editText, null);
+ }
+
+ @Test
+ public void startHandwriting_clearFocus_restoresHint() {
+ EditText editText =
+ new EditText(InstrumentationRegistry.getInstrumentation().getTargetContext());
+ editText.setHint("hint");
+ editText.setLayoutParams(new ViewGroup.LayoutParams(1024, 1024));
+ editText.requestFocus();
+
+ verifyEditTextDrawsText(editText, "hint");
+
+ mHandwritingInitiator.onTouchEvent(createStylusEvent(ACTION_DOWN, 0, 0, 0));
+ mHandwritingInitiator.startHandwriting(editText);
+
+ verifyEditTextDrawsText(editText, null);
+
+ editText.clearFocus();
+
+ verifyEditTextDrawsText(editText, "hint");
+ }
+
+ @Test
+ public void startHandwriting_setHint_restoresHint() {
+ EditText editText =
+ new EditText(InstrumentationRegistry.getInstrumentation().getTargetContext());
+ editText.setHint("hint");
+ editText.setLayoutParams(new ViewGroup.LayoutParams(1024, 1024));
+
+ verifyEditTextDrawsText(editText, "hint");
+
+ mHandwritingInitiator.onTouchEvent(createStylusEvent(ACTION_DOWN, 0, 0, 0));
+ mHandwritingInitiator.startHandwriting(editText);
+
+ verifyEditTextDrawsText(editText, null);
+
+ editText.setHint("new hint");
+
+ verifyEditTextDrawsText(editText, "new hint");
+ }
+
+ @Test
+ public void startHandwriting_setText_restoresHint() {
+ EditText editText =
+ new EditText(InstrumentationRegistry.getInstrumentation().getTargetContext());
+ editText.setHint("hint");
+ editText.setLayoutParams(new ViewGroup.LayoutParams(1024, 1024));
+
+ verifyEditTextDrawsText(editText, "hint");
+
+ mHandwritingInitiator.onTouchEvent(createStylusEvent(ACTION_DOWN, 0, 0, 0));
+ mHandwritingInitiator.startHandwriting(editText);
+
+ verifyEditTextDrawsText(editText, null);
+
+ editText.setText("a");
+ editText.setText("");
+
+ verifyEditTextDrawsText(editText, "hint");
+ }
+
+ private void verifyEditTextDrawsText(EditText editText, String text) {
+ editText.measure(
+ View.MeasureSpec.makeMeasureSpec(1024, View.MeasureSpec.AT_MOST),
+ View.MeasureSpec.makeMeasureSpec(1024, View.MeasureSpec.AT_MOST));
+ Canvas canvas = prepareMockCanvas(editText);
+ editText.draw(canvas);
+ if (text != null) {
+ ArgumentCaptor<CharSequence> textCaptor = ArgumentCaptor.forClass(CharSequence.class);
+ verify(canvas).drawText(
+ textCaptor.capture(), anyInt(), anyInt(), anyFloat(), anyFloat(), any());
+ assertThat(textCaptor.getValue().toString()).isEqualTo(text);
+ } else {
+ verify(canvas, never()).drawText(
+ any(CharSequence.class), anyInt(), anyInt(), anyFloat(), anyFloat(), any());
+ }
+ }
+
+ private Canvas prepareMockCanvas(View view) {
+ Canvas canvas = mock(Canvas.class);
+ when(canvas.getClipBounds(any())).thenAnswer(invocation -> {
+ Rect outRect = invocation.getArgument(0);
+ outRect.top = 0;
+ outRect.left = 0;
+ outRect.right = view.getMeasuredWidth();
+ outRect.bottom = view.getMeasuredHeight();
+ return true;
+ });
+ return canvas;
+ }
+
private MotionEvent createStylusEvent(int action, int x, int y, long eventTime) {
MotionEvent.PointerProperties[] properties = MotionEvent.PointerProperties.createArray(1);
properties[0].toolType = MotionEvent.TOOL_TYPE_STYLUS;
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
index 03d366e6..57a1376 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
@@ -46,6 +46,10 @@
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Handler;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
@@ -57,6 +61,7 @@
import com.android.internal.R;
import com.android.internal.accessibility.dialog.AccessibilityShortcutChooserActivity;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -73,8 +78,14 @@
@RunWith(AndroidJUnit4.class)
public class AccessibilityShortcutChooserActivityTest {
private static final String ONE_HANDED_MODE = "One-Handed mode";
+ private static final String DENY_LABEL = "Deny";
+ private static final String EDIT_LABEL = "Edit shortcuts";
+ private static final String LIST_TITLE_LABEL = "Choose features to use";
private static final String TEST_LABEL = "TEST_LABEL";
private static final ComponentName TEST_COMPONENT_NAME = new ComponentName("package", "class");
+ private static final long UI_TIMEOUT_MS = 1000;
+ private UiDevice mDevice;
+ private ActivityScenario<TestAccessibilityShortcutChooserActivity> mScenario;
private TestAccessibilityShortcutChooserActivity mActivity;
@Rule
@@ -92,6 +103,8 @@
@Before
public void setUp() throws Exception {
+ mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ mDevice.wakeUp();
when(mAccessibilityServiceInfo.getResolveInfo()).thenReturn(mResolveInfo);
mResolveInfo.serviceInfo = mServiceInfo;
mServiceInfo.applicationInfo = mApplicationInfo;
@@ -102,27 +115,36 @@
when(mAccessibilityManagerService.isAccessibilityTargetAllowed(
anyString(), anyInt(), anyInt())).thenReturn(true);
TestAccessibilityShortcutChooserActivity.setupForTesting(mAccessibilityManagerService);
+ mScenario = ActivityScenario.launch(TestAccessibilityShortcutChooserActivity.class);
+ mScenario.onActivity(activity -> mActivity = activity);
+ mScenario.moveToState(Lifecycle.State.CREATED);
+ mScenario.moveToState(Lifecycle.State.STARTED);
+ mScenario.moveToState(Lifecycle.State.RESUMED);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
+ @After
+ public void cleanUp() {
+ mScenario.moveToState(Lifecycle.State.DESTROYED);
}
@Test
public void doubleClickTestServiceAndClickDenyButton_permissionDialogDoesNotExist() {
- final ActivityScenario<TestAccessibilityShortcutChooserActivity> scenario =
- ActivityScenario.launch(TestAccessibilityShortcutChooserActivity.class);
- scenario.moveToState(Lifecycle.State.CREATED);
- scenario.moveToState(Lifecycle.State.STARTED);
- scenario.moveToState(Lifecycle.State.RESUMED);
+ openShortcutsList();
- onView(withText(R.string.accessibility_select_shortcut_menu_title)).inRoot(
- isDialog()).check(matches(isDisplayed()));
- onView(withText(R.string.edit_accessibility_shortcut_menu_button)).perform(click());
- onView(withText(TEST_LABEL)).perform(scrollTo(), doubleClick());
- onView(withId(R.id.accessibility_permission_enable_deny_button)).perform(scrollTo(),
- click());
+ // Performing the double-click is flaky so retry if needed.
+ for (int attempt = 1; attempt <= 2; attempt++) {
+ onView(withText(TEST_LABEL)).perform(scrollTo(), doubleClick());
+ if (mDevice.wait(Until.hasObject(By.text(DENY_LABEL)), UI_TIMEOUT_MS)) {
+ break;
+ }
+ }
+
+ onView(withText(DENY_LABEL)).perform(scrollTo(), click());
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
onView(withId(R.id.accessibility_permissionDialog_title)).inRoot(isDialog()).check(
doesNotExist());
- scenario.moveToState(Lifecycle.State.DESTROYED);
}
@Test
@@ -130,60 +152,42 @@
throws Exception {
when(mAccessibilityManagerService.isAccessibilityTargetAllowed(
eq(TEST_COMPONENT_NAME.getPackageName()), anyInt(), anyInt())).thenReturn(false);
- final ActivityScenario<TestAccessibilityShortcutChooserActivity> scenario =
- ActivityScenario.launch(TestAccessibilityShortcutChooserActivity.class);
- scenario.onActivity(activity -> mActivity = activity);
- scenario.moveToState(Lifecycle.State.CREATED);
- scenario.moveToState(Lifecycle.State.STARTED);
- scenario.moveToState(Lifecycle.State.RESUMED);
-
- onView(withText(R.string.accessibility_select_shortcut_menu_title)).inRoot(
- isDialog()).check(matches(isDisplayed()));
- onView(withText(R.string.edit_accessibility_shortcut_menu_button)).perform(click());
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ openShortcutsList();
onView(withText(TEST_LABEL)).perform(scrollTo(), click());
+
verify(mAccessibilityManagerService).sendRestrictedDialogIntent(
eq(TEST_COMPONENT_NAME.getPackageName()), anyInt(), anyInt());
- scenario.moveToState(Lifecycle.State.DESTROYED);
}
@Test
public void popEditShortcutMenuList_oneHandedModeEnabled_shouldBeInListView() {
TestUtils.setOneHandedModeEnabled(this, /* enabled= */ true);
- final ActivityScenario<TestAccessibilityShortcutChooserActivity> scenario =
- ActivityScenario.launch(TestAccessibilityShortcutChooserActivity.class);
- scenario.moveToState(Lifecycle.State.CREATED);
- scenario.moveToState(Lifecycle.State.STARTED);
- scenario.moveToState(Lifecycle.State.RESUMED);
+ openShortcutsList();
- onView(withText(R.string.accessibility_select_shortcut_menu_title)).inRoot(
- isDialog()).check(matches(isDisplayed()));
- onView(withText(R.string.edit_accessibility_shortcut_menu_button)).perform(click());
onView(allOf(withClassName(endsWith("ListView")), isDisplayed())).perform(swipeUp());
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ mDevice.wait(Until.hasObject(By.text(ONE_HANDED_MODE)), UI_TIMEOUT_MS);
onView(withText(ONE_HANDED_MODE)).inRoot(isDialog()).check(matches(isDisplayed()));
- scenario.moveToState(Lifecycle.State.DESTROYED);
}
@Test
public void popEditShortcutMenuList_oneHandedModeDisabled_shouldNotBeInListView() {
TestUtils.setOneHandedModeEnabled(this, /* enabled= */ false);
- final ActivityScenario<TestAccessibilityShortcutChooserActivity> scenario =
- ActivityScenario.launch(TestAccessibilityShortcutChooserActivity.class);
- scenario.moveToState(Lifecycle.State.CREATED);
- scenario.moveToState(Lifecycle.State.STARTED);
- scenario.moveToState(Lifecycle.State.RESUMED);
+ openShortcutsList();
- onView(withText(R.string.accessibility_select_shortcut_menu_title)).inRoot(
- isDialog()).check(matches(isDisplayed()));
- onView(withText(R.string.edit_accessibility_shortcut_menu_button)).perform(click());
onView(allOf(withClassName(endsWith("ListView")), isDisplayed())).perform(swipeUp());
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
onView(withText(ONE_HANDED_MODE)).inRoot(isDialog()).check(doesNotExist());
- scenario.moveToState(Lifecycle.State.DESTROYED);
+ }
+
+ private void openShortcutsList() {
+ UiObject2 editButton = mDevice.findObject(By.text(EDIT_LABEL));
+ if (editButton != null) {
+ editButton.click();
+ }
+ mDevice.wait(Until.hasObject(By.textStartsWith(LIST_TITLE_LABEL)), UI_TIMEOUT_MS);
}
/**
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/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 60111aa..f8f8897 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -1068,6 +1068,7 @@
// We need to be Z ordered on top in order for alpha animations to work.
mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(true);
mExpandedBubble.getExpandedView().setAnimating(true);
+ mExpandedViewContainer.setVisibility(VISIBLE);
}
}
@@ -3116,7 +3117,7 @@
mAnimatingOutBubbleBuffer.getColorSpace());
mAnimatingOutSurfaceView.setAlpha(1f);
- mExpandedViewContainer.setVisibility(View.GONE);
+ mExpandedViewContainer.setVisibility(View.INVISIBLE);
mSurfaceSynchronizer.syncSurfaceAndRun(() -> {
post(() -> {
@@ -3146,9 +3147,6 @@
int[] paddings = mPositioner.getExpandedViewContainerPadding(
mStackAnimationController.isStackOnLeftSide(), isOverflowExpanded);
mExpandedViewContainer.setPadding(paddings[0], paddings[1], paddings[2], paddings[3]);
- if (mIsExpansionAnimating) {
- mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
- }
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
PointF p = mPositioner.getExpandedBubbleXY(getBubbleIndex(mExpandedBubble),
getState());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
index cbd544c..e732a03 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
@@ -16,9 +16,12 @@
package com.android.wm.shell.desktopmode;
+import android.graphics.Region;
+
import com.android.wm.shell.common.annotations.ExternalThread;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
* Interface to interact with desktop mode feature in shell.
@@ -32,7 +35,16 @@
* @param listener the listener to add.
* @param callbackExecutor the executor to call the listener on.
*/
- void addListener(DesktopModeTaskRepository.VisibleTasksListener listener,
+ void addVisibleTasksListener(DesktopModeTaskRepository.VisibleTasksListener listener,
Executor callbackExecutor);
+ /**
+ * Adds a consumer to listen for Desktop task corner changes. This is used for gesture
+ * exclusion. The SparseArray contains a list of four corner resize handles mapped to each
+ * desktop task's taskId. The resize handle Rects are stored in the following order:
+ * left-top, left-bottom, right-top, right-bottom.
+ */
+ default void addDesktopGestureExclusionRegionListener(Consumer<Region> listener,
+ Executor callbackExecutor) { }
+
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
index 2bdbde1..86ea725 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
@@ -34,6 +34,7 @@
import android.app.WindowConfiguration;
import android.content.Context;
import android.database.ContentObserver;
+import android.graphics.Region;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
@@ -69,6 +70,7 @@
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
* Handles windowing changes when desktop mode system setting changes
@@ -149,11 +151,21 @@
* @param listener the listener to add.
* @param callbackExecutor the executor to call the listener on.
*/
- public void addListener(DesktopModeTaskRepository.VisibleTasksListener listener,
+ public void addVisibleTasksListener(DesktopModeTaskRepository.VisibleTasksListener listener,
Executor callbackExecutor) {
mDesktopModeTaskRepository.addVisibleTasksListener(listener, callbackExecutor);
}
+ /**
+ * Adds a listener to track changes to corners of desktop mode tasks.
+ * @param listener the listener to add.
+ * @param callbackExecutor the executor to call the listener on.
+ */
+ public void addTaskCornerListener(Consumer<Region> listener,
+ Executor callbackExecutor) {
+ mDesktopModeTaskRepository.setTaskCornerListener(listener, callbackExecutor);
+ }
+
@VisibleForTesting
void updateDesktopModeActive(boolean active) {
ProtoLog.d(WM_SHELL_DESKTOP_MODE, "updateDesktopModeActive: active=%s", active);
@@ -312,6 +324,23 @@
}
/**
+ * Update corner rects stored for a specific task
+ * @param taskId task to update
+ * @param taskCorners task's new corner handles
+ */
+ public void onTaskCornersChanged(int taskId, Region taskCorners) {
+ mDesktopModeTaskRepository.updateTaskCorners(taskId, taskCorners);
+ }
+
+ /**
+ * Remove corners saved for a task. Likely used due to task closure.
+ * @param taskId task to remove
+ */
+ public void removeCornersForTask(int taskId) {
+ mDesktopModeTaskRepository.removeTaskCorners(taskId);
+ }
+
+ /**
* Moves a specifc task to the front.
* @param taskInfo the task to show in front.
*/
@@ -426,10 +455,19 @@
private final class DesktopModeImpl implements DesktopMode {
@Override
- public void addListener(DesktopModeTaskRepository.VisibleTasksListener listener,
+ public void addVisibleTasksListener(
+ DesktopModeTaskRepository.VisibleTasksListener listener,
Executor callbackExecutor) {
mMainExecutor.execute(() -> {
- DesktopModeController.this.addListener(listener, callbackExecutor);
+ DesktopModeController.this.addVisibleTasksListener(listener, callbackExecutor);
+ });
+ }
+
+ @Override
+ public void addDesktopGestureExclusionRegionListener(Consumer<Region> listener,
+ Executor callbackExecutor) {
+ mMainExecutor.execute(() -> {
+ DesktopModeController.this.addTaskCornerListener(listener, callbackExecutor);
});
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
index 47342c9..12f8ea2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
@@ -16,9 +16,13 @@
package com.android.wm.shell.desktopmode
+import android.graphics.Region
import android.util.ArrayMap
import android.util.ArraySet
+import android.util.SparseArray
+import androidx.core.util.valueIterator
import java.util.concurrent.Executor
+import java.util.function.Consumer
/**
* Keeps track of task data related to desktop mode.
@@ -38,6 +42,10 @@
private val activeTasksListeners = ArraySet<ActiveTasksListener>()
// Track visible tasks separately because a task may be part of the desktop but not visible.
private val visibleTasksListeners = ArrayMap<VisibleTasksListener, Executor>()
+ // Track corners of desktop tasks, used to determine gesture exclusion
+ private val desktopCorners = SparseArray<Region>()
+ private var desktopGestureExclusionListener: Consumer<Region>? = null
+ private var desktopGestureExclusionExecutor: Executor? = null
/**
* Add a [ActiveTasksListener] to be notified of updates to active tasks in the repository.
@@ -56,6 +64,28 @@
}
/**
+ * Add a Consumer which will inform other classes of changes to corners for all Desktop tasks.
+ */
+ fun setTaskCornerListener(cornersListener: Consumer<Region>, executor: Executor) {
+ desktopGestureExclusionListener = cornersListener
+ desktopGestureExclusionExecutor = executor
+ executor.execute {
+ desktopGestureExclusionListener?.accept(calculateDesktopExclusionRegion())
+ }
+ }
+
+ /**
+ * Create a new merged region representative of all corners in all desktop tasks.
+ */
+ private fun calculateDesktopExclusionRegion(): Region {
+ val desktopCornersRegion = Region()
+ desktopCorners.valueIterator().forEach { taskCorners ->
+ desktopCornersRegion.op(taskCorners, Region.Op.UNION)
+ }
+ return desktopCornersRegion
+ }
+
+ /**
* Remove a previously registered [ActiveTasksListener]
*/
fun removeActiveTasksListener(activeTasksListener: ActiveTasksListener) {
@@ -167,6 +197,28 @@
}
/**
+ * Updates the active desktop corners; if desktopCorners has been accepted by
+ * desktopCornersListener, it will be updated in the appropriate classes.
+ */
+ fun updateTaskCorners(taskId: Int, taskCorners: Region) {
+ desktopCorners.put(taskId, taskCorners)
+ desktopGestureExclusionExecutor?.execute {
+ desktopGestureExclusionListener?.accept(calculateDesktopExclusionRegion())
+ }
+ }
+
+ /**
+ * Removes the active desktop corners for the specified task; if desktopCorners has been
+ * accepted by desktopCornersListener, it will be updated in the appropriate classes.
+ */
+ fun removeTaskCorners(taskId: Int) {
+ desktopCorners.delete(taskId)
+ desktopGestureExclusionExecutor?.execute {
+ desktopGestureExclusionListener?.accept(calculateDesktopExclusionRegion())
+ }
+ }
+
+ /**
* Defines interface for classes that can listen to changes for active tasks in desktop mode.
*/
interface ActiveTasksListener {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 0400963..0d56023 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -27,6 +27,7 @@
import android.content.Context
import android.graphics.Point
import android.graphics.Rect
+import android.graphics.Region
import android.os.IBinder
import android.os.SystemProperties
import android.view.SurfaceControl
@@ -487,6 +488,20 @@
return 2 * getStatusBarHeight(taskInfo)
}
+ /**
+ * Update the corner region for a specified task
+ */
+ fun onTaskCornersChanged(taskId: Int, corner: Region) {
+ desktopModeTaskRepository.updateTaskCorners(taskId, corner)
+ }
+
+ /**
+ * Remove a previously tracked corner region for a specified task.
+ */
+ fun removeCornersForTask(taskId: Int) {
+ desktopModeTaskRepository.removeTaskCorners(taskId)
+ }
+
/**
* Adds a listener to find out about changes in the visibility of freeform tasks.
@@ -494,20 +509,47 @@
* @param listener the listener to add.
* @param callbackExecutor the executor to call the listener on.
*/
- fun addListener(listener: VisibleTasksListener, callbackExecutor: Executor) {
+ fun addVisibleTasksListener(listener: VisibleTasksListener, callbackExecutor: Executor) {
desktopModeTaskRepository.addVisibleTasksListener(listener, callbackExecutor)
}
+ /**
+ * Adds a listener to track changes to desktop task corners
+ *
+ * @param listener the listener to add.
+ * @param callbackExecutor the executor to call the listener on.
+ */
+ fun setTaskCornerListener(
+ listener: Consumer<Region>,
+ callbackExecutor: Executor
+ ) {
+ desktopModeTaskRepository.setTaskCornerListener(listener, callbackExecutor)
+ }
+
/** The interface for calls from outside the shell, within the host process. */
@ExternalThread
private inner class DesktopModeImpl : DesktopMode {
- override fun addListener(listener: VisibleTasksListener, callbackExecutor: Executor) {
+ override fun addVisibleTasksListener(
+ listener: VisibleTasksListener,
+ callbackExecutor: Executor
+ ) {
mainExecutor.execute {
- this@DesktopTasksController.addListener(listener, callbackExecutor)
+ this@DesktopTasksController.addVisibleTasksListener(listener, callbackExecutor)
+ }
+ }
+
+ override fun addDesktopGestureExclusionRegionListener(
+ listener: Consumer<Region>,
+ callbackExecutor: Executor
+ ) {
+ mainExecutor.execute {
+ this@DesktopTasksController.setTaskCornerListener(listener, callbackExecutor)
}
}
}
+
+
/** The interface for calls from outside the host process. */
@BinderThread
private class IDesktopModeImpl(private var controller: DesktopTasksController?) :
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index 4f362d4..eb4d2a1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -36,6 +36,7 @@
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Slog;
+import android.view.Display;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationTarget;
@@ -132,7 +133,7 @@
public WindowContainerTransaction handleRequest(IBinder transition,
TransitionRequestInfo request) {
// do not directly handle requests. Only entry point should be via startRecentsTransition
- Slog.e(TAG, "RecentsTransitionHandler.handleRequest: Unexpected transition request");
+ // TODO: Only log an error if the transition is a recents transition
return null;
}
@@ -219,6 +220,7 @@
private int mRecentsTaskId = -1;
private TransitionInfo mInfo = null;
private boolean mOpeningSeparateHome = false;
+ private boolean mPausingSeparateHome = false;
private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null;
private PictureInPictureSurfaceTransaction mPipTransaction = null;
private IBinder mTransition = null;
@@ -407,6 +409,10 @@
// raise closing (pausing) task to "above" layer so it isn't covered
t.setLayer(target.leash, info.getChanges().size() * 3 - i);
mPausingTasks.add(new TaskState(change, target.leash));
+ if (taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
+ // This can only happen if we have a separate recents/home (3p launcher)
+ mPausingSeparateHome = true;
+ }
if (taskInfo.pictureInPictureParams != null
&& taskInfo.pictureInPictureParams.isAutoEnterEnabled()) {
mPipTask = taskInfo.token;
@@ -585,6 +591,8 @@
final int rootIdx = TransitionUtil.rootIndexFor(change, mInfo);
t.reparent(appearedTargets[i].leash, mInfo.getRoot(rootIdx).getLeash());
t.setLayer(appearedTargets[i].leash, layer);
+ // Hide the animation leash, let listener show it.
+ t.hide(appearedTargets[i].leash);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
" opening new taskId=%d", appearedTargets[i].taskId);
mOpeningTasks.add(new TaskState(change, appearedTargets[i].leash));
@@ -612,13 +620,14 @@
t.apply();
// not using the incoming anim-only surfaces
info.releaseAnimSurfaces();
- if (appearedTargets == null) return;
- try {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
- "[%d] RecentsController.merge: calling onTasksAppeared", mInstanceId);
- mListener.onTasksAppeared(appearedTargets);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error sending appeared tasks to recents animation", e);
+ if (appearedTargets != null) {
+ try {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "[%d] RecentsController.merge: calling onTasksAppeared", mInstanceId);
+ mListener.onTasksAppeared(appearedTargets);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error sending appeared tasks to recents animation", e);
+ }
}
finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
}
@@ -657,6 +666,8 @@
mFinishCB != null, enabled);
return;
}
+ final int displayId = mInfo.getRootCount() > 0 ? mInfo.getRoot(0).getDisplayId()
+ : Display.DEFAULT_DISPLAY;
// transient launches don't receive focus automatically. Since we are taking over
// the gesture now, take focus explicitly.
// This also moves recents back to top if the user gestured before a switch
@@ -665,7 +676,7 @@
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
"[%d] RecentsController.setInputConsumerEnabled: set focus to recents",
mInstanceId);
- ActivityTaskManager.getService().setFocusedTask(mRecentsTaskId);
+ ActivityTaskManager.getService().focusTopTask(displayId);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to set focused task", e);
}
@@ -700,8 +711,9 @@
return;
}
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
- "[%d] RecentsController.finishInner: toHome=%b userLeave=%b willFinishToHome=%b",
- mInstanceId, toHome, sendUserLeaveHint, mWillFinishToHome);
+ "[%d] RecentsController.finishInner: toHome=%b userLeave=%b "
+ + "willFinishToHome=%b state=%d",
+ mInstanceId, toHome, sendUserLeaveHint, mWillFinishToHome, mState);
final Transitions.TransitionFinishCallback finishCB = mFinishCB;
mFinishCB = null;
@@ -712,8 +724,19 @@
if (toHome) wct.reorder(mRecentsTask, true /* toTop */);
else wct.restoreTransientOrder(mRecentsTask);
}
- if (!toHome && !mWillFinishToHome && mPausingTasks != null && mState == STATE_NORMAL) {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, " returning to app");
+ if (!toHome
+ // If a recents gesture starts on the 3p launcher, then the 3p launcher is the
+ // live tile (pausing app). If the gesture is "cancelled" we need to return to
+ // 3p launcher instead of "task-switching" away from it.
+ && (!mWillFinishToHome || mPausingSeparateHome)
+ && mPausingTasks != null && mState == STATE_NORMAL) {
+ if (mPausingSeparateHome) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ " returning to 3p home");
+ } else {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ " returning to app");
+ }
// The gesture is returning to the pausing-task(s) rather than continuing with
// recents, so end the transition by moving the app back to the top (and also
// re-showing it's task).
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index e4f2724..cca63ef 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -89,6 +89,9 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.IntArray;
import android.util.Log;
import android.util.Slog;
import android.view.Choreographer;
@@ -2390,6 +2393,7 @@
if (!mMainStage.isActive()) return false;
mSplitLayout.setFreezeDividerWindow(false);
+ final StageChangeRecord record = new StageChangeRecord();
for (int iC = 0; iC < info.getChanges().size(); ++iC) {
final TransitionInfo.Change change = info.getChanges().get(iC);
if (change.getMode() == TRANSIT_CHANGE
@@ -2405,20 +2409,29 @@
if (!stage.containsTask(taskInfo.taskId)) {
Log.w(TAG, "Expected onTaskAppeared on " + stage + " to have been called"
+ " with " + taskInfo.taskId + " before startAnimation().");
+ record.addRecord(stage, true, taskInfo.taskId);
}
} else if (isClosingType(change.getMode())) {
if (stage.containsTask(taskInfo.taskId)) {
+ record.addRecord(stage, false, taskInfo.taskId);
Log.w(TAG, "Expected onTaskVanished on " + stage + " to have been called"
+ " with " + taskInfo.taskId + " before startAnimation().");
}
}
}
- if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
+ // If the size of dismissStages == 1, one of the task is closed without prepare pending
+ // transition, which could happen if all activities were finished after finish top
+ // activity in a task, so the trigger task is null when handleRequest.
+ // Note if the size of dismissStages == 2, it's starting a new task, so don't handle it.
+ final ArraySet<StageTaskListener> dismissStages = record.getShouldDismissedStage();
+ if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0
+ || dismissStages.size() == 1) {
Log.e(TAG, "Somehow removed the last task in a stage outside of a proper "
+ "transition.");
final WindowContainerTransaction wct = new WindowContainerTransaction();
- final int dismissTop = mMainStage.getChildCount() == 0
- ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+ final int dismissTop = (dismissStages.size() == 1
+ && getStageType(dismissStages.valueAt(0)) == STAGE_TYPE_MAIN)
+ || mMainStage.getChildCount() == 0 ? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN;
prepareExitSplitScreen(dismissTop, wct);
mSplitTransitions.startDismissTransition(wct, this, dismissTop,
EXIT_REASON_UNKNOWN);
@@ -2445,6 +2458,57 @@
finishCallback);
}
+ static class StageChangeRecord {
+ static class StageChange {
+ final StageTaskListener mStageTaskListener;
+ final IntArray mAddedTaskId = new IntArray();
+ final IntArray mRemovedTaskId = new IntArray();
+ StageChange(StageTaskListener stage) {
+ mStageTaskListener = stage;
+ }
+
+ boolean shouldDismissStage() {
+ if (mAddedTaskId.size() > 0 || mRemovedTaskId.size() == 0) {
+ return false;
+ }
+ int removeChildTaskCount = 0;
+ for (int i = mRemovedTaskId.size() - 1; i >= 0; --i) {
+ if (mStageTaskListener.containsTask(mRemovedTaskId.get(i))) {
+ ++removeChildTaskCount;
+ }
+ }
+ return removeChildTaskCount == mStageTaskListener.getChildCount();
+ }
+ }
+ private final ArrayMap<StageTaskListener, StageChange> mChanges = new ArrayMap<>();
+
+ void addRecord(StageTaskListener stage, boolean open, int taskId) {
+ final StageChange next;
+ if (!mChanges.containsKey(stage)) {
+ next = new StageChange(stage);
+ mChanges.put(stage, next);
+ } else {
+ next = mChanges.get(stage);
+ }
+ if (open) {
+ next.mAddedTaskId.add(taskId);
+ } else {
+ next.mRemovedTaskId.add(taskId);
+ }
+ }
+
+ ArraySet<StageTaskListener> getShouldDismissedStage() {
+ final ArraySet<StageTaskListener> dismissTarget = new ArraySet<>();
+ for (int i = mChanges.size() - 1; i >= 0; --i) {
+ final StageChange change = mChanges.valueAt(i);
+ if (change.shouldDismissStage()) {
+ dismissTarget.add(change.mStageTaskListener);
+ }
+ }
+ return dismissTarget;
+ }
+ }
+
/** Starts the pending transition animation. */
public boolean startPendingAnimation(@NonNull IBinder transition,
@NonNull TransitionInfo info,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 49a5eac..8fb56fc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -36,6 +36,7 @@
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.Region;
import android.hardware.input.InputManager;
import android.os.Handler;
import android.os.IBinder;
@@ -69,6 +70,7 @@
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.TaskCornersListener;
import java.util.Optional;
import java.util.function.Supplier;
@@ -95,9 +97,11 @@
private SparseArray<EventReceiver> mEventReceiversByDisplay = new SparseArray<>();
+ private final TaskCornersListener mCornersListener = new TaskCornersListenerImpl();
+
private final SparseArray<DesktopModeWindowDecoration> mWindowDecorByTaskId =
new SparseArray<>();
- private final DragStartListenerImpl mDragStartListener = new DragStartListenerImpl();
+ private final DragListenerImpl mDragStartListener = new DragListenerImpl();
private final InputMonitorFactory mInputMonitorFactory;
private TaskOperations mTaskOperations;
private final Supplier<SurfaceControl.Transaction> mTransactionFactory;
@@ -779,6 +783,7 @@
final DesktopModeTouchEventListener touchEventListener =
new DesktopModeTouchEventListener(taskInfo, taskPositioner);
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
+ windowDecoration.setCornersListener(mCornersListener);
windowDecoration.setDragPositioningCallback(taskPositioner);
windowDecoration.setDragDetector(touchEventListener.mDragDetector);
windowDecoration.relayout(taskInfo, startT, finishT,
@@ -786,7 +791,7 @@
incrementEventReceiverTasks(taskInfo.displayId);
}
- private class DragStartListenerImpl implements TaskPositioner.DragStartListener {
+ private class DragListenerImpl implements TaskPositioner.DragStartListener {
@Override
public void onDragStart(int taskId) {
mWindowDecorByTaskId.get(taskId).closeHandleMenu();
@@ -798,6 +803,22 @@
return inputManager.monitorGestureInput("caption-touch", context.getDisplayId());
}
}
+
+ private class TaskCornersListenerImpl
+ implements DesktopModeWindowDecoration.TaskCornersListener {
+
+ @Override
+ public void onTaskCornersChanged(int taskId, Region corner) {
+ mDesktopModeController.ifPresent(d -> d.onTaskCornersChanged(taskId, corner));
+ mDesktopTasksController.ifPresent(d -> d.onTaskCornersChanged(taskId, corner));
+ }
+
+ @Override
+ public void onTaskCornersRemoved(int taskId) {
+ mDesktopModeController.ifPresent(d -> d.removeCornersForTask(taskId));
+ mDesktopTasksController.ifPresent(d -> d.removeCornersForTask(taskId));
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index af3fb0e..f9fdd83 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -17,19 +17,15 @@
package com.android.wm.shell.windowdecor;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.res.ColorStateList;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
+import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.Log;
@@ -38,11 +34,6 @@
import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewConfiguration;
-import android.widget.Button;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.window.SurfaceSyncGroup;
import android.window.WindowContainerTransaction;
import com.android.launcher3.icons.IconProvider;
@@ -80,6 +71,7 @@
private final WindowDecoration.RelayoutResult<WindowDecorLinearLayout> mResult =
new WindowDecoration.RelayoutResult<>();
+ private final Point mPositionInParent = new Point();
private final PointF mHandleMenuAppInfoPillPosition = new PointF();
private final PointF mHandleMenuWindowingPillPosition = new PointF();
private final PointF mHandleMenuMoreActionsPillPosition = new PointF();
@@ -88,10 +80,13 @@
private AdditionalWindow mHandleMenuAppInfoPill;
private AdditionalWindow mHandleMenuWindowingPill;
private AdditionalWindow mHandleMenuMoreActionsPill;
+ private HandleMenu mHandleMenu;
private Drawable mAppIcon;
private CharSequence mAppName;
+ private TaskCornersListener mCornersListener;
+
private int mMenuWidth;
private int mMarginMenuTop;
private int mMarginMenuStart;
@@ -118,29 +113,6 @@
mSyncQueue = syncQueue;
loadAppInfo();
- loadHandleMenuDimensions();
- }
-
- private void loadHandleMenuDimensions() {
- final Resources resources = mDecorWindowContext.getResources();
- mMenuWidth = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_width);
- mMarginMenuTop = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_margin_top);
- mMarginMenuStart = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_margin_start);
- mMarginMenuSpacing = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_pill_spacing_margin);
- mAppInfoPillHeight = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_app_info_pill_height);
- mWindowingPillHeight = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_windowing_pill_height);
- mShadowRadius = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_shadow_radius);
- mCornerRadius = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_corner_radius);
- mMoreActionsPillHeight = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_more_actions_pill_height);
}
@Override
@@ -161,6 +133,10 @@
mOnCaptionTouchListener = onCaptionTouchListener;
}
+ void setCornersListener(TaskCornersListener cornersListener) {
+ mCornersListener = cornersListener;
+ }
+
void setDragPositioningCallback(DragPositioningCallback dragPositioningCallback) {
mDragPositioningCallback = dragPositioningCallback;
}
@@ -189,20 +165,8 @@
taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM;
final boolean isDragResizeable = isFreeform && taskInfo.isResizeable;
- if (mHandleMenuAppInfoPill != null) {
- updateHandleMenuPillPositions();
- startT.setPosition(mHandleMenuAppInfoPill.mWindowSurface,
- mHandleMenuAppInfoPillPosition.x, mHandleMenuAppInfoPillPosition.y);
-
- // Only show windowing buttons in proto2. Proto1 uses a system-level mode only.
- final boolean shouldShowWindowingPill = DesktopModeStatus.isProto2Enabled();
- if (shouldShowWindowingPill) {
- startT.setPosition(mHandleMenuWindowingPill.mWindowSurface,
- mHandleMenuWindowingPillPosition.x, mHandleMenuWindowingPillPosition.y);
- }
-
- startT.setPosition(mHandleMenuMoreActionsPill.mWindowSurface,
- mHandleMenuMoreActionsPillPosition.x, mHandleMenuMoreActionsPillPosition.y);
+ if (isHandleMenuActive()) {
+ mHandleMenu.relayout(startT);
}
final WindowDecorLinearLayout oldRootView = mResult.mRootView;
@@ -278,12 +242,18 @@
.getDimensionPixelSize(R.dimen.freeform_resize_handle);
final int resize_corner = mResult.mRootView.getResources()
.getDimensionPixelSize(R.dimen.freeform_resize_corner);
- mDragResizeListener.setGeometry(
- mResult.mWidth, mResult.mHeight, resize_handle, resize_corner, touchSlop);
+
+ // If either task geometry or position have changed, update this task's cornersListener
+ if (mDragResizeListener.setGeometry(
+ mResult.mWidth, mResult.mHeight, resize_handle, resize_corner, touchSlop)
+ || !mTaskInfo.positionInParent.equals(mPositionInParent)) {
+ mCornersListener.onTaskCornersChanged(mTaskInfo.taskId, getGlobalCornersRegion());
+ }
+ mPositionInParent.set(mTaskInfo.positionInParent);
}
boolean isHandleMenuActive() {
- return mHandleMenuAppInfoPill != null;
+ return mHandleMenu != null;
}
private void loadAppInfo() {
@@ -313,136 +283,16 @@
* Create and display handle menu window
*/
void createHandleMenu() {
- final SurfaceSyncGroup ssg = new SurfaceSyncGroup(TAG);
- final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- updateHandleMenuPillPositions();
-
- createAppInfoPill(t, ssg);
-
- // Only show windowing buttons in proto2. Proto1 uses a system-level mode only.
- final boolean shouldShowWindowingPill = DesktopModeStatus.isProto2Enabled();
- if (shouldShowWindowingPill) {
- createWindowingPill(t, ssg);
- }
-
- createMoreActionsPill(t, ssg);
-
- ssg.addTransaction(t);
- ssg.markSyncReady();
- setupHandleMenu(shouldShowWindowingPill);
- }
-
- private void createAppInfoPill(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) {
- final int x = (int) mHandleMenuAppInfoPillPosition.x;
- final int y = (int) mHandleMenuAppInfoPillPosition.y;
- mHandleMenuAppInfoPill = addWindow(
- R.layout.desktop_mode_window_decor_handle_menu_app_info_pill,
- "Menu's app info pill",
- t, ssg, x, y, mMenuWidth, mAppInfoPillHeight, mShadowRadius, mCornerRadius);
- }
-
- private void createWindowingPill(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) {
- final int x = (int) mHandleMenuWindowingPillPosition.x;
- final int y = (int) mHandleMenuWindowingPillPosition.y;
- mHandleMenuWindowingPill = addWindow(
- R.layout.desktop_mode_window_decor_handle_menu_windowing_pill,
- "Menu's windowing pill",
- t, ssg, x, y, mMenuWidth, mWindowingPillHeight, mShadowRadius, mCornerRadius);
- }
-
- private void createMoreActionsPill(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) {
- final int x = (int) mHandleMenuMoreActionsPillPosition.x;
- final int y = (int) mHandleMenuMoreActionsPillPosition.y;
- mHandleMenuMoreActionsPill = addWindow(
- R.layout.desktop_mode_window_decor_handle_menu_more_actions_pill,
- "Menu's more actions pill",
- t, ssg, x, y, mMenuWidth, mMoreActionsPillHeight, mShadowRadius, mCornerRadius);
- }
-
- private void setupHandleMenu(boolean windowingPillShown) {
- // App Info pill setup.
- final View appInfoPillView = mHandleMenuAppInfoPill.mWindowViewHost.getView();
- final ImageButton collapseBtn = appInfoPillView.findViewById(R.id.collapse_menu_button);
- final ImageView appIcon = appInfoPillView.findViewById(R.id.application_icon);
- final TextView appName = appInfoPillView.findViewById(R.id.application_name);
- collapseBtn.setOnClickListener(mOnCaptionButtonClickListener);
- appInfoPillView.setOnTouchListener(mOnCaptionTouchListener);
- appIcon.setImageDrawable(mAppIcon);
- appName.setText(mAppName);
-
- // Windowing pill setup.
- if (windowingPillShown) {
- final View windowingPillView = mHandleMenuWindowingPill.mWindowViewHost.getView();
- final ImageButton fullscreenBtn = windowingPillView.findViewById(
- R.id.fullscreen_button);
- final ImageButton splitscreenBtn = windowingPillView.findViewById(
- R.id.split_screen_button);
- final ImageButton floatingBtn = windowingPillView.findViewById(R.id.floating_button);
- final ImageButton desktopBtn = windowingPillView.findViewById(R.id.desktop_button);
- fullscreenBtn.setOnClickListener(mOnCaptionButtonClickListener);
- splitscreenBtn.setOnClickListener(mOnCaptionButtonClickListener);
- floatingBtn.setOnClickListener(mOnCaptionButtonClickListener);
- desktopBtn.setOnClickListener(mOnCaptionButtonClickListener);
- // The button corresponding to the windowing mode that the task is currently in uses a
- // different color than the others.
- final ColorStateList activeColorStateList = ColorStateList.valueOf(
- mContext.getColor(R.color.desktop_mode_caption_menu_buttons_color_active));
- final ColorStateList inActiveColorStateList = ColorStateList.valueOf(
- mContext.getColor(R.color.desktop_mode_caption_menu_buttons_color_inactive));
- fullscreenBtn.setImageTintList(
- mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
- ? activeColorStateList : inActiveColorStateList);
- splitscreenBtn.setImageTintList(
- mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW
- ? activeColorStateList : inActiveColorStateList);
- floatingBtn.setImageTintList(mTaskInfo.getWindowingMode() == WINDOWING_MODE_PINNED
- ? activeColorStateList : inActiveColorStateList);
- desktopBtn.setImageTintList(mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
- ? activeColorStateList : inActiveColorStateList);
- }
-
- // More Actions pill setup.
- final View moreActionsPillView = mHandleMenuMoreActionsPill.mWindowViewHost.getView();
- final Button closeBtn = moreActionsPillView.findViewById(R.id.close_button);
- closeBtn.setOnClickListener(mOnCaptionButtonClickListener);
- }
-
- /**
- * Updates the handle menu pills' position variables to reflect their next positions
- */
- private void updateHandleMenuPillPositions() {
- final int menuX, menuY;
- final int captionWidth = mTaskInfo.getConfiguration()
- .windowConfiguration.getBounds().width();
- if (mRelayoutParams.mLayoutResId
- == R.layout.desktop_mode_app_controls_window_decor) {
- // Align the handle menu to the left of the caption.
- menuX = mRelayoutParams.mCaptionX + mMarginMenuStart;
- menuY = mRelayoutParams.mCaptionY + mMarginMenuTop;
- } else {
- // Position the handle menu at the center of the caption.
- menuX = mRelayoutParams.mCaptionX + (captionWidth / 2) - (mMenuWidth / 2);
- menuY = mRelayoutParams.mCaptionY + mMarginMenuStart;
- }
-
- // App Info pill setup.
- final int appInfoPillY = menuY;
- mHandleMenuAppInfoPillPosition.set(menuX, appInfoPillY);
-
- // Only show windowing buttons in proto2. Proto1 uses a system-level mode only.
- final boolean shouldShowWindowingPill = DesktopModeStatus.isProto2Enabled();
-
- final int windowingPillY, moreActionsPillY;
- if (shouldShowWindowingPill) {
- windowingPillY = appInfoPillY + mAppInfoPillHeight + mMarginMenuSpacing;
- mHandleMenuWindowingPillPosition.set(menuX, windowingPillY);
- moreActionsPillY = windowingPillY + mWindowingPillHeight + mMarginMenuSpacing;
- mHandleMenuMoreActionsPillPosition.set(menuX, moreActionsPillY);
- } else {
- // Just start after the end of the app info pill + margins.
- moreActionsPillY = appInfoPillY + mAppInfoPillHeight + mMarginMenuSpacing;
- mHandleMenuMoreActionsPillPosition.set(menuX, moreActionsPillY);
- }
+ mHandleMenu = new HandleMenu.Builder(this)
+ .setAppIcon(mAppIcon)
+ .setAppName(mAppName)
+ .setOnClickListener(mOnCaptionButtonClickListener)
+ .setOnTouchListener(mOnCaptionTouchListener)
+ .setLayoutId(mRelayoutParams.mLayoutResId)
+ .setCaptionPosition(mRelayoutParams.mCaptionX, mRelayoutParams.mCaptionY)
+ .setWindowingButtonsVisible(DesktopModeStatus.isProto2Enabled())
+ .build();
+ mHandleMenu.show();
}
/**
@@ -450,14 +300,8 @@
*/
void closeHandleMenu() {
if (!isHandleMenuActive()) return;
- mHandleMenuAppInfoPill.releaseView();
- mHandleMenuAppInfoPill = null;
- if (mHandleMenuWindowingPill != null) {
- mHandleMenuWindowingPill.releaseView();
- mHandleMenuWindowingPill = null;
- }
- mHandleMenuMoreActionsPill.releaseView();
- mHandleMenuMoreActionsPill = null;
+ mHandleMenu.close();
+ mHandleMenu = null;
}
@Override
@@ -474,10 +318,6 @@
void closeHandleMenuIfNeeded(MotionEvent ev) {
if (!isHandleMenuActive()) return;
- // When this is called before the layout is fully inflated, width will be 0.
- // Menu is not visible in this scenario, so skip the check if that is the case.
- if (mHandleMenuAppInfoPill.mWindowViewHost.getView().getWidth() == 0) return;
-
PointF inputPoint = offsetCaptionLocation(ev);
// If this is called before open_menu_button's onClick, we don't want to close
@@ -487,22 +327,7 @@
inputPoint.x,
inputPoint.y);
- final boolean pointInAppInfoPill = pointInView(
- mHandleMenuAppInfoPill.mWindowViewHost.getView(),
- inputPoint.x - mHandleMenuAppInfoPillPosition.x,
- inputPoint.y - mHandleMenuAppInfoPillPosition.y);
- boolean pointInWindowingPill = false;
- if (mHandleMenuWindowingPill != null) {
- pointInWindowingPill = pointInView(mHandleMenuWindowingPill.mWindowViewHost.getView(),
- inputPoint.x - mHandleMenuWindowingPillPosition.x,
- inputPoint.y - mHandleMenuWindowingPillPosition.y);
- }
- final boolean pointInMoreActionsPill = pointInView(
- mHandleMenuMoreActionsPill.mWindowViewHost.getView(),
- inputPoint.x - mHandleMenuMoreActionsPillPosition.x,
- inputPoint.y - mHandleMenuMoreActionsPillPosition.y);
- if (!pointInAppInfoPill && !pointInWindowingPill
- && !pointInMoreActionsPill && !pointInOpenMenuButton) {
+ if (!mHandleMenu.isValidMenuInput(inputPoint) && !pointInOpenMenuButton) {
closeHandleMenu();
}
}
@@ -559,13 +384,7 @@
final View handle = caption.findViewById(R.id.caption_handle);
clickIfPointInView(new PointF(ev.getX(), ev.getY()), handle);
} else {
- final View appInfoPill = mHandleMenuAppInfoPill.mWindowViewHost.getView();
- final ImageButton collapse = appInfoPill.findViewById(R.id.collapse_menu_button);
- // Translate the input point from display coordinates to the same space as the collapse
- // button, meaning its parent (app info pill view).
- final PointF inputPoint = new PointF(ev.getX() - mHandleMenuAppInfoPillPosition.x,
- ev.getY() - mHandleMenuAppInfoPillPosition.y);
- clickIfPointInView(inputPoint, collapse);
+ mHandleMenu.checkClickEvent(ev);
}
}
@@ -577,7 +396,7 @@
return false;
}
- private boolean pointInView(View v, float x, float y) {
+ boolean pointInView(View v, float x, float y) {
return v != null && v.getLeft() <= x && v.getRight() >= x
&& v.getTop() <= y && v.getBottom() >= y;
}
@@ -586,6 +405,7 @@
public void close() {
closeDragResizeListener();
closeHandleMenu();
+ mCornersListener.onTaskCornersRemoved(mTaskInfo.taskId);
super.close();
}
@@ -598,6 +418,15 @@
: R.layout.desktop_mode_focused_window_decor;
}
+ /**
+ * Create a new region out of the corner rects of this task.
+ */
+ Region getGlobalCornersRegion() {
+ Region cornersRegion = mDragResizeListener.getCornersRegion();
+ cornersRegion.translate(mPositionInParent.x, mPositionInParent.y);
+ return cornersRegion;
+ }
+
static class Factory {
DesktopModeWindowDecoration create(
@@ -620,4 +449,13 @@
syncQueue);
}
}
+
+ interface TaskCornersListener {
+ /** Inform the implementing class of this task's change in corner resize handles */
+ void onTaskCornersChanged(int taskId, Region corner);
+
+ /** Inform the implementing class that this task no longer needs its corners tracked,
+ * likely due to it closing. */
+ void onTaskCornersRemoved(int taskId);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index d5437c7..34c8c08 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -134,13 +134,14 @@
* @param cornerSize The size of the resize handle centered in each corner.
* @param touchSlop The distance in pixels user has to drag with touch for it to register as
* a resize action.
+ * @return whether the geometry has changed or not
*/
- void setGeometry(int taskWidth, int taskHeight, int resizeHandleThickness, int cornerSize,
+ boolean setGeometry(int taskWidth, int taskHeight, int resizeHandleThickness, int cornerSize,
int touchSlop) {
if (mTaskWidth == taskWidth && mTaskHeight == taskHeight
&& mResizeHandleThickness == resizeHandleThickness
&& mCornerSize == cornerSize) {
- return;
+ return false;
}
mTaskWidth = taskWidth;
@@ -220,6 +221,19 @@
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
+ return true;
+ }
+
+ /**
+ * Generate a Region that encapsulates all 4 corner handles
+ */
+ Region getCornersRegion() {
+ Region region = new Region();
+ region.union(mLeftTopCornerBounds);
+ region.union(mLeftBottomCornerBounds);
+ region.union(mRightTopCornerBounds);
+ region.union(mRightBottomCornerBounds);
+ return region;
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
new file mode 100644
index 0000000..ed3cca0
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
@@ -0,0 +1,402 @@
+/*
+ * 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.wm.shell.windowdecor;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.graphics.PointF;
+import android.graphics.drawable.Drawable;
+import android.view.MotionEvent;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.window.SurfaceSyncGroup;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.desktopmode.DesktopModeStatus;
+
+/**
+ * Handle menu opened when the appropriate button is clicked on.
+ *
+ * Displays up to 3 pills that show the following:
+ * App Info: App name, app icon, and collapse button to close the menu.
+ * Windowing Options(Proto 2 only): Buttons to change windowing modes.
+ * Additional Options: Miscellaneous functions including screenshot and closing task.
+ */
+class HandleMenu {
+ private static final String TAG = "HandleMenu";
+ private final Context mContext;
+ private final WindowDecoration mParentDecor;
+ private WindowDecoration.AdditionalWindow mAppInfoPill;
+ private WindowDecoration.AdditionalWindow mWindowingPill;
+ private WindowDecoration.AdditionalWindow mMoreActionsPill;
+ private final PointF mAppInfoPillPosition = new PointF();
+ private final PointF mWindowingPillPosition = new PointF();
+ private final PointF mMoreActionsPillPosition = new PointF();
+ private final boolean mShouldShowWindowingPill;
+ private final Drawable mAppIcon;
+ private final CharSequence mAppName;
+ private final View.OnClickListener mOnClickListener;
+ private final View.OnTouchListener mOnTouchListener;
+ private final RunningTaskInfo mTaskInfo;
+ private final int mLayoutResId;
+ private final int mCaptionX;
+ private final int mCaptionY;
+ private int mMarginMenuTop;
+ private int mMarginMenuStart;
+ private int mMarginMenuSpacing;
+ private int mMenuWidth;
+ private int mAppInfoPillHeight;
+ private int mWindowingPillHeight;
+ private int mMoreActionsPillHeight;
+ private int mShadowRadius;
+ private int mCornerRadius;
+
+
+ HandleMenu(WindowDecoration parentDecor, int layoutResId, int captionX, int captionY,
+ View.OnClickListener onClickListener, View.OnTouchListener onTouchListener,
+ Drawable appIcon, CharSequence appName, boolean shouldShowWindowingPill) {
+ mParentDecor = parentDecor;
+ mContext = mParentDecor.mDecorWindowContext;
+ mTaskInfo = mParentDecor.mTaskInfo;
+ mLayoutResId = layoutResId;
+ mCaptionX = captionX;
+ mCaptionY = captionY;
+ mOnClickListener = onClickListener;
+ mOnTouchListener = onTouchListener;
+ mAppIcon = appIcon;
+ mAppName = appName;
+ mShouldShowWindowingPill = shouldShowWindowingPill;
+ loadHandleMenuDimensions();
+ updateHandleMenuPillPositions();
+ }
+
+ void show() {
+ final SurfaceSyncGroup ssg = new SurfaceSyncGroup(TAG);
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+
+ createAppInfoPill(t, ssg);
+ if (mShouldShowWindowingPill) {
+ createWindowingPill(t, ssg);
+ }
+ createMoreActionsPill(t, ssg);
+ ssg.addTransaction(t);
+ ssg.markSyncReady();
+ setupHandleMenu();
+ }
+
+ private void createAppInfoPill(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) {
+ final int x = (int) mAppInfoPillPosition.x;
+ final int y = (int) mAppInfoPillPosition.y;
+ mAppInfoPill = mParentDecor.addWindow(
+ R.layout.desktop_mode_window_decor_handle_menu_app_info_pill,
+ "Menu's app info pill",
+ t, ssg, x, y, mMenuWidth, mAppInfoPillHeight, mShadowRadius, mCornerRadius);
+ }
+
+ private void createWindowingPill(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) {
+ final int x = (int) mWindowingPillPosition.x;
+ final int y = (int) mWindowingPillPosition.y;
+ mWindowingPill = mParentDecor.addWindow(
+ R.layout.desktop_mode_window_decor_handle_menu_windowing_pill,
+ "Menu's windowing pill",
+ t, ssg, x, y, mMenuWidth, mWindowingPillHeight, mShadowRadius, mCornerRadius);
+ }
+
+ private void createMoreActionsPill(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) {
+ final int x = (int) mMoreActionsPillPosition.x;
+ final int y = (int) mMoreActionsPillPosition.y;
+ mMoreActionsPill = mParentDecor.addWindow(
+ R.layout.desktop_mode_window_decor_handle_menu_more_actions_pill,
+ "Menu's more actions pill",
+ t, ssg, x, y, mMenuWidth, mMoreActionsPillHeight, mShadowRadius, mCornerRadius);
+ }
+
+ /**
+ * Set up interactive elements and color of this handle menu
+ */
+ private void setupHandleMenu() {
+ // App Info pill setup.
+ final View appInfoPillView = mAppInfoPill.mWindowViewHost.getView();
+ final ImageButton collapseBtn = appInfoPillView.findViewById(R.id.collapse_menu_button);
+ final ImageView appIcon = appInfoPillView.findViewById(R.id.application_icon);
+ final TextView appName = appInfoPillView.findViewById(R.id.application_name);
+ collapseBtn.setOnClickListener(mOnClickListener);
+ appInfoPillView.setOnTouchListener(mOnTouchListener);
+ appIcon.setImageDrawable(mAppIcon);
+ appName.setText(mAppName);
+
+ // Windowing pill setup.
+ if (mShouldShowWindowingPill) {
+ final View windowingPillView = mWindowingPill.mWindowViewHost.getView();
+ final ImageButton fullscreenBtn = windowingPillView.findViewById(
+ R.id.fullscreen_button);
+ final ImageButton splitscreenBtn = windowingPillView.findViewById(
+ R.id.split_screen_button);
+ final ImageButton floatingBtn = windowingPillView.findViewById(R.id.floating_button);
+ final ImageButton desktopBtn = windowingPillView.findViewById(R.id.desktop_button);
+ fullscreenBtn.setOnClickListener(mOnClickListener);
+ splitscreenBtn.setOnClickListener(mOnClickListener);
+ floatingBtn.setOnClickListener(mOnClickListener);
+ desktopBtn.setOnClickListener(mOnClickListener);
+ // The button corresponding to the windowing mode that the task is currently in uses a
+ // different color than the others.
+ final ColorStateList activeColorStateList = ColorStateList.valueOf(
+ mContext.getColor(R.color.desktop_mode_caption_menu_buttons_color_active));
+ final ColorStateList inActiveColorStateList = ColorStateList.valueOf(
+ mContext.getColor(R.color.desktop_mode_caption_menu_buttons_color_inactive));
+ fullscreenBtn.setImageTintList(
+ mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+ ? activeColorStateList : inActiveColorStateList);
+ splitscreenBtn.setImageTintList(
+ mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW
+ ? activeColorStateList : inActiveColorStateList);
+ floatingBtn.setImageTintList(mTaskInfo.getWindowingMode() == WINDOWING_MODE_PINNED
+ ? activeColorStateList : inActiveColorStateList);
+ desktopBtn.setImageTintList(mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
+ ? activeColorStateList : inActiveColorStateList);
+ }
+
+ // More Actions pill setup.
+ final View moreActionsPillView = mMoreActionsPill.mWindowViewHost.getView();
+ final Button closeBtn = moreActionsPillView.findViewById(R.id.close_button);
+ closeBtn.setOnClickListener(mOnClickListener);
+ }
+
+ /**
+ * Updates the handle menu pills' position variables to reflect their next positions
+ */
+ private void updateHandleMenuPillPositions() {
+ final int menuX, menuY;
+ final int captionWidth = mTaskInfo.getConfiguration()
+ .windowConfiguration.getBounds().width();
+ if (mLayoutResId
+ == R.layout.desktop_mode_app_controls_window_decor) {
+ // Align the handle menu to the left of the caption.
+ menuX = mCaptionX + mMarginMenuStart;
+ menuY = mCaptionY + mMarginMenuTop;
+ } else {
+ // Position the handle menu at the center of the caption.
+ menuX = mCaptionX + (captionWidth / 2) - (mMenuWidth / 2);
+ menuY = mCaptionY + mMarginMenuStart;
+ }
+
+ // App Info pill setup.
+ final int appInfoPillY = menuY;
+ mAppInfoPillPosition.set(menuX, appInfoPillY);
+
+ final int windowingPillY, moreActionsPillY;
+ if (mShouldShowWindowingPill) {
+ windowingPillY = appInfoPillY + mAppInfoPillHeight + mMarginMenuSpacing;
+ mWindowingPillPosition.set(menuX, windowingPillY);
+ moreActionsPillY = windowingPillY + mWindowingPillHeight + mMarginMenuSpacing;
+ mMoreActionsPillPosition.set(menuX, moreActionsPillY);
+ } else {
+ // Just start after the end of the app info pill + margins.
+ moreActionsPillY = appInfoPillY + mAppInfoPillHeight + mMarginMenuSpacing;
+ mMoreActionsPillPosition.set(menuX, moreActionsPillY);
+ }
+ }
+
+ /**
+ * Update pill layout, in case task changes have caused positioning to change.
+ * @param t
+ */
+ void relayout(SurfaceControl.Transaction t) {
+ if (mAppInfoPill != null) {
+ updateHandleMenuPillPositions();
+ t.setPosition(mAppInfoPill.mWindowSurface,
+ mAppInfoPillPosition.x, mAppInfoPillPosition.y);
+ // Only show windowing buttons in proto2. Proto1 uses a system-level mode only.
+ final boolean shouldShowWindowingPill = DesktopModeStatus.isProto2Enabled();
+ if (shouldShowWindowingPill) {
+ t.setPosition(mWindowingPill.mWindowSurface,
+ mWindowingPillPosition.x, mWindowingPillPosition.y);
+ }
+ t.setPosition(mMoreActionsPill.mWindowSurface,
+ mMoreActionsPillPosition.x, mMoreActionsPillPosition.y);
+ }
+ }
+ /**
+ * Check a passed MotionEvent if a click has occurred on any button on this caption
+ * Note this should only be called when a regular onClick is not possible
+ * (i.e. the button was clicked through status bar layer)
+ * @param ev the MotionEvent to compare against.
+ */
+ void checkClickEvent(MotionEvent ev) {
+ final View appInfoPill = mAppInfoPill.mWindowViewHost.getView();
+ final ImageButton collapse = appInfoPill.findViewById(R.id.collapse_menu_button);
+ // Translate the input point from display coordinates to the same space as the collapse
+ // button, meaning its parent (app info pill view).
+ final PointF inputPoint = new PointF(ev.getX() - mAppInfoPillPosition.x,
+ ev.getY() - mAppInfoPillPosition.y);
+ if (pointInView(collapse, inputPoint.x, inputPoint.y)) {
+ mOnClickListener.onClick(collapse);
+ }
+ }
+
+ /**
+ * A valid menu input is one of the following:
+ * An input that happens in the menu views.
+ * Any input before the views have been laid out.
+ * @param inputPoint the input to compare against.
+ */
+ boolean isValidMenuInput(PointF inputPoint) {
+ if (!viewsLaidOut()) return true;
+ final boolean pointInAppInfoPill = pointInView(
+ mAppInfoPill.mWindowViewHost.getView(),
+ inputPoint.x - mAppInfoPillPosition.x,
+ inputPoint.y - mAppInfoPillPosition.y);
+ boolean pointInWindowingPill = false;
+ if (mWindowingPill != null) {
+ pointInWindowingPill = pointInView(
+ mWindowingPill.mWindowViewHost.getView(),
+ inputPoint.x - mWindowingPillPosition.x,
+ inputPoint.y - mWindowingPillPosition.y);
+ }
+ final boolean pointInMoreActionsPill = pointInView(
+ mMoreActionsPill.mWindowViewHost.getView(),
+ inputPoint.x - mMoreActionsPillPosition.x,
+ inputPoint.y - mMoreActionsPillPosition.y);
+
+ return pointInAppInfoPill || pointInWindowingPill || pointInMoreActionsPill;
+ }
+
+ private boolean pointInView(View v, float x, float y) {
+ return v != null && v.getLeft() <= x && v.getRight() >= x
+ && v.getTop() <= y && v.getBottom() >= y;
+ }
+
+ /**
+ * Check if the views for handle menu can be seen.
+ * @return
+ */
+ private boolean viewsLaidOut() {
+ return mAppInfoPill.mWindowViewHost.getView().isLaidOut();
+ }
+
+
+ private void loadHandleMenuDimensions() {
+ final Resources resources = mContext.getResources();
+ mMenuWidth = loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_width);
+ mMarginMenuTop = loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_margin_top);
+ mMarginMenuStart = loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_margin_start);
+ mMarginMenuSpacing = loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_pill_spacing_margin);
+ mAppInfoPillHeight = loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_app_info_pill_height);
+ mWindowingPillHeight = loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_windowing_pill_height);
+ mMoreActionsPillHeight = loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_more_actions_pill_height);
+ mShadowRadius = loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_shadow_radius);
+ mCornerRadius = loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_corner_radius);
+ }
+
+ private int loadDimensionPixelSize(Resources resources, int resourceId) {
+ if (resourceId == Resources.ID_NULL) {
+ return 0;
+ }
+ return resources.getDimensionPixelSize(resourceId);
+ }
+
+ void close() {
+ mAppInfoPill.releaseView();
+ mAppInfoPill = null;
+ if (mWindowingPill != null) {
+ mWindowingPill.releaseView();
+ mWindowingPill = null;
+ }
+ mMoreActionsPill.releaseView();
+ mMoreActionsPill = null;
+ }
+
+ static final class Builder {
+ private final WindowDecoration mParent;
+ private CharSequence mName;
+ private Drawable mAppIcon;
+ private View.OnClickListener mOnClickListener;
+ private View.OnTouchListener mOnTouchListener;
+ private int mLayoutId;
+ private int mCaptionX;
+ private int mCaptionY;
+ private boolean mShowWindowingPill;
+
+
+ Builder(@NonNull WindowDecoration parent) {
+ mParent = parent;
+ }
+
+ Builder setAppName(@Nullable CharSequence name) {
+ mName = name;
+ return this;
+ }
+
+ Builder setAppIcon(@Nullable Drawable appIcon) {
+ mAppIcon = appIcon;
+ return this;
+ }
+
+ Builder setOnClickListener(@Nullable View.OnClickListener onClickListener) {
+ mOnClickListener = onClickListener;
+ return this;
+ }
+
+ Builder setOnTouchListener(@Nullable View.OnTouchListener onTouchListener) {
+ mOnTouchListener = onTouchListener;
+ return this;
+ }
+
+ Builder setLayoutId(int layoutId) {
+ mLayoutId = layoutId;
+ return this;
+ }
+
+ Builder setCaptionPosition(int captionX, int captionY) {
+ mCaptionX = captionX;
+ mCaptionY = captionY;
+ return this;
+ }
+
+ Builder setWindowingButtonsVisible(boolean windowingButtonsVisible) {
+ mShowWindowingPill = windowingButtonsVisible;
+ return this;
+ }
+
+ HandleMenu build() {
+ return new HandleMenu(mParent, mLayoutId, mCaptionX, mCaptionY, mOnClickListener,
+ mOnTouchListener, mAppIcon, mName, mShowWindowingPill);
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 9a1b4ff..e772fc2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -458,7 +458,7 @@
SurfaceControlViewHost mWindowViewHost;
Supplier<SurfaceControl.Transaction> mTransactionSupplier;
- private AdditionalWindow(SurfaceControl surfaceControl,
+ AdditionalWindow(SurfaceControl surfaceControl,
SurfaceControlViewHost surfaceControlViewHost,
Supplier<SurfaceControl.Transaction> transactionSupplier) {
mWindowSurface = surfaceControl;
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/CompanionDeviceManager/res/layout/activity_confirmation.xml b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
index d470d4c..aae30df 100644
--- a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
@@ -16,13 +16,15 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- style="@style/ScrollViewStyle">
+ style="@style/ScrollViewStyle"
+ android:importantForAccessibility="no">
<LinearLayout
android:id="@+id/activity_confirmation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:baselineAligned="false">
+ android:baselineAligned="false"
+ android:importantForAccessibility="no">
<LinearLayout android:id="@+id/association_confirmation"
style="@style/ContainerLayout">
@@ -153,7 +155,8 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_weight="1">
+ android:layout_weight="1"
+ android:importantForAccessibility="noHideDescendants">
<ProgressBar
android:id="@+id/spinner_single_device"
diff --git a/packages/CompanionDeviceManager/res/layout/vendor_header.xml b/packages/CompanionDeviceManager/res/layout/vendor_header.xml
index 16a87e5..77c79b3 100644
--- a/packages/CompanionDeviceManager/res/layout/vendor_header.xml
+++ b/packages/CompanionDeviceManager/res/layout/vendor_header.xml
@@ -33,7 +33,7 @@
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
- android:contentDescription="@string/vendor_icon_description" />
+ android:importantForAccessibility="no" />
<TextView
android:id="@+id/vendor_header_name"
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index 256e0eb..74072e9 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -132,11 +132,8 @@
<!-- Text of the permission sync explanation in the confirmation dialog. [CHAR LIMIT=NONE] -->
<string name="permission_sync_summary">This may include <strong>Microphone</strong>, <strong>Camera</strong>, and <strong>Location access</strong>, and other sensitive permissions on <strong><xliff:g id="companion_device_name" example="My Watch">%1$s</xliff:g></strong>. <br/><br/>You can change these permissions any time in your Settings on <strong><xliff:g id="companion_device_name" example="My Watch">%1$s</xliff:g></strong>.</string>
- <!--Description for vendor icon [CHAR LIMIT=30]-->
- <string name="vendor_icon_description">App Icon</string>
-
<!--Description for information icon [CHAR LIMIT=30]-->
- <string name="vendor_header_button_description">More Information Button</string>
+ <string name="vendor_header_button_description">More Information</string>
<!-- ================= Permissions ================= -->
diff --git a/packages/CompanionDeviceManager/res/values/styles.xml b/packages/CompanionDeviceManager/res/values/styles.xml
index b167377..e85190b 100644
--- a/packages/CompanionDeviceManager/res/values/styles.xml
+++ b/packages/CompanionDeviceManager/res/values/styles.xml
@@ -36,7 +36,7 @@
</style>
<style name="DescriptionTitle"
- parent="@android:style/TextAppearance.DeviceDefault.Medium">
+ parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:gravity">center</item>
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/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 6d375ac..48259e1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -46,12 +46,16 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
+import java.util.Set;
public class SettingsHelper {
private static final String TAG = "SettingsHelper";
private static final String SILENT_RINGTONE = "_silent";
private static final String SETTINGS_REPLACED_KEY = "backup_skip_user_facing_data";
private static final String SETTING_ORIGINAL_KEY_SUFFIX = "_original";
+ private static final String UNICODE_LOCALE_EXTENSION_FW = "fw";
+ private static final String UNICODE_LOCALE_EXTENSION_MU = "mu";
+ private static final String UNICODE_LOCALE_EXTENSION_NU = "nu";
private static final float FLOAT_TOLERANCE = 0.01f;
/** See frameworks/base/core/res/res/values/config.xml#config_longPressOnPowerBehavior **/
@@ -97,6 +101,25 @@
sBroadcastOnRestoreSystemUI.add(Settings.Secure.QS_AUTO_ADDED_TILES);
}
+ private static final ArraySet<String> UNICODE_LOCALE_SUPPORTED_EXTENSIONS = new ArraySet<>();
+
+ /**
+ * Current supported extensions are fw (first day of week) and mu (temperature unit) extension.
+ * User can set these extensions in Settings app, and it will be appended to the locale,
+ * for example: zh-Hant-TW-u-fw-mon-mu-celsius. So after the factory reset, these extensions
+ * should be restored as well because they are set by users.
+ * We do not put the nu (numbering system) extension here because it is an Android supported
+ * extension and defined in some particular locales, for example:
+ * ar-Arab-MA-u-nu-arab and ar-Arab-YE-u-nu-latn. See
+ * <code>frameworks/base/core/res/res/values/locale_config.xml</code>
+ * The nu extension should not be appended to the current/restored locale after factory reset
+ * if the current/restored locale does not have it.
+ */
+ static {
+ UNICODE_LOCALE_SUPPORTED_EXTENSIONS.add(UNICODE_LOCALE_EXTENSION_FW);
+ UNICODE_LOCALE_SUPPORTED_EXTENSIONS.add(UNICODE_LOCALE_EXTENSION_MU);
+ }
+
private interface SettingsLookup {
public String lookup(ContentResolver resolver, String name, int userHandle);
}
@@ -500,20 +523,25 @@
allLocales.put(toFullLocale(locale), locale);
}
+ // After restoring to reset locales, need to get extensions from restored locale. Get the
+ // first restored locale to check its extension.
+ final Locale restoredLocale = restore.isEmpty()
+ ? Locale.ROOT
+ : restore.get(0);
final ArrayList<Locale> filtered = new ArrayList<>(current.size());
for (int i = 0; i < current.size(); i++) {
- final Locale locale = current.get(i);
+ Locale locale = copyExtensionToTargetLocale(restoredLocale, current.get(i));
allLocales.remove(toFullLocale(locale));
filtered.add(locale);
}
for (int i = 0; i < restore.size(); i++) {
- final Locale locale = allLocales.remove(toFullLocale(restore.get(i)));
- if (locale != null) {
- filtered.add(locale);
+ final Locale restoredLocaleWithExtension = copyExtensionToTargetLocale(restoredLocale,
+ getFilteredLocale(restore.get(i), allLocales));
+ if (restoredLocaleWithExtension != null) {
+ filtered.add(restoredLocaleWithExtension);
}
}
-
if (filtered.size() == current.size()) {
return current; // Nothing added to current locale list.
}
@@ -521,6 +549,45 @@
return new LocaleList(filtered.toArray(new Locale[filtered.size()]));
}
+ private static Locale copyExtensionToTargetLocale(Locale restoredLocale,
+ Locale targetLocale) {
+ if (!restoredLocale.hasExtensions()) {
+ return targetLocale;
+ }
+
+ if (targetLocale == null) {
+ return null;
+ }
+
+ Locale.Builder builder = new Locale.Builder()
+ .setLocale(targetLocale);
+ Set<String> unicodeLocaleKeys = restoredLocale.getUnicodeLocaleKeys();
+ unicodeLocaleKeys.stream().forEach(key -> {
+ // Copy all supported extensions from restored locales except "nu" extension. The "nu"
+ // extension has been added in #getFilteredLocale(Locale, HashMap<Locale, Locale>)
+ // already, we don't need to add it again.
+ if (UNICODE_LOCALE_SUPPORTED_EXTENSIONS.contains(key)) {
+ builder.setUnicodeLocaleKeyword(key, restoredLocale.getUnicodeLocaleType(key));
+ }
+ });
+ return builder.build();
+ }
+
+ private static Locale getFilteredLocale(Locale restoreLocale,
+ HashMap<Locale, Locale> allLocales) {
+ Locale locale = allLocales.remove(toFullLocale(restoreLocale));
+ if (locale != null) {
+ return locale;
+ }
+
+ Locale filteredLocale = new Locale.Builder()
+ .setLocale(restoreLocale.stripExtensions())
+ .setUnicodeLocaleKeyword(UNICODE_LOCALE_EXTENSION_NU,
+ restoreLocale.getUnicodeLocaleType(UNICODE_LOCALE_EXTENSION_NU))
+ .build();
+ return allLocales.remove(toFullLocale(filteredLocale));
+ }
+
/**
* Sets the locale specified. Input data is the byte representation of comma separated
* multiple BCP-47 language tags. For backwards compatibility, strings of the form
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/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
index ee76dbf..bc81c44 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
@@ -299,12 +299,42 @@
LocaleList.forLanguageTags("en-US"), // current
new String[] { "en-US", "zh-Hans-CN" })); // supported
- // Old langauge code should be updated.
+ // Old language code should be updated.
assertEquals(LocaleList.forLanguageTags("en-US,he-IL,id-ID,yi"),
SettingsHelper.resolveLocales(
LocaleList.forLanguageTags("iw-IL,in-ID,ji"), // restore
LocaleList.forLanguageTags("en-US"), // current
new String[] { "he-IL", "id-ID", "yi" })); // supported
+
+ // No matter the current locale has "nu" extension or not, if the restored locale has fw
+ // (first day of week) or mu(temperature unit) extension, we should restore fw or mu
+ // extensions as well and append these to restore and current locales.
+ assertEquals(LocaleList.forLanguageTags(
+ "en-US-u-fw-mon-mu-celsius,zh-Hant-TW-u-fw-mon-mu-celsius"),
+ SettingsHelper.resolveLocales(
+ LocaleList.forLanguageTags("zh-Hant-TW-u-fw-mon-mu-celsius"), // restore
+ LocaleList.forLanguageTags("en-US"), // current
+ new String[] { "en-US", "zh-Hant-TW" })); // supported
+
+ // No matter the current locale has "nu" extension or not, if the restored locale has fw
+ // (first day of week) or mu(temperature unit) extension, we should restore fw or mu
+ // extensions as well and append these to restore and current locales.
+ assertEquals(LocaleList.forLanguageTags(
+ "fa-Arab-AF-u-nu-latn-fw-mon-mu-celsius,zh-Hant-TW-u-fw-mon-mu-celsius"),
+ SettingsHelper.resolveLocales(
+ LocaleList.forLanguageTags("zh-Hant-TW-u-fw-mon-mu-celsius"), // restore
+ LocaleList.forLanguageTags("fa-Arab-AF-u-nu-latn"), // current
+ new String[] { "fa-Arab-AF-u-nu-latn", "zh-Hant-TW" })); // supported
+
+ // If the restored locale only has nu extension, we should not restore the nu extensions to
+ // current locales.
+ assertEquals(LocaleList.forLanguageTags("zh-Hant-TW,fa-Arab-AF-u-nu-latn"),
+ SettingsHelper.resolveLocales(
+ LocaleList.forLanguageTags("fa-Arab-AF-u-nu-latn"), // restore
+ LocaleList.forLanguageTags("zh-Hant-TW"), // current
+ new String[] { "fa-Arab-AF-u-nu-latn", "zh-Hant-TW" })); // supported
+
+
}
@Test
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 62c6c1d..865b0df 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -173,6 +173,7 @@
"androidx.palette_palette",
"androidx.legacy_legacy-preference-v14",
"androidx.leanback_leanback",
+ "androidx.tracing_tracing",
"androidx.slice_slice-core",
"androidx.slice_slice-view",
"androidx.slice_slice-builders",
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/animation/Android.bp b/packages/SystemUI/animation/Android.bp
index 5b5871f..8eb012d 100644
--- a/packages/SystemUI/animation/Android.bp
+++ b/packages/SystemUI/animation/Android.bp
@@ -43,6 +43,7 @@
"androidx.core_core-ktx",
"androidx.annotation_annotation",
"SystemUIShaderLib",
+ "animationlib",
],
manifest: "AndroidManifest.xml",
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 296c2ae..2e80379 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -39,9 +39,9 @@
import android.view.animation.PathInterpolator
import androidx.annotation.BinderThread
import androidx.annotation.UiThread
+import com.android.app.animation.Interpolators
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.policy.ScreenDecorationsUtils
-import java.lang.IllegalArgumentException
import kotlin.math.roundToInt
private const val TAG = "ActivityLaunchAnimator"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index 42a8636..48dd08f 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -33,10 +33,10 @@
import android.view.WindowManager
import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
import android.widget.FrameLayout
+import com.android.app.animation.Interpolators
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.jank.InteractionJankMonitor.CujType
import com.android.systemui.util.registerAnimationOnBackInvoked
-import java.lang.IllegalArgumentException
import kotlin.math.roundToInt
private const val TAG = "DialogLaunchAnimator"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
deleted file mode 100644
index 9dbb920..0000000
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2016 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.animation;
-
-import android.graphics.Path;
-import android.util.MathUtils;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.BounceInterpolator;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-import android.view.animation.PathInterpolator;
-
-/**
- * Utility class to receive interpolators from.
- *
- * Make sure that changes made to this class are also reflected in {@link InterpolatorsAndroidX}.
- * Please consider using the androidx dependencies featuring better testability altogether.
- */
-public class Interpolators {
-
- /*
- * ============================================================================================
- * Emphasized interpolators.
- * ============================================================================================
- */
-
- /**
- * The default emphasized interpolator. Used for hero / emphasized movement of content.
- */
- public static final Interpolator EMPHASIZED = createEmphasizedInterpolator();
-
- /**
- * The accelerated emphasized interpolator. Used for hero / emphasized movement of content that
- * is disappearing e.g. when moving off screen.
- */
- public static final Interpolator EMPHASIZED_ACCELERATE = new PathInterpolator(
- 0.3f, 0f, 0.8f, 0.15f);
-
- /**
- * The decelerating emphasized interpolator. Used for hero / emphasized movement of content that
- * is appearing e.g. when coming from off screen
- */
- public static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator(
- 0.05f, 0.7f, 0.1f, 1f);
-
-
- /*
- * ============================================================================================
- * Standard interpolators.
- * ============================================================================================
- */
-
- /**
- * The standard interpolator that should be used on every normal animation
- */
- public static final Interpolator STANDARD = new PathInterpolator(
- 0.2f, 0f, 0f, 1f);
-
- /**
- * The standard accelerating interpolator that should be used on every regular movement of
- * content that is disappearing e.g. when moving off screen.
- */
- public static final Interpolator STANDARD_ACCELERATE = new PathInterpolator(
- 0.3f, 0f, 1f, 1f);
-
- /**
- * The standard decelerating interpolator that should be used on every regular movement of
- * content that is appearing e.g. when coming from off screen.
- */
- public static final Interpolator STANDARD_DECELERATE = new PathInterpolator(
- 0f, 0f, 0f, 1f);
-
- /*
- * ============================================================================================
- * Legacy
- * ============================================================================================
- */
-
- /**
- * The default legacy interpolator as defined in Material 1. Also known as FAST_OUT_SLOW_IN.
- */
- public static final Interpolator LEGACY = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
-
- /**
- * The default legacy accelerating interpolator as defined in Material 1.
- * Also known as FAST_OUT_LINEAR_IN.
- */
- public static final Interpolator LEGACY_ACCELERATE = new PathInterpolator(0.4f, 0f, 1f, 1f);
-
- /**
- * The default legacy decelerating interpolator as defined in Material 1.
- * Also known as LINEAR_OUT_SLOW_IN.
- */
- public static final Interpolator LEGACY_DECELERATE = new PathInterpolator(0f, 0f, 0.2f, 1f);
-
- /**
- * Linear interpolator. Often used if the interpolator is for different properties who need
- * different interpolations.
- */
- public static final Interpolator LINEAR = new LinearInterpolator();
-
- /*
- * ============================================================================================
- * Custom interpolators
- * ============================================================================================
- */
-
- public static final Interpolator FAST_OUT_SLOW_IN = LEGACY;
- public static final Interpolator FAST_OUT_LINEAR_IN = LEGACY_ACCELERATE;
- public static final Interpolator LINEAR_OUT_SLOW_IN = LEGACY_DECELERATE;
-
- /**
- * Like {@link #FAST_OUT_SLOW_IN}, but used in case the animation is played in reverse (i.e. t
- * goes from 1 to 0 instead of 0 to 1).
- */
- public static final Interpolator FAST_OUT_SLOW_IN_REVERSE =
- new PathInterpolator(0.8f, 0f, 0.6f, 1f);
- public static final Interpolator SLOW_OUT_LINEAR_IN = new PathInterpolator(0.8f, 0f, 1f, 1f);
- public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
- public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
- public static final Interpolator ACCELERATE = new AccelerateInterpolator();
- public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator();
- public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f);
- public static final Interpolator CUSTOM_40_40 = new PathInterpolator(0.4f, 0f, 0.6f, 1f);
- public static final Interpolator ICON_OVERSHOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f);
- public static final Interpolator ICON_OVERSHOT_LESS = new PathInterpolator(0.4f, 0f, 0.2f,
- 1.1f);
- public static final Interpolator PANEL_CLOSE_ACCELERATED = new PathInterpolator(0.3f, 0, 0.5f,
- 1);
- public static final Interpolator BOUNCE = new BounceInterpolator();
- /**
- * For state transitions on the control panel that lives in GlobalActions.
- */
- public static final Interpolator CONTROL_STATE = new PathInterpolator(0.4f, 0f, 0.2f,
- 1.0f);
-
- /**
- * Interpolator to be used when animating a move based on a click. Pair with enough duration.
- */
- public static final Interpolator TOUCH_RESPONSE =
- new PathInterpolator(0.3f, 0f, 0.1f, 1f);
-
- /**
- * Like {@link #TOUCH_RESPONSE}, but used in case the animation is played in reverse (i.e. t
- * goes from 1 to 0 instead of 0 to 1).
- */
- public static final Interpolator TOUCH_RESPONSE_REVERSE =
- new PathInterpolator(0.9f, 0f, 0.7f, 1f);
-
- /*
- * ============================================================================================
- * Functions / Utilities
- * ============================================================================================
- */
-
- /**
- * Calculate the amount of overshoot using an exponential falloff function with desired
- * properties, where the overshoot smoothly transitions at the 1.0f boundary into the
- * overshoot, retaining its acceleration.
- *
- * @param progress a progress value going from 0 to 1
- * @param overshootAmount the amount > 0 of overshoot desired. A value of 0.1 means the max
- * value of the overall progress will be at 1.1.
- * @param overshootStart the point in (0,1] where the result should reach 1
- * @return the interpolated overshoot
- */
- public static float getOvershootInterpolation(float progress, float overshootAmount,
- float overshootStart) {
- if (overshootAmount == 0.0f || overshootStart == 0.0f) {
- throw new IllegalArgumentException("Invalid values for overshoot");
- }
- float b = MathUtils.log((overshootAmount + 1) / (overshootAmount)) / overshootStart;
- return MathUtils.max(0.0f,
- (float) (1.0f - Math.exp(-b * progress)) * (overshootAmount + 1.0f));
- }
-
- /**
- * Similar to {@link #getOvershootInterpolation(float, float, float)} but the overshoot
- * starts immediately here, instead of first having a section of non-overshooting
- *
- * @param progress a progress value going from 0 to 1
- */
- public static float getOvershootInterpolation(float progress) {
- return MathUtils.max(0.0f, (float) (1.0f - Math.exp(-4 * progress)));
- }
-
- // Create the default emphasized interpolator
- private static PathInterpolator createEmphasizedInterpolator() {
- Path path = new Path();
- // Doing the same as fast_out_extra_slow_in
- path.moveTo(0f, 0f);
- path.cubicTo(0.05f, 0f, 0.133333f, 0.06f, 0.166666f, 0.4f);
- path.cubicTo(0.208333f, 0.82f, 0.25f, 1f, 1f, 1f);
- return new PathInterpolator(path);
- }
-}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/InterpolatorsAndroidX.java b/packages/SystemUI/animation/src/com/android/systemui/animation/InterpolatorsAndroidX.java
deleted file mode 100644
index 8da87feb..0000000
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/InterpolatorsAndroidX.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2022 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.animation;
-
-import android.graphics.Path;
-import android.util.MathUtils;
-
-import androidx.core.animation.AccelerateDecelerateInterpolator;
-import androidx.core.animation.AccelerateInterpolator;
-import androidx.core.animation.BounceInterpolator;
-import androidx.core.animation.DecelerateInterpolator;
-import androidx.core.animation.Interpolator;
-import androidx.core.animation.LinearInterpolator;
-import androidx.core.animation.PathInterpolator;
-
-/**
- * Utility class to receive interpolators from. (androidx compatible version)
- *
- * This is the androidx compatible version of {@link Interpolators}. Make sure that changes made to
- * this class are also reflected in {@link Interpolators}.
- *
- * Using the androidx versions of {@link androidx.core.animation.ValueAnimator} or
- * {@link androidx.core.animation.ObjectAnimator} improves animation testability. This file provides
- * the androidx compatible versions of the interpolators defined in {@link Interpolators}.
- * AnimatorTestRule can be used in Tests to manipulate the animation under test (e.g. artificially
- * advancing the time).
- */
-public class InterpolatorsAndroidX {
-
- /*
- * ============================================================================================
- * Emphasized interpolators.
- * ============================================================================================
- */
-
- /**
- * The default emphasized interpolator. Used for hero / emphasized movement of content.
- */
- public static final Interpolator EMPHASIZED = createEmphasizedInterpolator();
-
- /**
- * The accelerated emphasized interpolator. Used for hero / emphasized movement of content that
- * is disappearing e.g. when moving off screen.
- */
- public static final Interpolator EMPHASIZED_ACCELERATE = new PathInterpolator(
- 0.3f, 0f, 0.8f, 0.15f);
-
- /**
- * The decelerating emphasized interpolator. Used for hero / emphasized movement of content that
- * is appearing e.g. when coming from off screen
- */
- public static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator(
- 0.05f, 0.7f, 0.1f, 1f);
-
-
- /*
- * ============================================================================================
- * Standard interpolators.
- * ============================================================================================
- */
-
- /**
- * The standard interpolator that should be used on every normal animation
- */
- public static final Interpolator STANDARD = new PathInterpolator(
- 0.2f, 0f, 0f, 1f);
-
- /**
- * The standard accelerating interpolator that should be used on every regular movement of
- * content that is disappearing e.g. when moving off screen.
- */
- public static final Interpolator STANDARD_ACCELERATE = new PathInterpolator(
- 0.3f, 0f, 1f, 1f);
-
- /**
- * The standard decelerating interpolator that should be used on every regular movement of
- * content that is appearing e.g. when coming from off screen.
- */
- public static final Interpolator STANDARD_DECELERATE = new PathInterpolator(
- 0f, 0f, 0f, 1f);
-
- /*
- * ============================================================================================
- * Legacy
- * ============================================================================================
- */
-
- /**
- * The default legacy interpolator as defined in Material 1. Also known as FAST_OUT_SLOW_IN.
- */
- public static final Interpolator LEGACY = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
-
- /**
- * The default legacy accelerating interpolator as defined in Material 1.
- * Also known as FAST_OUT_LINEAR_IN.
- */
- public static final Interpolator LEGACY_ACCELERATE = new PathInterpolator(0.4f, 0f, 1f, 1f);
-
- /**
- * The default legacy decelerating interpolator as defined in Material 1.
- * Also known as LINEAR_OUT_SLOW_IN.
- */
- public static final Interpolator LEGACY_DECELERATE = new PathInterpolator(0f, 0f, 0.2f, 1f);
-
- /**
- * Linear interpolator. Often used if the interpolator is for different properties who need
- * different interpolations.
- */
- public static final Interpolator LINEAR = new LinearInterpolator();
-
- /*
- * ============================================================================================
- * Custom interpolators
- * ============================================================================================
- */
-
- public static final Interpolator FAST_OUT_SLOW_IN = LEGACY;
- public static final Interpolator FAST_OUT_LINEAR_IN = LEGACY_ACCELERATE;
- public static final Interpolator LINEAR_OUT_SLOW_IN = LEGACY_DECELERATE;
-
- /**
- * Like {@link #FAST_OUT_SLOW_IN}, but used in case the animation is played in reverse (i.e. t
- * goes from 1 to 0 instead of 0 to 1).
- */
- public static final Interpolator FAST_OUT_SLOW_IN_REVERSE =
- new PathInterpolator(0.8f, 0f, 0.6f, 1f);
- public static final Interpolator SLOW_OUT_LINEAR_IN = new PathInterpolator(0.8f, 0f, 1f, 1f);
- public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
- public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
- public static final Interpolator ACCELERATE = new AccelerateInterpolator();
- public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator();
- public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f);
- public static final Interpolator CUSTOM_40_40 = new PathInterpolator(0.4f, 0f, 0.6f, 1f);
- public static final Interpolator ICON_OVERSHOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f);
- public static final Interpolator ICON_OVERSHOT_LESS = new PathInterpolator(0.4f, 0f, 0.2f,
- 1.1f);
- public static final Interpolator PANEL_CLOSE_ACCELERATED = new PathInterpolator(0.3f, 0, 0.5f,
- 1);
- public static final Interpolator BOUNCE = new BounceInterpolator();
- /**
- * For state transitions on the control panel that lives in GlobalActions.
- */
- public static final Interpolator CONTROL_STATE = new PathInterpolator(0.4f, 0f, 0.2f,
- 1.0f);
-
- /**
- * Interpolator to be used when animating a move based on a click. Pair with enough duration.
- */
- public static final Interpolator TOUCH_RESPONSE =
- new PathInterpolator(0.3f, 0f, 0.1f, 1f);
-
- /**
- * Like {@link #TOUCH_RESPONSE}, but used in case the animation is played in reverse (i.e. t
- * goes from 1 to 0 instead of 0 to 1).
- */
- public static final Interpolator TOUCH_RESPONSE_REVERSE =
- new PathInterpolator(0.9f, 0f, 0.7f, 1f);
-
- /*
- * ============================================================================================
- * Functions / Utilities
- * ============================================================================================
- */
-
- /**
- * Calculate the amount of overshoot using an exponential falloff function with desired
- * properties, where the overshoot smoothly transitions at the 1.0f boundary into the
- * overshoot, retaining its acceleration.
- *
- * @param progress a progress value going from 0 to 1
- * @param overshootAmount the amount > 0 of overshoot desired. A value of 0.1 means the max
- * value of the overall progress will be at 1.1.
- * @param overshootStart the point in (0,1] where the result should reach 1
- * @return the interpolated overshoot
- */
- public static float getOvershootInterpolation(float progress, float overshootAmount,
- float overshootStart) {
- if (overshootAmount == 0.0f || overshootStart == 0.0f) {
- throw new IllegalArgumentException("Invalid values for overshoot");
- }
- float b = MathUtils.log((overshootAmount + 1) / (overshootAmount)) / overshootStart;
- return MathUtils.max(0.0f,
- (float) (1.0f - Math.exp(-b * progress)) * (overshootAmount + 1.0f));
- }
-
- /**
- * Similar to {@link #getOvershootInterpolation(float, float, float)} but the overshoot
- * starts immediately here, instead of first having a section of non-overshooting
- *
- * @param progress a progress value going from 0 to 1
- */
- public static float getOvershootInterpolation(float progress) {
- return MathUtils.max(0.0f, (float) (1.0f - Math.exp(-4 * progress)));
- }
-
- // Create the default emphasized interpolator
- private static PathInterpolator createEmphasizedInterpolator() {
- Path path = new Path();
- // Doing the same as fast_out_extra_slow_in
- path.moveTo(0f, 0f);
- path.cubicTo(0.05f, 0f, 0.133333f, 0.06f, 0.166666f, 0.4f);
- path.cubicTo(0.208333f, 0.82f, 0.25f, 1f, 1f, 1f);
- return new PathInterpolator(path);
- }
-}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
index 3417ffd..142fd21 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
@@ -28,7 +28,7 @@
import android.view.View
import android.view.ViewGroup
import android.view.animation.Interpolator
-import com.android.systemui.animation.Interpolators.LINEAR
+import com.android.app.animation.Interpolators.LINEAR
import kotlin.math.roundToInt
private const val TAG = "LaunchAnimator"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
index 3ee97be..9346a2f 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
@@ -24,12 +24,30 @@
import android.graphics.Typeface
import android.graphics.fonts.Font
import android.text.Layout
+import android.text.TextPaint
import android.util.LruCache
private const val DEFAULT_ANIMATION_DURATION: Long = 300
private const val TYPEFACE_CACHE_MAX_ENTRIES = 5
typealias GlyphCallback = (TextAnimator.PositionedGlyph, Float) -> Unit
+
+interface TypefaceVariantCache {
+ fun getTypefaceForVariant(fvar: String, targetPaint: TextPaint): Typeface?
+}
+
+class TypefaceVariantCacheImpl() : TypefaceVariantCache {
+ private val cache = LruCache<String, Typeface>(TYPEFACE_CACHE_MAX_ENTRIES)
+ override fun getTypefaceForVariant(fvar: String, targetPaint: TextPaint): Typeface? {
+ cache.get(fvar)?.let {
+ return it
+ }
+
+ targetPaint.fontVariationSettings = fvar
+ return targetPaint.typeface?.also { cache.put(fvar, it) }
+ }
+}
+
/**
* This class provides text animation between two styles.
*
@@ -56,9 +74,19 @@
* ```
* </code> </pre>
*/
-class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) {
+class TextAnimator(
+ layout: Layout,
+ private val invalidateCallback: () -> Unit,
+) {
+ var typefaceCache: TypefaceVariantCache = TypefaceVariantCacheImpl()
+ get() = field
+ set(value) {
+ field = value
+ textInterpolator.typefaceCache = value
+ }
+
// Following two members are for mutable for testing purposes.
- public var textInterpolator: TextInterpolator = TextInterpolator(layout)
+ public var textInterpolator: TextInterpolator = TextInterpolator(layout, typefaceCache)
public var animator: ValueAnimator =
ValueAnimator.ofFloat(1f).apply {
duration = DEFAULT_ANIMATION_DURATION
@@ -68,9 +96,7 @@
}
addListener(
object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator?) {
- textInterpolator.rebase()
- }
+ override fun onAnimationEnd(animation: Animator?) = textInterpolator.rebase()
override fun onAnimationCancel(animation: Animator?) = textInterpolator.rebase()
}
)
@@ -116,8 +142,6 @@
private val fontVariationUtils = FontVariationUtils()
- private val typefaceCache = LruCache<String, Typeface>(TYPEFACE_CACHE_MAX_ENTRIES)
-
fun updateLayout(layout: Layout) {
textInterpolator.layout = layout
}
@@ -220,12 +244,8 @@
}
if (!fvar.isNullOrBlank()) {
- textInterpolator.targetPaint.typeface = typefaceCache.get(fvar) ?: run {
- textInterpolator.targetPaint.fontVariationSettings = fvar
- textInterpolator.targetPaint.typeface?.also {
- typefaceCache.put(fvar, textInterpolator.targetPaint.typeface)
- }
- }
+ textInterpolator.targetPaint.typeface =
+ typefaceCache.getTypefaceForVariant(fvar, textInterpolator.targetPaint)
}
if (color != null) {
@@ -304,7 +324,8 @@
weight = weight,
width = width,
opticalSize = opticalSize,
- roundness = roundness,)
+ roundness = roundness,
+ )
setTextStyle(
fvar = fvar,
textSize = textSize,
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
index 23f16f2..a041926 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
@@ -28,8 +28,10 @@
import java.lang.Math.max
/** Provide text style linear interpolation for plain text. */
-class TextInterpolator(layout: Layout) {
-
+class TextInterpolator(
+ layout: Layout,
+ var typefaceCache: TypefaceVariantCache,
+) {
/**
* Returns base paint used for interpolation.
*
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
index 58ffef2..8e79e3c 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
@@ -25,6 +25,7 @@
import android.view.View
import android.view.ViewGroup
import android.view.animation.Interpolator
+import com.android.app.animation.Interpolators
import kotlin.math.max
import kotlin.math.min
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
index f3d8b17..dd32851 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
@@ -19,7 +19,7 @@
import android.util.DisplayMetrics
import android.view.animation.Interpolator
import android.window.BackEvent
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.util.dpToPx
/** Used to convert [BackEvent] into a [BackTransformation]. */
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
index 387b67d..520c888 100644
--- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
@@ -40,7 +40,8 @@
SoftwareBitmapDetector.ISSUE,
NonInjectedServiceDetector.ISSUE,
StaticSettingsProviderDetector.ISSUE,
- DemotingTestWithoutBugDetector.ISSUE
+ DemotingTestWithoutBugDetector.ISSUE,
+ TestFunctionNameViolationDetector.ISSUE,
)
override val api: Int
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/TestFunctionNameViolationDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/TestFunctionNameViolationDetector.kt
new file mode 100644
index 0000000..d91c7e5
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/TestFunctionNameViolationDetector.kt
@@ -0,0 +1,89 @@
+/*
+ * 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.systemui.lint
+
+import com.android.tools.lint.detector.api.AnnotationInfo
+import com.android.tools.lint.detector.api.AnnotationUsageInfo
+import com.android.tools.lint.detector.api.AnnotationUsageType
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.getParentOfType
+import org.jetbrains.uast.kotlin.KotlinUAnnotation
+import org.jetbrains.uast.kotlin.KotlinUMethod
+
+/**
+ * Detects test function naming violations regarding use of the backtick-wrapped space-allowed
+ * feature of Kotlin functions.
+ */
+class TestFunctionNameViolationDetector : Detector(), SourceCodeScanner {
+
+ override fun applicableAnnotations(): List<String> = listOf(ANNOTATION)
+ override fun isApplicableAnnotationUsage(type: AnnotationUsageType): Boolean = true
+
+ @Suppress("UnstableApiUsage")
+ override fun visitAnnotationUsage(
+ context: JavaContext,
+ element: UElement,
+ annotationInfo: AnnotationInfo,
+ usageInfo: AnnotationUsageInfo,
+ ) {
+ (element as? KotlinUAnnotation)?.getParentOfType(KotlinUMethod::class.java)?.let { method ->
+ if (method.name.contains(" ")) {
+ context.report(
+ issue = ISSUE,
+ scope = method.nameIdentifier,
+ location = context.getLocation(method.nameIdentifier),
+ message =
+ "Spaces are not allowed in test names. Use pascalCase_withUnderScores" +
+ " instead.",
+ )
+ }
+ }
+ }
+
+ companion object {
+ private const val ANNOTATION = "org.junit.Test"
+
+ @JvmStatic
+ val ISSUE =
+ Issue.create(
+ id = "TestFunctionNameViolation",
+ briefDescription = "Spaces not allowed in test function names.",
+ explanation =
+ """
+ We don't allow test function names because it leads to issues with our test
+ harness system (for example, see b/277739595). Please use
+ pascalCase_withUnderScores instead.
+ """,
+ category = Category.TESTING,
+ priority = 8,
+ severity = Severity.FATAL,
+ implementation =
+ Implementation(
+ TestFunctionNameViolationDetector::class.java,
+ Scope.JAVA_FILE_SCOPE,
+ ),
+ )
+ }
+}
diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/TestFunctionNameViolationDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/TestFunctionNameViolationDetectorTest.kt
new file mode 100644
index 0000000..db73154
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/TestFunctionNameViolationDetectorTest.kt
@@ -0,0 +1,103 @@
+/*
+ * 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.systemui.lint
+
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+
+@Suppress("UnstableApiUsage")
+class TestFunctionNameViolationDetectorTest : SystemUILintDetectorTest() {
+ override fun getDetector(): Detector {
+ return TestFunctionNameViolationDetector()
+ }
+
+ override fun getIssues(): List<Issue> {
+ return listOf(
+ TestFunctionNameViolationDetector.ISSUE,
+ )
+ }
+
+ @Test
+ fun violations() {
+ lint()
+ .files(
+ kotlin(
+ """
+ package test.pkg.name
+
+ import org.junit.Test
+
+ class MyTest {
+ @Test
+ fun `illegal test name - violation should be detected`() {
+ // some test code here.
+ }
+
+ @Test
+ fun legitimateTestName_doesNotViolate() {
+ // some test code here.
+ }
+
+ fun helperFunction_doesNotViolate() {
+ // some code.
+ }
+
+ fun `helper function - does not violate`() {
+ // some code.
+ }
+ }
+ """
+ .trimIndent()
+ ),
+ testAnnotationStub,
+ )
+ .issues(
+ TestFunctionNameViolationDetector.ISSUE,
+ )
+ .run()
+ .expectWarningCount(0)
+ .expect(
+ """
+ src/test/pkg/name/MyTest.kt:7: Error: Spaces are not allowed in test names. Use pascalCase_withUnderScores instead. [TestFunctionNameViolation]
+ fun `illegal test name - violation should be detected`() {
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 1 errors, 0 warnings
+ """
+ )
+ }
+
+ companion object {
+ private val testAnnotationStub: TestFile =
+ kotlin(
+ """
+ package org.junit
+
+ import java.lang.annotation.ElementType
+ import java.lang.annotation.Retention
+ import java.lang.annotation.RetentionPolicy
+ import java.lang.annotation.Target
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.METHOD})
+ annotation class Test
+ """
+ )
+ }
+}
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..3688f9e 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
@@ -29,9 +29,9 @@
import android.util.AttributeSet
import android.util.MathUtils
import android.widget.TextView
+import com.android.app.animation.Interpolators
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.animation.GlyphCallback
-import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.TextAnimator
import com.android.systemui.customization.R
import com.android.systemui.plugins.log.LogBuffer
@@ -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/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardQuickAffordancePreviewConstants.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardPreviewConstants.kt
similarity index 86%
rename from packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardQuickAffordancePreviewConstants.kt
rename to packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardPreviewConstants.kt
index bf922bc..08ee602 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardQuickAffordancePreviewConstants.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardPreviewConstants.kt
@@ -17,7 +17,9 @@
package com.android.systemui.shared.quickaffordance.shared.model
-object KeyguardQuickAffordancePreviewConstants {
+object KeyguardPreviewConstants {
+ const val MESSAGE_ID_HIDE_SMART_SPACE = 1111
+ const val KEY_HIDE_SMART_SPACE = "hide_smart_space"
const val MESSAGE_ID_SLOT_SELECTED = 1337
const val KEY_SLOT_ID = "slot_id"
const val KEY_INITIALLY_SELECTED_SLOT_ID = "initially_selected_slot_id"
diff --git a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
index f59bf8e..64d766d 100644
--- a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
+++ b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
@@ -26,8 +26,8 @@
import android.graphics.Color
import android.util.AttributeSet
import android.view.View
+import com.android.app.animation.Interpolators
import com.android.settingslib.Utils
-import com.android.systemui.animation.Interpolators
/** Displays security messages for the keyguard bouncer. */
open class BouncerKeyguardMessageArea(context: Context?, attrs: AttributeSet?) :
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index a6c782d..a30cae9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -15,9 +15,9 @@
import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting;
+import com.android.app.animation.Interpolators;
import com.android.keyguard.dagger.KeyguardStatusViewScope;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.ClockController;
import com.android.systemui.plugins.log.LogBuffer;
import com.android.systemui.plugins.log.LogLevel;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 0394754..0982030 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -32,9 +32,9 @@
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
+import com.android.app.animation.Interpolators;
import com.android.settingslib.animation.DisappearAnimationUtils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt;
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 33bea02..1d7c35d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -45,11 +45,11 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.TextViewInputDisabler;
import com.android.systemui.DejankUtils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
/**
* Displays an alphanumeric (latin-1) key entry for the user to enter
* an unlock password
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 0a91150..b4ddc9a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -34,9 +34,9 @@
import android.view.KeyEvent;
import android.view.View;
+import com.android.app.animation.Interpolators;
import com.android.internal.widget.LockscreenCredential;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import java.util.ArrayList;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index ba5a8c9..78021ad 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -32,7 +32,7 @@
import static androidx.constraintlayout.widget.ConstraintSet.TOP;
import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT;
-import static com.android.systemui.animation.InterpolatorsAndroidX.DECELERATE_QUINT;
+import static com.android.app.animation.InterpolatorsAndroidX.DECELERATE_QUINT;
import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
import static java.lang.Integer.max;
@@ -86,6 +86,7 @@
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringAnimation;
+import com.android.app.animation.Interpolators;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
@@ -96,7 +97,6 @@
import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.classifier.FalsingA11yDelegate;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.SysUiStatsLog;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
index c9128e5..96ac8ad 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
@@ -26,9 +26,9 @@
import android.view.View
import android.view.ViewGroup
import android.view.animation.AnimationUtils
+import com.android.app.animation.Interpolators
import com.android.internal.R.interpolator.fast_out_extra_slow_in
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
/** Animates constraint layout changes for the security view. */
class KeyguardSecurityViewTransition : Transition() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 65a7166..b4f124a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -44,11 +44,11 @@
import androidx.slice.widget.RowContent;
import androidx.slice.widget.SliceContent;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index edfcb8d..89e7e17 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -40,11 +40,11 @@
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
+import com.android.app.animation.Interpolators;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.keyguard.KeyguardClockSwitch.ClockSize;
import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.ClockController;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
index 651c979..aa652fa 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
@@ -21,7 +21,7 @@
import android.util.Property;
import android.view.View;
-import com.android.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
import com.android.systemui.plugins.log.LogBuffer;
import com.android.systemui.plugins.log.LogLevel;
import com.android.systemui.statusbar.StatusBarState;
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
index ad66909..e761123 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
@@ -30,7 +30,7 @@
import androidx.annotation.StyleRes;
-import com.android.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
/**
* Provides background color and radius animations for key pad buttons.
diff --git a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
index 14810d9..c4ecb39 100644
--- a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
+++ b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
@@ -35,9 +35,9 @@
import androidx.core.graphics.drawable.DrawableCompat;
+import com.android.app.animation.Interpolators;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
/**
* This class contains implementation for methods that will be used when user has set a
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/DisplayCutoutBaseView.kt b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
index de82ca0..c1871e0 100644
--- a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
+++ b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
@@ -36,7 +36,7 @@
import android.view.View
import androidx.annotation.VisibleForTesting
import com.android.systemui.RegionInterceptingFrameLayout.RegionInterceptableView
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.util.asIndenting
import java.io.PrintWriter
diff --git a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
index a3e7d71..e72ad82 100644
--- a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
@@ -34,7 +34,7 @@
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.settingslib.Utils
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.biometrics.AuthController
import com.android.systemui.log.ScreenDecorationsLogger
import com.android.systemui.plugins.statusbar.StatusBarStateController
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 2503520..9adfcc9 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -43,8 +43,8 @@
import androidx.annotation.VisibleForTesting;
+import com.android.app.animation.Interpolators;
import com.android.internal.dynamicanimation.animation.SpringForce;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.FalsingManager;
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
index 6e8275f..7bfd84e 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
@@ -346,6 +346,15 @@
setSystemGestureExclusion();
mIsVisible = true;
mCallback.onSettingsPanelVisibilityChanged(/* shown= */ true);
+
+ if (resetPosition) {
+ // We could not put focus on the settings panel automatically
+ // since it is an inactive window. Therefore, we announce the existence of
+ // magnification settings for accessibility when it is opened.
+ mSettingView.announceForAccessibility(
+ mContext.getResources().getString(
+ R.string.accessibility_magnification_settings_panel_description));
+ }
}
mContext.registerReceiver(mScreenOffReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
index d6f0b59..d491975 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
@@ -32,8 +32,8 @@
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
+import com.android.app.animation.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
/**
* Visually discloses that contextual data was provided to an assistant.
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index 0002ae9..2aac056 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -45,9 +45,9 @@
import androidx.annotation.StyleRes;
import androidx.annotation.VisibleForTesting;
+import com.android.app.animation.Interpolators;
import com.android.systemui.DualToneHandler;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.policy.BatteryController;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index aeebb01..be585ed 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -59,11 +59,11 @@
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.biometrics.AuthController.ScaleFactorProvider;
import com.android.systemui.biometrics.domain.interactor.BiometricPromptCredentialInteractor;
import com.android.systemui.biometrics.ui.CredentialView;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index e0b9f01..782a10b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -23,14 +23,17 @@
import android.graphics.Point
import android.hardware.biometrics.BiometricFingerprintConstants
import android.hardware.biometrics.BiometricSourceType
+import android.util.DisplayMetrics
import androidx.annotation.VisibleForTesting
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.keyguard.logging.KeyguardLogger
import com.android.settingslib.Utils
import com.android.settingslib.udfps.UdfpsOverlayParams
+import com.android.systemui.CoreStartable
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.WakefulnessLifecycle
@@ -39,12 +42,11 @@
import com.android.systemui.statusbar.CircleReveal
import com.android.systemui.statusbar.LiftReveal
import com.android.systemui.statusbar.LightRevealEffect
+import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.phone.BiometricUnlockController
-import com.android.systemui.statusbar.phone.CentralSurfaces
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.ViewController
@@ -60,9 +62,8 @@
*
* The ripple uses the accent color of the current theme.
*/
-@CentralSurfacesScope
+@SysUISingleton
class AuthRippleController @Inject constructor(
- private val centralSurfaces: CentralSurfaces,
private val sysuiContext: Context,
private val authController: AuthController,
private val configurationController: ConfigurationController,
@@ -73,12 +74,15 @@
private val notificationShadeWindowController: NotificationShadeWindowController,
private val udfpsControllerProvider: Provider<UdfpsController>,
private val statusBarStateController: StatusBarStateController,
+ private val displayMetrics: DisplayMetrics,
private val featureFlags: FeatureFlags,
private val logger: KeyguardLogger,
private val biometricUnlockController: BiometricUnlockController,
+ private val lightRevealScrim: LightRevealScrim,
rippleView: AuthRippleView?
) :
ViewController<AuthRippleView>(rippleView),
+ CoreStartable,
KeyguardStateController.Callback,
WakefulnessLifecycle.Observer {
@@ -92,6 +96,10 @@
private var udfpsController: UdfpsController? = null
private var udfpsRadius: Float = -1f
+ override fun start() {
+ init()
+ }
+
@VisibleForTesting
public override fun onViewAttached() {
authController.addCallback(authControllerCallback)
@@ -153,8 +161,8 @@
it.y,
0,
Math.max(
- Math.max(it.x, centralSurfaces.displayWidth.toInt() - it.x),
- Math.max(it.y, centralSurfaces.displayHeight.toInt() - it.y)
+ Math.max(it.x, displayMetrics.widthPixels - it.x),
+ Math.max(it.y, displayMetrics.heightPixels - it.y)
)
)
logger.showingUnlockRippleAt(it.x, it.y, "FP sensor radius: $udfpsRadius")
@@ -168,8 +176,8 @@
it.y,
0,
Math.max(
- Math.max(it.x, centralSurfaces.displayWidth.toInt() - it.x),
- Math.max(it.y, centralSurfaces.displayHeight.toInt() - it.y)
+ Math.max(it.x, displayMetrics.widthPixels - it.x),
+ Math.max(it.y, displayMetrics.heightPixels - it.y)
)
)
logger.showingUnlockRippleAt(it.x, it.y, "Face unlock ripple")
@@ -184,11 +192,10 @@
// This code path is not used if the KeyguardTransitionRepository is managing the light
// reveal scrim.
if (!featureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)) {
- val lightRevealScrim = centralSurfaces.lightRevealScrim
if (statusBarStateController.isDozing || biometricUnlockController.isWakeAndUnlock) {
circleReveal?.let {
- lightRevealScrim?.revealAmount = 0f
- lightRevealScrim?.revealEffect = it
+ lightRevealScrim.revealAmount = 0f
+ lightRevealScrim.revealEffect = it
startLightRevealScrimOnKeyguardFadingAway = true
}
}
@@ -208,8 +215,7 @@
}
if (keyguardStateController.isKeyguardFadingAway) {
- val lightRevealScrim = centralSurfaces.lightRevealScrim
- if (startLightRevealScrimOnKeyguardFadingAway && lightRevealScrim != null) {
+ if (startLightRevealScrimOnKeyguardFadingAway) {
lightRevealScrimAnimator?.cancel()
lightRevealScrimAnimator = ValueAnimator.ofFloat(.1f, 1f).apply {
interpolator = Interpolators.LINEAR_OUT_SLOW_IN
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index b007134..5ede16d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -28,7 +28,7 @@
import android.view.View
import android.view.animation.PathInterpolator
import com.android.internal.graphics.ColorUtils
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.surfaceeffects.ripple.RippleShader
private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.3f
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
index ef7dcb7..1dbafc6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
@@ -19,7 +19,7 @@
import android.graphics.PointF
import android.graphics.RectF
import com.android.systemui.Dumpable
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.ShadeExpansionListener
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index ba8e60a..52db4ab 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -40,9 +40,9 @@
import androidx.annotation.Nullable;
import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
+import com.android.app.animation.Interpolators;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.airbnb.lottie.LottieAnimationView;
import com.airbnb.lottie.LottieProperty;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
index 3b50bbc..eaab75a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
@@ -23,11 +23,11 @@
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.animation.Interpolators
import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.R
import com.android.systemui.animation.ActivityLaunchAnimator
-import com.android.systemui.animation.Interpolators
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
index e2d36dc..9292bd7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
@@ -6,8 +6,8 @@
import android.widget.TextView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.animation.Interpolators
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
import com.android.systemui.biometrics.AuthDialog
import com.android.systemui.biometrics.AuthPanelController
import com.android.systemui.biometrics.ui.CredentialPasswordView
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
index 11ef749..7bf8f4d 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
@@ -30,9 +30,9 @@
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.app.animation.Interpolators;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.surfaceeffects.ripple.RippleShader;
import com.android.systemui.surfaceeffects.ripple.RippleShader.RippleShape;
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java
index 1fa9ac5..1ffbe32 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java
@@ -72,7 +72,7 @@
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Package not found: " + mClipboardManager.getPrimaryClipSource(), e);
}
- mEditText.setText(clip.getItemAt(0).getText());
+ mEditText.setText(clip.getItemAt(0).getText().toString());
mEditText.requestFocus();
mEditText.setSelection(0);
mSensitive = clip.getDescription().getExtras() != null
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
index 8d0edf8..b447d66 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
@@ -32,7 +32,7 @@
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.controls.ui.ControlsUiController
object ControlsAnimations {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index 6a9aaf8..e6361f4 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -50,7 +50,7 @@
import androidx.annotation.VisibleForTesting
import com.android.internal.graphics.ColorUtils
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.controls.ControlsMetricsLogger
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.util.concurrency.DelayableExecutor
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
index fa36eee..1461135 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -38,7 +38,7 @@
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.controls.ui.ControlViewHolder.Companion.MAX_LEVEL
import com.android.systemui.controls.ui.ControlViewHolder.Companion.MIN_LEVEL
import java.util.IllegalFormatException
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 0be3bb6..0dcba50 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -50,6 +50,7 @@
import android.content.pm.ShortcutManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
+import android.graphics.Color;
import android.hardware.SensorManager;
import android.hardware.SensorPrivacyManager;
import android.hardware.biometrics.BiometricManager;
@@ -113,13 +114,13 @@
import com.android.systemui.dagger.qualifiers.TestHarness;
import com.android.systemui.shared.system.PackageManagerWrapper;
+import dagger.Module;
+import dagger.Provides;
+
import java.util.Optional;
import javax.inject.Singleton;
-import dagger.Module;
-import dagger.Provides;
-
/**
* Provides Non-SystemUI, Framework-Owned instances to the dependency graph.
*/
@@ -323,7 +324,9 @@
@Provides
@Singleton
static InteractionJankMonitor provideInteractionJankMonitor() {
- return InteractionJankMonitor.getInstance();
+ InteractionJankMonitor jankMonitor = InteractionJankMonitor.getInstance();
+ jankMonitor.configDebugOverlay(Color.YELLOW, 0.75);
+ return jankMonitor;
}
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index 5b56c04..83f39b5 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -24,8 +24,8 @@
import androidx.core.animation.doOnEnd
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.animation.Interpolators
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
import com.android.systemui.complication.ComplicationHostViewController
import com.android.systemui.complication.ComplicationLayoutParams
import com.android.systemui.complication.ComplicationLayoutParams.POSITION_BOTTOM
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 15a32d2..c22019e 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -33,9 +33,9 @@
import androidx.annotation.NonNull;
+import com.android.app.animation.Interpolators;
import com.android.dream.lowlight.LowLightTransitionCoordinator;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.complication.ComplicationHostViewController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
index 5bbfbda..3ef19b7 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
@@ -16,12 +16,9 @@
package com.android.systemui.dreams.conditions;
import android.app.DreamManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.text.TextUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.shared.condition.Condition;
import javax.inject.Inject;
@@ -30,48 +27,33 @@
* {@link DreamCondition} provides a signal when a dream begins and ends.
*/
public class DreamCondition extends Condition {
- private final Context mContext;
private final DreamManager mDreamManager;
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- processIntent(intent);
- }
- };
+ private final KeyguardUpdateMonitor mUpdateMonitor;
+
+
+ private final KeyguardUpdateMonitorCallback mUpdateCallback =
+ new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onDreamingStateChanged(boolean dreaming) {
+ updateCondition(dreaming);
+ }
+ };
@Inject
- public DreamCondition(Context context,
- DreamManager dreamManager) {
- mContext = context;
+ public DreamCondition(DreamManager dreamManager, KeyguardUpdateMonitor monitor) {
mDreamManager = dreamManager;
- }
-
- private void processIntent(Intent intent) {
- // In the case of a non-existent sticky broadcast, ignore when there is no intent.
- if (intent == null) {
- return;
- }
- if (TextUtils.equals(intent.getAction(), Intent.ACTION_DREAMING_STARTED)) {
- updateCondition(true);
- } else if (TextUtils.equals(intent.getAction(), Intent.ACTION_DREAMING_STOPPED)) {
- updateCondition(false);
- } else {
- throw new IllegalStateException("unexpected intent:" + intent);
- }
+ mUpdateMonitor = monitor;
}
@Override
protected void start() {
- final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_DREAMING_STARTED);
- filter.addAction(Intent.ACTION_DREAMING_STOPPED);
- mContext.registerReceiver(mReceiver, filter);
+ mUpdateMonitor.registerCallback(mUpdateCallback);
updateCondition(mDreamManager.isDreaming());
}
@Override
protected void stop() {
- mContext.unregisterReceiver(mReceiver);
+ mUpdateMonitor.removeCallback(mUpdateCallback);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 05153b6..2ecb0a0 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -110,7 +110,7 @@
// TODO(b/275694445): Tracking Bug
@JvmField
- val LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING = unreleasedFlag(208,
+ val LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING = releasedFlag(208,
"lockscreen_without_secure_lock_when_dreaming")
/**
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index d3b6fc2..5189944 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -97,6 +97,7 @@
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
+import com.android.app.animation.Interpolators;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
@@ -116,7 +117,6 @@
import com.android.systemui.animation.DialogCuj;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.animation.Expandable;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Background;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 2d1b7ae..9844ca0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -36,7 +36,7 @@
import com.android.internal.R
import com.android.keyguard.KeyguardClockSwitchController
import com.android.keyguard.KeyguardViewController
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
@@ -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..99a9bed5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -98,6 +98,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import com.android.app.animation.Interpolators;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.internal.policy.IKeyguardDismissCallback;
@@ -121,7 +122,6 @@
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.animation.LaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollector;
@@ -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/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index e6568f2..cde67f9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
index c2d139c..7e9cbc1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index 86f65dde..aca4019 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 3beac0b..fc7bfb4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
index b5bcd45..39c630b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 87f3164..0505d37 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
index 1fbfff9..944adba 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index 94961cb..d4af381 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -17,10 +17,10 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
+import com.android.app.animation.Interpolators
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Password
import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
index 38b9d50..9d7477c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui
import android.view.animation.Interpolator
-import com.android.systemui.animation.Interpolators.LINEAR
+import com.android.app.animation.Interpolators.LINEAR
import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED
import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
index d96609c..c8d37a1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
@@ -32,11 +32,11 @@
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.animation.Interpolators
import com.android.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.animation.Expandable
-import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.view.LaunchableLinearLayout
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.binder.IconViewBinder
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index 9aecb5d..85fb565 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -39,7 +39,8 @@
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
import com.android.systemui.shared.clocks.ClockRegistry
import com.android.systemui.shared.clocks.shared.model.ClockPreviewConstants
-import com.android.systemui.shared.quickaffordance.shared.model.KeyguardQuickAffordancePreviewConstants
+import com.android.systemui.shared.quickaffordance.shared.model.KeyguardPreviewConstants
+import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
import com.android.systemui.statusbar.phone.KeyguardBottomAreaView
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
@@ -59,6 +60,7 @@
private val clockController: ClockEventController,
private val clockRegistry: ClockRegistry,
private val broadcastDispatcher: BroadcastDispatcher,
+ private val lockscreenSmartspaceController: LockscreenSmartspaceController,
@Assisted bundle: Bundle,
) {
@@ -67,7 +69,7 @@
private val height: Int = bundle.getInt(KEY_VIEW_HEIGHT)
private val shouldHighlightSelectedAffordance: Boolean =
bundle.getBoolean(
- KeyguardQuickAffordancePreviewConstants.KEY_HIGHLIGHT_QUICK_AFFORDANCES,
+ KeyguardPreviewConstants.KEY_HIGHLIGHT_QUICK_AFFORDANCES,
false,
)
private val shouldHideClock: Boolean =
@@ -79,6 +81,7 @@
get() = host.surfacePackage
private var clockView: View? = null
+ private var smartSpaceView: View? = null
private val disposables = mutableSetOf<DisposableHandle>()
private var isDestroyed = false
@@ -87,7 +90,7 @@
bottomAreaViewModel.enablePreviewMode(
initiallySelectedSlotId =
bundle.getString(
- KeyguardQuickAffordancePreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID,
+ KeyguardPreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID,
),
shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance,
)
@@ -108,9 +111,10 @@
val rootView = FrameLayout(context)
setUpBottomArea(rootView)
- if (!shouldHideClock) {
- setUpClock(rootView)
- }
+
+ setupSmartspace(rootView)
+
+ setUpClock(rootView)
rootView.measure(
View.MeasureSpec.makeMeasureSpec(
@@ -147,9 +151,62 @@
fun destroy() {
isDestroyed = true
+ lockscreenSmartspaceController.disconnect()
disposables.forEach { it.dispose() }
}
+ fun hideSmartspace(hide: Boolean) {
+ smartSpaceView?.visibility = if (hide) View.INVISIBLE else View.VISIBLE
+ }
+
+ /**
+ * This sets up and shows a non-interactive smart space
+ *
+ * The top padding is as follows:
+ * Status bar height + clock top margin + keyguard smart space top offset
+ *
+ * The start padding is as follows:
+ * Clock padding start + Below clock padding start
+ *
+ * The end padding is as follows:
+ * Below clock padding end
+ */
+ private fun setupSmartspace(parentView: ViewGroup) {
+ if (!lockscreenSmartspaceController.isEnabled() ||
+ !lockscreenSmartspaceController.isDateWeatherDecoupled()) {
+ return
+ }
+
+ smartSpaceView = lockscreenSmartspaceController.buildAndConnectDateView(parentView)
+
+ val topPadding: Int = with(context.resources) {
+ getDimensionPixelSize(R.dimen.status_bar_header_height_keyguard) +
+ getDimensionPixelSize(R.dimen.keyguard_smartspace_top_offset) +
+ getDimensionPixelSize(R.dimen.keyguard_clock_top_margin)
+ }
+
+ val startPadding: Int = with(context.resources) {
+ getDimensionPixelSize(R.dimen.clock_padding_start) +
+ getDimensionPixelSize(R.dimen.below_clock_padding_start)
+ }
+
+ val endPadding: Int = context.resources
+ .getDimensionPixelSize(R.dimen.below_clock_padding_end)
+
+ smartSpaceView?.let {
+ it.setPaddingRelative(startPadding, topPadding, endPadding, 0)
+ it.isClickable = false
+
+ parentView.addView(
+ it,
+ FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.WRAP_CONTENT,
+ ),
+ )
+ }
+ }
+
private fun setUpBottomArea(parentView: ViewGroup) {
val bottomAreaView =
LayoutInflater.from(context)
@@ -202,22 +259,48 @@
disposables.add(DisposableHandle { broadcastDispatcher.unregisterReceiver(receiver) })
onClockChanged(parentView)
+
+ updateSmartspaceWithSetupClock()
}
private fun onClockChanged(parentView: ViewGroup) {
clockController.clock = clockRegistry.createCurrentClock()
- clockController.clock
- ?.largeClock
- ?.events
- ?.onTargetRegionChanged(KeyguardClockSwitch.getLargeClockRegion(parentView))
- clockView?.let { parentView.removeView(it) }
- clockView =
- clockController.clock?.largeClock?.view?.apply {
+
+ if (!shouldHideClock) {
+ val largeClock = clockController.clock?.largeClock
+
+ largeClock
+ ?.events
+ ?.onTargetRegionChanged(KeyguardClockSwitch.getLargeClockRegion(parentView))
+
+ clockView?.let { parentView.removeView(it) }
+ clockView = largeClock?.view?.apply {
if (shouldHighlightSelectedAffordance) {
alpha = DIM_ALPHA
}
parentView.addView(this)
+ visibility = View.VISIBLE
}
+ } else {
+ clockView?.visibility = View.GONE
+ }
+ }
+
+ /**
+ * Updates smart space after clock is set up. Used to show or hide smartspace with the right
+ * opacity based on the clock after setup.
+ */
+ private fun updateSmartspaceWithSetupClock() {
+ val hasCustomWeatherDataDisplay =
+ clockController
+ .clock
+ ?.largeClock
+ ?.config
+ ?.hasCustomWeatherDataDisplay == true
+
+ hideSmartspace(hasCustomWeatherDataDisplay)
+
+ smartSpaceView?.alpha = if (shouldHighlightSelectedAffordance) DIM_ALPHA else 1.0f
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
index 6d95882..3869b23 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
@@ -29,7 +29,7 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.shared.quickaffordance.shared.model.KeyguardQuickAffordancePreviewConstants
+import com.android.systemui.shared.quickaffordance.shared.model.KeyguardPreviewConstants
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@@ -114,13 +114,18 @@
}
when (message.what) {
- KeyguardQuickAffordancePreviewConstants.MESSAGE_ID_SLOT_SELECTED -> {
+ KeyguardPreviewConstants.MESSAGE_ID_SLOT_SELECTED -> {
message.data
.getString(
- KeyguardQuickAffordancePreviewConstants.KEY_SLOT_ID,
+ KeyguardPreviewConstants.KEY_SLOT_ID,
)
?.let { slotId -> renderer.onSlotSelected(slotId = slotId) }
}
+ KeyguardPreviewConstants.MESSAGE_ID_HIDE_SMART_SPACE -> {
+ message.data
+ .getBoolean(KeyguardPreviewConstants.KEY_HIDE_SMART_SPACE)
+ .let { hide -> renderer.hideSmartspace(hide) }
+ }
else -> requestDestruction(this)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
index 8d6545a4..2c9a9b3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
@@ -16,8 +16,8 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
-import com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt
index f16827d..c135786 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_DREAMING_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
index bc9dc4f..c6187dd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_DREAMING_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt
index a60665a..d3ea89c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_OCCLUDED_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
index ddce516..6845c55 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromOccludedTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
index df93d23..68810f9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt
index 37d956b..e38abc2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt
@@ -21,9 +21,9 @@
import android.text.format.DateUtils
import androidx.annotation.UiThread
import androidx.lifecycle.Observer
+import com.android.app.animation.Interpolators
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
import com.android.systemui.media.controls.ui.SquigglyProgress
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt
index 3669493..b46ebb2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt
@@ -34,10 +34,10 @@
import android.util.MathUtils
import android.view.View
import androidx.annotation.Keep
+import com.android.app.animation.Interpolators
import com.android.internal.graphics.ColorUtils
import com.android.internal.graphics.ColorUtils.blendARGB
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
import org.xmlpull.v1.XmlPullParser
private const val BACKGROUND_ANIM_DURATION = 370L
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt
index dd5c2bf..937a618 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt
@@ -35,9 +35,9 @@
import android.util.AttributeSet
import android.util.MathUtils.lerp
import androidx.annotation.Keep
+import com.android.app.animation.Interpolators
import com.android.internal.graphics.ColorUtils
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
import org.xmlpull.v1.XmlPullParser
private const val RIPPLE_ANIM_DURATION = 800L
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
index ab39442..0aa4349 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
@@ -166,6 +166,7 @@
}
}
+ /** Whether the media card currently has the "expanded" layout */
@VisibleForTesting
var currentlyExpanded = true
set(value) {
@@ -501,6 +502,7 @@
mediaHostStatesManager.addCallback(
object : MediaHostStatesManager.Callback {
override fun onHostStateChanged(location: Int, mediaHostState: MediaHostState) {
+ updateUserVisibility()
if (location == desiredLocation) {
onDesiredLocationChanged(desiredLocation, mediaHostState, animate = false)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index 40027a1..f9d3094 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -72,6 +72,7 @@
import androidx.annotation.UiThread;
import androidx.constraintlayout.widget.ConstraintSet;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.jank.InteractionJankMonitor;
@@ -82,7 +83,6 @@
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.GhostedViewLaunchAnimatorController;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.bluetooth.BroadcastDialogController;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.qualifiers.Background;
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
index 54237ce..fe8ebaf 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
@@ -33,9 +33,9 @@
import android.view.ViewGroup
import android.view.ViewGroupOverlay
import androidx.annotation.VisibleForTesting
+import com.android.app.animation.Interpolators
import com.android.keyguard.KeyguardViewController
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dreams.DreamOverlayStateController
@@ -257,7 +257,7 @@
if (value && (isLockScreenShadeVisibleToUser() || isHomeScreenShadeVisibleToUser())) {
mediaCarouselController.logSmartspaceImpression(value)
}
- mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser()
+ updateUserVisibility()
}
/**
@@ -460,8 +460,7 @@
) {
mediaCarouselController.logSmartspaceImpression(qsExpanded)
}
- mediaCarouselController.mediaCarouselScrollHandler.visibleToUser =
- isVisibleToUser()
+ updateUserVisibility()
}
override fun onDozeAmountChanged(linear: Float, eased: Float) {
@@ -480,8 +479,7 @@
qsExpanded = false
closeGuts()
}
- mediaCarouselController.mediaCarouselScrollHandler.visibleToUser =
- isVisibleToUser()
+ updateUserVisibility()
}
override fun onExpandedChanged(isExpanded: Boolean) {
@@ -489,8 +487,7 @@
if (isHomeScreenShadeVisibleToUser()) {
mediaCarouselController.logSmartspaceImpression(qsExpanded)
}
- mediaCarouselController.mediaCarouselScrollHandler.visibleToUser =
- isVisibleToUser()
+ updateUserVisibility()
}
}
)
@@ -532,9 +529,7 @@
}
)
- mediaCarouselController.updateUserVisibility = {
- mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser()
- }
+ mediaCarouselController.updateUserVisibility = this::updateUserVisibility
mediaCarouselController.updateHostVisibility = {
mediaHosts.forEach { it?.updateViewVisibility() }
}
@@ -1180,11 +1175,15 @@
return isCrossFadeAnimatorRunning
}
- /** Returns true when the media card could be visible to the user if existed. */
- private fun isVisibleToUser(): Boolean {
- return isLockScreenVisibleToUser() ||
- isLockScreenShadeVisibleToUser() ||
- isHomeScreenShadeVisibleToUser()
+ /** Update whether or not the media carousel could be visible to the user */
+ private fun updateUserVisibility() {
+ val shadeVisible =
+ isLockScreenVisibleToUser() ||
+ isLockScreenShadeVisibleToUser() ||
+ isHomeScreenShadeVisibleToUser()
+ val mediaVisible = qsExpanded || hasActiveMediaOrRecommendation
+ mediaCarouselController.mediaCarouselScrollHandler.visibleToUser =
+ shadeVisible && mediaVisible
}
private fun isLockScreenVisibleToUser(): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt
index e9b2cf2..583c626 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt
@@ -31,8 +31,8 @@
import android.util.MathUtils.lerpInv
import android.util.MathUtils.lerpInvSat
import androidx.annotation.VisibleForTesting
+import com.android.app.animation.Interpolators
import com.android.internal.graphics.ColorUtils
-import com.android.systemui.animation.Interpolators
import kotlin.math.abs
import kotlin.math.cos
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 78082c3..77ff036 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -36,7 +36,7 @@
import android.view.View.ACCESSIBILITY_LIVE_REGION_NONE
import com.android.internal.widget.CachingIconView
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.ui.binder.TintedIconViewBinder
import com.android.systemui.dagger.SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskLabelLoader.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskLabelLoader.kt
index eadcb93..1be8b70 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskLabelLoader.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskLabelLoader.kt
@@ -20,6 +20,7 @@
import android.content.ComponentName
import android.content.pm.PackageManager
import android.os.UserHandle
+import android.util.Log
import com.android.systemui.dagger.qualifiers.Background
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -36,18 +37,27 @@
private val packageManager: PackageManager
) : RecentTaskLabelLoader {
+ private val TAG = "RecentTaskLabelLoader"
+
override suspend fun loadLabel(
@UserIdInt userId: Int,
componentName: ComponentName
): CharSequence? =
withContext(coroutineDispatcher) {
- val userHandle = UserHandle(userId)
- val appInfo =
- packageManager.getApplicationInfo(
- componentName.packageName,
- PackageManager.ApplicationInfoFlags.of(0 /* no flags */)
- )
- val label = packageManager.getApplicationLabel(appInfo)
- return@withContext packageManager.getUserBadgedLabel(label, userHandle)
+ var badgedLabel: CharSequence? = null
+ try {
+ val appInfo =
+ packageManager.getApplicationInfoAsUser(
+ componentName.packageName,
+ PackageManager.ApplicationInfoFlags.of(0 /* no flags */),
+ userId
+ )
+ val label = packageManager.getApplicationLabel(appInfo)
+ val userHandle = UserHandle(userId)
+ badgedLabel = packageManager.getUserBadgedLabel(label, userHandle)
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.e(TAG, "Unable to get application info", e)
+ }
+ return@withContext badgedLabel
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTaskViewHolder.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTaskViewHolder.kt
index 64f97f2..2d75359 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTaskViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTaskViewHolder.kt
@@ -68,7 +68,7 @@
}
launch {
val label = labelLoader.loadLabel(task.userId, component)
- root.contentDescription = label
+ root.contentDescription = label ?: root.context.getString(R.string.unknown)
}
}
launch {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 94f01b8..146b5f5 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -58,11 +58,11 @@
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.Utils;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
import com.android.systemui.navigationbar.buttons.ContextualButton;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
index 0218016..10084bd 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
@@ -16,7 +16,7 @@
package com.android.systemui.navigationbar.buttons;
-import static com.android.systemui.animation.Interpolators.LINEAR;
+import static com.android.app.animation.Interpolators.LINEAR;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -24,9 +24,6 @@
import android.view.View;
import android.view.View.AccessibilityDelegate;
-import com.android.systemui.Dependency;
-import com.android.systemui.assist.AssistManager;
-
import java.util.ArrayList;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index b9ef916..41e3e6d 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -89,6 +89,7 @@
import com.android.systemui.tracing.nano.SystemUiTraceProto;
import com.android.systemui.util.Assert;
import com.android.wm.shell.back.BackAnimation;
+import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.pip.Pip;
import java.io.PrintWriter;
@@ -190,6 +191,7 @@
private final WindowManager mWindowManager;
private final IWindowManager mWindowManagerService;
private final Optional<Pip> mPipOptional;
+ private final Optional<DesktopMode> mDesktopModeOptional;
private final FalsingManager mFalsingManager;
private final Configuration mLastReportedConfig = new Configuration();
// Activities which should not trigger Back gesture.
@@ -204,6 +206,7 @@
private final Rect mPipExcludedBounds = new Rect();
private final Rect mNavBarOverlayExcludedBounds = new Rect();
private final Region mExcludeRegion = new Region();
+ private final Region mDesktopModeExcludeRegion = new Region();
private final Region mUnrestrictedExcludeRegion = new Region();
private final Provider<NavigationBarEdgePanel> mNavBarEdgePanelProvider;
private final Provider<BackGestureTfClassifierProvider>
@@ -328,6 +331,9 @@
private final Consumer<Boolean> mOnIsInPipStateChangedListener =
(isInPip) -> mIsInPip = isInPip;
+ private final Consumer<Region> mDesktopCornersChangedListener =
+ (desktopExcludeRegion) -> mDesktopModeExcludeRegion.set(desktopExcludeRegion);
+
private final UserTracker.Callback mUserChangedCallback =
new UserTracker.Callback() {
@Override
@@ -352,6 +358,7 @@
WindowManager windowManager,
IWindowManager windowManagerService,
Optional<Pip> pipOptional,
+ Optional<DesktopMode> desktopModeOptional,
FalsingManager falsingManager,
Provider<NavigationBarEdgePanel> navigationBarEdgePanelProvider,
Provider<BackGestureTfClassifierProvider> backGestureTfClassifierProviderProvider,
@@ -372,6 +379,7 @@
mWindowManager = windowManager;
mWindowManagerService = windowManagerService;
mPipOptional = pipOptional;
+ mDesktopModeOptional = desktopModeOptional;
mFalsingManager = falsingManager;
mNavBarEdgePanelProvider = navigationBarEdgePanelProvider;
mBackGestureTfClassifierProviderProvider = backGestureTfClassifierProviderProvider;
@@ -580,6 +588,9 @@
mMainExecutor::execute, mOnPropertiesChangedListener);
mPipOptional.ifPresent(
pip -> pip.setOnIsInPipStateChangedListener(mOnIsInPipStateChangedListener));
+ mDesktopModeOptional.ifPresent(
+ dm -> dm.addDesktopGestureExclusionRegionListener(
+ mDesktopCornersChangedListener, mMainExecutor));
try {
mWindowManagerService.registerSystemGestureExclusionListener(
@@ -802,11 +813,17 @@
mDisplaySize.y - insets.bottom);
}
+ private boolean desktopExcludeRegionContains(int x, int y) {
+ return mDesktopModeExcludeRegion.contains(x, y);
+ }
+
private boolean isWithinTouchRegion(int x, int y) {
// If the point is inside the PiP or Nav bar overlay excluded bounds, then ignore the back
// gesture
final boolean isInsidePip = mIsInPip && mPipExcludedBounds.contains(x, y);
- if (isInsidePip || mNavBarOverlayExcludedBounds.contains(x, y)) {
+ final boolean isInDesktopExcludeRegion = desktopExcludeRegionContains(x, y);
+ if (isInsidePip || isInDesktopExcludeRegion
+ || mNavBarOverlayExcludedBounds.contains(x, y)) {
return false;
}
@@ -1136,6 +1153,7 @@
pw.println(" mUnrestrictedExcludeRegion=" + mUnrestrictedExcludeRegion);
pw.println(" mIsInPip=" + mIsInPip);
pw.println(" mPipExcludedBounds=" + mPipExcludedBounds);
+ pw.println(" mDesktopModeExclusionRegion=" + mDesktopModeExcludeRegion);
pw.println(" mNavBarOverlayExcludedBounds=" + mNavBarOverlayExcludedBounds);
pw.println(" mEdgeWidthLeft=" + mEdgeWidthLeft);
pw.println(" mEdgeWidthRight=" + mEdgeWidthRight);
@@ -1206,6 +1224,7 @@
private final WindowManager mWindowManager;
private final IWindowManager mWindowManagerService;
private final Optional<Pip> mPipOptional;
+ private final Optional<DesktopMode> mDesktopModeOptional;
private final FalsingManager mFalsingManager;
private final Provider<NavigationBarEdgePanel> mNavBarEdgePanelProvider;
private final Provider<BackGestureTfClassifierProvider>
@@ -1227,6 +1246,7 @@
WindowManager windowManager,
IWindowManager windowManagerService,
Optional<Pip> pipOptional,
+ Optional<DesktopMode> desktopModeOptional,
FalsingManager falsingManager,
Provider<NavigationBarEdgePanel> navBarEdgePanelProvider,
Provider<BackGestureTfClassifierProvider>
@@ -1246,6 +1266,7 @@
mWindowManager = windowManager;
mWindowManagerService = windowManagerService;
mPipOptional = pipOptional;
+ mDesktopModeOptional = desktopModeOptional;
mFalsingManager = falsingManager;
mNavBarEdgePanelProvider = navBarEdgePanelProvider;
mBackGestureTfClassifierProviderProvider = backGestureTfClassifierProviderProvider;
@@ -1270,6 +1291,7 @@
mWindowManager,
mWindowManagerService,
mPipOptional,
+ mDesktopModeOptional,
mFalsingManager,
mNavBarEdgePanelProvider,
mBackGestureTfClassifierProviderProvider,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
index 590efbb..ff22398 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -48,10 +48,10 @@
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
+import com.android.app.animation.Interpolators;
import com.android.internal.util.LatencyTracker;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.plugins.NavigationEdgeBackPlugin;
import com.android.systemui.settings.DisplayTracker;
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/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
index 0641eec..a3b901b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
@@ -44,6 +44,7 @@
import android.widget.TextView
import androidx.annotation.GuardedBy
import androidx.annotation.VisibleForTesting
+import androidx.annotation.WorkerThread
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@@ -201,7 +202,7 @@
@GuardedBy("lock")
private val appListAdapter: AppListAdapter = AppListAdapter()
- @GuardedBy("lock")
+ /* Only mutate on the background thread */
private var runningApps: ArrayMap<UserPackage, RunningApp> = ArrayMap()
private val userTrackerCallback = object : UserTracker.Callback {
@@ -374,11 +375,6 @@
override fun showDialog(expandable: Expandable?) {
synchronized(lock) {
if (dialog == null) {
-
- runningTaskIdentifiers.keys.forEach {
- it.updateUiControl()
- }
-
val dialog = SystemUIDialog(context)
dialog.setTitle(R.string.fgs_manager_dialog_title)
dialog.setMessage(R.string.fgs_manager_dialog_message)
@@ -421,33 +417,53 @@
}
}
- backgroundExecutor.execute {
- synchronized(lock) {
- updateAppItemsLocked()
- }
- }
+ updateAppItemsLocked(refreshUiControls = true)
}
}
}
@GuardedBy("lock")
- private fun updateAppItemsLocked() {
+ private fun updateAppItemsLocked(refreshUiControls: Boolean = false) {
if (dialog == null) {
- runningApps.clear()
+ backgroundExecutor.execute {
+ clearRunningApps()
+ }
return
}
- val addedPackages = runningTaskIdentifiers.keys.filter {
- currentProfileIds.contains(it.userId) &&
+ val packagesToStartTime = runningTaskIdentifiers.mapValues { it.value.startTime }
+ val profileIds = currentProfileIds.toSet()
+ backgroundExecutor.execute {
+ updateAppItems(packagesToStartTime, profileIds, refreshUiControls)
+ }
+ }
+
+ /**
+ * Must be called on the background thread.
+ */
+ @WorkerThread
+ private fun updateAppItems(
+ packages: Map<UserPackage, Long>,
+ profileIds: Set<Int>,
+ refreshUiControls: Boolean = true
+ ) {
+ if (refreshUiControls) {
+ packages.forEach { (pkg, _) ->
+ pkg.updateUiControl()
+ }
+ }
+
+ val addedPackages = packages.keys.filter {
+ profileIds.contains(it.userId) &&
it.uiControl != UIControl.HIDE_ENTRY && runningApps[it]?.stopped != true
}
- val removedPackages = runningApps.keys.filter { !runningTaskIdentifiers.containsKey(it) }
+ val removedPackages = runningApps.keys.filter { it !in packages }
addedPackages.forEach {
val ai = packageManager.getApplicationInfoAsUser(it.packageName, 0, it.userId)
runningApps[it] = RunningApp(
it.userId, it.packageName,
- runningTaskIdentifiers[it]!!.startTime, it.uiControl,
+ packages[it]!!, it.uiControl,
packageManager.getApplicationLabel(ai),
packageManager.getUserBadgedIcon(
packageManager.getApplicationIcon(ai), UserHandle.of(it.userId)
@@ -472,6 +488,14 @@
}
}
+ /**
+ * Must be called on the background thread.
+ */
+ @WorkerThread
+ private fun clearRunningApps() {
+ runningApps.clear()
+ }
+
private fun stopPackage(userId: Int, packageName: String, timeStarted: Long) {
logEvent(stopped = true, packageName, userId, timeStarted)
val userPackageKey = UserPackage(userId, packageName)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index a7aac5a..463c79c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -26,7 +26,7 @@
import androidx.annotation.Nullable;
-import com.android.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.qs.QSTile;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 584d27f8..09cc2c5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -18,9 +18,10 @@
import static com.android.systemui.media.dagger.MediaModule.QS_PANEL;
import static com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL;
-import static com.android.systemui.statusbar.disableflags.DisableFlagsLogger.DisableState;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
+import static com.android.systemui.statusbar.disableflags.DisableFlagsLogger.DisableState;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.res.Configuration;
@@ -43,10 +44,10 @@
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
+import com.android.app.animation.Interpolators;
import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.compose.ComposeFacade;
import com.android.systemui.dump.DumpManager;
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/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index d28ccff..be92bd4 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -22,10 +22,10 @@
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
+import static com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE;
+import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
-import static com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE;
-import static com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
import static com.android.systemui.classifier.Classifier.GENERIC;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
@@ -59,8 +59,6 @@
import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.Region;
-import android.hardware.biometrics.SensorLocationInternal;
-import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
@@ -90,6 +88,7 @@
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
@@ -113,7 +112,6 @@
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.animation.LaunchAnimator;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.classifier.Classifier;
@@ -224,8 +222,6 @@
import com.android.systemui.util.time.SystemClock;
import com.android.wm.shell.animation.FlingAnimationUtils;
-import kotlin.Unit;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -236,6 +232,8 @@
import javax.inject.Inject;
import javax.inject.Provider;
+import kotlin.Unit;
+
import kotlinx.coroutines.CoroutineDispatcher;
@CentralSurfacesComponent.CentralSurfacesScope
@@ -410,7 +408,8 @@
private int mDisplayRightInset = 0; // in pixels
private int mDisplayLeftInset = 0; // in pixels
- private final KeyguardClockPositionAlgorithm
+ @VisibleForTesting
+ KeyguardClockPositionAlgorithm
mClockPositionAlgorithm =
new KeyguardClockPositionAlgorithm();
private final KeyguardClockPositionAlgorithm.Result
@@ -1493,11 +1492,9 @@
? 1.0f : mInterpolatedDarkAmount;
float udfpsAodTopLocation = -1f;
- if (mUpdateMonitor.isUdfpsEnrolled() && mAuthController.getUdfpsProps().size() > 0) {
- FingerprintSensorPropertiesInternal props = mAuthController.getUdfpsProps().get(0);
- final SensorLocationInternal location = props.getLocation();
- udfpsAodTopLocation = location.sensorLocationY - location.sensorRadius
- - mUdfpsMaxYBurnInOffset;
+ if (mUpdateMonitor.isUdfpsEnrolled() && mAuthController.getUdfpsLocation() != null) {
+ udfpsAodTopLocation = mAuthController.getUdfpsLocation().y
+ - mAuthController.getUdfpsRadius() - mUdfpsMaxYBurnInOffset;
}
mClockPositionAlgorithm.setup(
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index ef14d1c..7a79e85 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -50,6 +50,7 @@
import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
@@ -59,7 +60,6 @@
import com.android.keyguard.FaceAuthApiRequestReason;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
index f0815e9..4131e7d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
@@ -34,10 +34,10 @@
import android.widget.TextView
import androidx.annotation.VisibleForTesting
import androidx.constraintlayout.motion.widget.MotionLayout
+import com.android.app.animation.Interpolators
import com.android.settingslib.Utils
import com.android.systemui.Dumpable
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.battery.BatteryMeterView
import com.android.systemui.battery.BatteryMeterViewController
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
index b0b9ab2..4c6673c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
@@ -17,15 +17,28 @@
package com.android.systemui.shade
import android.view.LayoutInflater
+import com.android.systemui.CoreStartable
import com.android.systemui.R
+import com.android.systemui.biometrics.AuthRippleController
+import com.android.systemui.biometrics.AuthRippleView
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
+import dagger.Binds
import dagger.Module
import dagger.Provides
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
/** Module for classes related to the notification shade. */
@Module
abstract class ShadeModule {
+
+ @Binds
+ @IntoMap
+ @ClassKey(AuthRippleController::class)
+ abstract fun bindAuthRippleController(controller: AuthRippleController): CoreStartable
+
companion object {
@Provides
@SysUISingleton
@@ -59,5 +72,22 @@
): NotificationPanelView {
return notificationShadeWindowView.findViewById(R.id.notification_panel)
}
+
+ @Provides
+ @SysUISingleton
+ fun providesLightRevealScrim(
+ notificationShadeWindowView: NotificationShadeWindowView,
+ ): LightRevealScrim {
+ return notificationShadeWindowView.findViewById(R.id.light_reveal_scrim)
+ }
+
+ // TODO(b/277762009): Only allow this view's controller to inject the view. See above.
+ @Provides
+ @SysUISingleton
+ fun providesAuthRippleView(
+ notificationShadeWindowView: NotificationShadeWindowView,
+ ): AuthRippleView? {
+ return notificationShadeWindowView.findViewById(R.id.auth_ripple)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index 63179da..c1ebf12 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -18,8 +18,8 @@
import android.view.View;
+import com.android.app.animation.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 54b341f..1a32d70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -38,8 +38,8 @@
import android.view.animation.Interpolator;
import android.widget.ImageView;
+import com.android.app.animation.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.wm.shell.animation.FlingAnimationUtils;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 9421524..823bb35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -16,7 +16,7 @@
import android.util.MathUtils.lerp
import android.view.View
import android.view.animation.PathInterpolator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.statusbar.LightRevealEffect.Companion.getPercentPastThreshold
import com.android.systemui.util.getColorWithAlpha
import com.android.systemui.util.leak.RotationUtils
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index faf592e..2258968 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -18,7 +18,7 @@
import com.android.systemui.ExpandHelper
import com.android.systemui.Gefingerpoken
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.biometrics.UdfpsKeyguardViewController
import com.android.systemui.classifier.Classifier
import com.android.systemui.classifier.FalsingCollector
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 72ae16e..fb88a96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -44,9 +44,9 @@
import android.view.View;
import android.widget.ImageView;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dumpable;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 8dc7842..d37cbcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -33,7 +33,7 @@
import androidx.dynamicanimation.animation.SpringAnimation
import androidx.dynamicanimation.animation.SpringForce
import com.android.systemui.Dumpable
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 7eb63da..5c3bacc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -35,10 +35,10 @@
import androidx.annotation.NonNull;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index 976924a..f9d4f1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -31,7 +31,7 @@
import com.android.systemui.Dumpable
import com.android.systemui.Gefingerpoken
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt b/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt
index 575f354..f1e51e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt
@@ -4,7 +4,7 @@
import android.content.res.Configuration
import android.util.MathUtils
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.policy.ConfigurationController
import dagger.assisted.Assisted
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt b/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt
index 572c0e0..3d574ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt
@@ -8,7 +8,7 @@
import android.view.animation.PathInterpolator
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.qs.QS
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 7755003..91c08a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -52,10 +52,10 @@
import androidx.core.graphics.ColorUtils;
+import com.android.app.animation.Interpolators;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.NotificationIconDozeHelper;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.util.drawable.DrawableSize;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 79d01b4a..d6a14604 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -42,6 +42,7 @@
import androidx.annotation.NonNull;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
@@ -49,7 +50,6 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dumpable;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
index 2fa27ee..67ab060 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
@@ -25,8 +25,8 @@
import android.view.ViewGroup;
import android.view.animation.Interpolator;
+import com.android.app.animation.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.TransformState;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
index bfc4e9c..eddb683 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
@@ -26,7 +26,7 @@
import android.widget.FrameLayout
import com.android.internal.annotations.GuardedBy
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.statusbar.StatusBarStateController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
index 0446165..b09b9f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
@@ -21,8 +21,8 @@
import android.view.View;
import android.widget.ImageView;
+import com.android.app.animation.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.notification.row.HybridNotificationView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt
index c22dbf6..785e65d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt
@@ -3,7 +3,7 @@
import android.util.MathUtils
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.animation.ActivityLaunchAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.animation.LaunchAnimator
import kotlin.math.min
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
index c22cd1b..5a14200 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
@@ -23,13 +23,13 @@
import android.view.ViewGroup;
import android.widget.TextView;
+import com.android.app.animation.Interpolators;
import com.android.internal.widget.IMessagingLayout;
import com.android.internal.widget.MessagingGroup;
import com.android.internal.widget.MessagingImageMessage;
import com.android.internal.widget.MessagingLinearLayout;
import com.android.internal.widget.MessagingMessage;
import com.android.internal.widget.MessagingPropertyAnimator;
-import com.android.systemui.animation.Interpolators;
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
index 3fc7b13..a045698 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
@@ -24,8 +24,8 @@
import android.view.View;
import android.widget.ImageView;
+import com.android.app.animation.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import java.util.function.Consumer;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index fe0b28d..9ba2199 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -21,8 +21,8 @@
import androidx.annotation.VisibleForTesting
import androidx.core.animation.ObjectAnimator
import com.android.systemui.Dumpable
-import com.android.systemui.animation.Interpolators
-import com.android.systemui.animation.InterpolatorsAndroidX
+import com.android.app.animation.Interpolators
+import com.android.app.animation.InterpolatorsAndroidX
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
index 5d07cac..57d20246 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
@@ -24,7 +24,7 @@
import android.view.View;
import android.view.animation.Interpolator;
-import com.android.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
import com.android.systemui.statusbar.notification.stack.AnimationFilter;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.ViewState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index 9f9fba4..90eb630 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -23,11 +23,11 @@
import android.widget.ProgressBar;
import android.widget.TextView;
+import com.android.app.animation.Interpolators;
import com.android.internal.widget.MessagingImageMessage;
import com.android.internal.widget.MessagingPropertyAnimator;
import com.android.internal.widget.ViewClippingUtil;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.ViewTransformationHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt
index dc16274..16f1a45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt
@@ -22,7 +22,7 @@
import android.view.View
import android.view.ViewGroup
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
/**
* Class to help with fading of view groups without fading one subview
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 766ad88..f70d5e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -31,12 +31,12 @@
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import com.android.app.animation.Interpolators;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.settingslib.Utils;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationUtils;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index e468a59..2695410 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -64,6 +64,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -72,7 +73,6 @@
import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.CallLayout;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
index b56bae1..7a2bee9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
@@ -45,10 +45,10 @@
import androidx.annotation.VisibleForTesting;
+import com.android.app.animation.Interpolators;
import com.android.internal.logging.InstanceId;
import com.android.internal.logging.InstanceIdSequence;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 5edff5f..9dbbc58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -32,9 +32,9 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.Roundable;
import com.android.systemui.statusbar.notification.RoundableState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index f21db0b..9bc0333 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -25,7 +25,7 @@
import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE;
import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT;
-import static com.android.systemui.animation.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.app.animation.Interpolators.FAST_OUT_SLOW_IN;
import static java.lang.annotation.RetentionPolicy.SOURCE;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
index 596bdc0..047db20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
@@ -33,9 +33,9 @@
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 8a50f2f..99a7755 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -20,7 +20,7 @@
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
-import static com.android.systemui.animation.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.app.animation.Interpolators.FAST_OUT_SLOW_IN;
import static java.lang.annotation.RetentionPolicy.SOURCE;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index bafc474..5a129fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -39,9 +39,9 @@
import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.AlphaOptimizedImageView;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
index 5f4c926..d5d7f75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
@@ -45,11 +45,11 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
index 5aaf63f..b24cec1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
@@ -23,8 +23,8 @@
import android.view.View;
import android.view.animation.Interpolator;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.animation.Interpolators;
import java.util.function.Consumer;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index 9a777ea..84fe9ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -34,10 +34,10 @@
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.NotificationExpandButton;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.ViewTransformationHelper;
import com.android.systemui.statusbar.notification.CustomInterpolatorTransformation;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
index 7f3381c..d73bbeb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
@@ -22,8 +22,8 @@
import android.animation.ValueAnimator;
import android.view.View;
+import com.android.app.animation.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
index 0b435fe..9a33a94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
@@ -26,7 +26,7 @@
import android.view.View;
import android.view.animation.Interpolator;
-import com.android.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
import com.android.systemui.statusbar.notification.ShadeViewRefactor;
import com.android.systemui.statusbar.notification.row.ExpandableView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 5c322d7..24e8f39 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -75,6 +75,7 @@
import android.widget.OverScroller;
import android.widget.ScrollView;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.jank.InteractionJankMonitor;
@@ -86,7 +87,6 @@
import com.android.systemui.Dumpable;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index ee72943..f07dd00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -22,9 +22,9 @@
import android.util.Property;
import android.view.View;
+import com.android.app.animation.Interpolators;
import com.android.keyguard.KeyguardSliceView;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.shared.clocks.AnimatableClockView;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarIconView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
index d07da38..f4605be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
@@ -26,9 +26,9 @@
import android.view.View;
import android.view.animation.Interpolator;
+import com.android.app.animation.Interpolators;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.NotificationFadeAware.FadeOptimizedNotification;
import com.android.systemui.statusbar.notification.PropertyAnimator;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 9dce332..4590712 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -33,9 +33,9 @@
import android.util.Log;
import android.view.View;
+import com.android.app.animation.Interpolators;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index e66a8b1..2387495 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -452,7 +452,7 @@
protected PhoneStatusBarView mStatusBarView;
private PhoneStatusBarViewController mPhoneStatusBarViewController;
private PhoneStatusBarTransitions mStatusBarTransitions;
- private AuthRippleController mAuthRippleController;
+ private final AuthRippleController mAuthRippleController;
@WindowVisibleState private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
protected final NotificationShadeWindowController mNotificationShadeWindowController;
private final StatusBarInitializer mStatusBarInitializer;
@@ -460,7 +460,7 @@
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@VisibleForTesting
DozeServiceHost mDozeServiceHost;
- private LightRevealScrim mLightRevealScrim;
+ private final LightRevealScrim mLightRevealScrim;
private PowerButtonReveal mPowerButtonReveal;
private boolean mWakeUpComingFromTouch;
@@ -768,6 +768,7 @@
ScrimController scrimController,
Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
+ AuthRippleController authRippleController,
DozeServiceHost dozeServiceHost,
PowerManager powerManager,
ScreenPinningRequest screenPinningRequest,
@@ -810,6 +811,7 @@
IDreamManager dreamManager,
Lazy<CameraLauncher> cameraLauncherLazy,
Lazy<LightRevealScrimViewModel> lightRevealScrimViewModelLazy,
+ LightRevealScrim lightRevealScrim,
AlternateBouncerInteractor alternateBouncerInteractor,
UserTracker userTracker,
Provider<FingerprintManager> fingerprintManager
@@ -866,6 +868,7 @@
mScreenPinningRequest = screenPinningRequest;
mDozeScrimController = dozeScrimController;
mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
+ mAuthRippleController = authRippleController;
mNotificationShadeDepthControllerLazy = notificationShadeDepthControllerLazy;
mVolumeComponent = volumeComponent;
mCommandQueue = commandQueue;
@@ -932,6 +935,7 @@
wiredChargingRippleController.registerCallbacks();
mLightRevealScrimViewModelLazy = lightRevealScrimViewModelLazy;
+ mLightRevealScrim = lightRevealScrim;
// Based on teamfood flag, turn predictive back dispatch on at runtime.
if (mFeatureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_SYSUI)) {
@@ -1326,8 +1330,6 @@
});
mScrimController.attachViews(scrimBehind, notificationsScrim, scrimInFront);
- mLightRevealScrim = mNotificationShadeWindowView.findViewById(R.id.light_reveal_scrim);
-
if (mFeatureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)) {
LightRevealScrimViewBinder.bind(
mLightRevealScrim, mLightRevealScrimViewModelLazy.get());
@@ -1635,10 +1637,7 @@
private void inflateStatusBarWindow() {
if (mCentralSurfacesComponent != null) {
- // Tear down
- for (CentralSurfacesComponent.Startable s : mCentralSurfacesComponent.getStartables()) {
- s.stop();
- }
+ Log.e(TAG, "CentralSurfacesComponent being recreated; this is unexpected.");
}
mCentralSurfacesComponent = mCentralSurfacesComponentFactory.create();
mFragmentService.addFragmentInstantiationProvider(
@@ -1667,8 +1666,6 @@
mPresenter = mCentralSurfacesComponent.getNotificationPresenter();
mNotificationActivityStarter = mCentralSurfacesComponent.getNotificationActivityStarter();
mNotificationShelfController = mCentralSurfacesComponent.getNotificationShelfController();
- mAuthRippleController = mCentralSurfacesComponent.getAuthRippleController();
- mAuthRippleController.init();
mHeadsUpManager.addListener(mCentralSurfacesComponent.getStatusBarHeadsUpChangeListener());
@@ -1682,11 +1679,6 @@
mCentralSurfacesComponent.getCentralSurfacesCommandQueueCallbacks();
// Connect in to the status bar manager service
mCommandQueue.addCallback(mCommandQueueCallbacks);
-
- // Perform all other initialization for CentralSurfacesScope
- for (CentralSurfacesComponent.Startable s : mCentralSurfacesComponent.getStartables()) {
- s.start();
- }
}
protected void startKeyguard() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 90a6d0f..c1859b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -23,10 +23,10 @@
import android.content.res.Resources;
import android.util.MathUtils;
+import com.android.app.animation.Interpolators;
import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcherListView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
index 9d30cb4..61c1cc8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -30,9 +30,9 @@
import androidx.annotation.StyleRes;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.keyguard.KeyguardIndication;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 13566ef..720eeba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -43,9 +43,9 @@
import androidx.annotation.VisibleForTesting;
+import com.android.app.animation.Interpolators;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index e835c5ce..5232fb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -37,12 +37,12 @@
import androidx.core.animation.AnimatorListenerAdapter;
import androidx.core.animation.ValueAnimator;
+import com.android.app.animation.InterpolatorsAndroidX;
import com.android.keyguard.CarrierTextController;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.R;
-import com.android.systemui.animation.InterpolatorsAndroidX;
import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.log.LogLevel;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index 6bf5443..7bc4fc3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -24,21 +24,21 @@
import android.util.MathUtils;
import android.util.TimeUtils;
+import com.android.app.animation.Interpolators;
import com.android.systemui.Dumpable;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.policy.KeyguardStateController;
-import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
-
import dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
import dagger.assisted.AssistedInject;
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+
/**
* Class to control all aspects about light bar changes.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index cc4f901..46a2457 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -31,9 +31,9 @@
import android.util.SparseArray;
import android.view.ViewTreeObserver.OnPreDrawListener;
+import com.android.app.animation.Interpolators;
import com.android.internal.graphics.ColorUtils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 55dc188..560ea8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -15,11 +15,11 @@
import androidx.annotation.VisibleForTesting;
import androidx.collection.ArrayMap;
+import com.android.app.animation.Interpolators;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.ContrastColorUtil;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 006a029d..bef422c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -36,10 +36,10 @@
import androidx.annotation.VisibleForTesting;
import androidx.collection.ArrayMap;
+import com.android.app.animation.Interpolators;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.settingslib.Utils;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.stack.AnimationFilter;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
index 5e5317d7..07a6d0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
@@ -29,7 +29,7 @@
import android.view.animation.AnimationUtils;
import android.widget.Button;
-import com.android.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
import com.android.systemui.statusbar.AlphaOptimizedImageView;
public class SettingsButton extends AlphaOptimizedImageView {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index 8fa803e..cdf6652 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -15,7 +15,7 @@
import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF
import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD
import com.android.systemui.DejankUtils
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.WakefulnessLifecycle
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
index d80e1d3..ddb6d93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
@@ -45,7 +45,6 @@
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
-import java.util.Set;
import javax.inject.Named;
import javax.inject.Scope;
@@ -60,7 +59,6 @@
* outside the component. Should more items be moved *into* this component to avoid so many getters?
*/
@Subcomponent(modules = {
- CentralSurfacesStartableModule.class,
NotificationStackScrollLayoutListContainerModule.class,
StatusBarViewModule.class,
StatusBarNotificationActivityStarterModule.class,
@@ -85,14 +83,6 @@
@interface CentralSurfacesScope {}
/**
- * Performs initialization logic after {@link CentralSurfacesComponent} has been constructed.
- */
- interface Startable {
- void start();
- void stop();
- }
-
- /**
* Creates a {@link NotificationShadeWindowView}.
*/
NotificationShadeWindowView getNotificationShadeWindowView();
@@ -122,11 +112,6 @@
LockIconViewController getLockIconViewController();
/**
- * Creates an AuthRippleViewController. Must be init after creation.
- */
- AuthRippleController getAuthRippleController();
-
- /**
* Creates a StatusBarHeadsUpChangeListener.
*/
StatusBarHeadsUpChangeListener getStatusBarHeadsUpChangeListener();
@@ -148,11 +133,6 @@
@Named(STATUS_BAR_FRAGMENT)
CollapsedStatusBarFragment createCollapsedStatusBarFragment();
- /**
- * Set of startables to be run after a CentralSurfacesComponent has been constructed.
- */
- Set<Startable> getStartables();
-
NotificationActivityStarter getNotificationActivityStarter();
NotificationPresenter getNotificationPresenter();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesStartableModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesStartableModule.java
deleted file mode 100644
index 7ded90f..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesStartableModule.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2022 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.statusbar.phone.dagger;
-
-import dagger.Module;
-import dagger.multibindings.Multibinds;
-
-import java.util.Set;
-
-@Module
-interface CentralSurfacesStartableModule {
- @Multibinds
- Set<CentralSurfacesComponent.Startable> multibindStartables();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index ef86162..1a943e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -29,7 +29,6 @@
import com.android.systemui.R;
import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.battery.BatteryMeterViewController;
-import com.android.systemui.biometrics.AuthRippleView;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
@@ -150,15 +149,6 @@
/** */
@Provides
- @CentralSurfacesComponent.CentralSurfacesScope
- @Nullable
- public static AuthRippleView getAuthRippleView(
- NotificationShadeWindowView notificationShadeWindowView) {
- return notificationShadeWindowView.findViewById(R.id.auth_ripple);
- }
-
- /** */
- @Provides
@Named(SHADE_HEADER)
@CentralSurfacesComponent.CentralSurfacesScope
public static MotionLayout getLargeScreenShadeHeaderBarView(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 453dd1b..831d402 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -44,10 +44,10 @@
import androidx.annotation.VisibleForTesting;
import androidx.core.animation.Animator;
+import com.android.app.animation.Interpolators;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java
index 4dd63be..e1ec94f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java
@@ -24,9 +24,9 @@
import androidx.core.graphics.ColorUtils;
+import com.android.app.animation.Interpolators;
import com.android.keyguard.KeyguardConstants;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.qs.tiles.UserDetailItemView;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
index 928e011..66b5256 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -31,6 +31,7 @@
import android.view.View;
import android.view.ViewGroup;
+import com.android.app.animation.Interpolators;
import com.android.keyguard.KeyguardConstants;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -38,7 +39,6 @@
import com.android.keyguard.dagger.KeyguardUserSwitcherScope;
import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
index 850a4b4..363b06a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
@@ -21,11 +21,11 @@
import android.util.Log;
import android.view.View;
+import com.android.app.animation.Interpolators;
import com.android.keyguard.AlphaOptimizedLinearLayout;
import com.android.keyguard.KeyguardConstants;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils;
-import com.android.systemui.animation.Interpolators;
/**
* The container for the user switcher on Keyguard.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 403a7e8..e311bad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -73,6 +73,7 @@
import androidx.core.animation.ObjectAnimator;
import androidx.core.animation.ValueAnimator;
+import com.android.app.animation.InterpolatorsAndroidX;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.logging.UiEvent;
@@ -80,7 +81,6 @@
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.animation.InterpolatorsAndroidX;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt
index 1612388..46954b5 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt
@@ -18,7 +18,7 @@
import android.view.View
import android.view.ViewGroup
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
import com.android.systemui.animation.ViewHierarchyAnimator
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.util.children
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
index e819f94..4fbbc89 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
@@ -34,10 +34,10 @@
import androidx.annotation.DimenRes
import androidx.annotation.IdRes
import androidx.annotation.VisibleForTesting
+import com.android.app.animation.Interpolators
import com.android.internal.widget.CachingIconView
import com.android.systemui.Gefingerpoken
import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription
import com.android.systemui.common.shared.model.Text.Companion.loadText
diff --git a/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt b/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt
index 64234c2..41c6b5d 100644
--- a/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt
@@ -16,20 +16,22 @@
package com.android.systemui.util
-import android.os.Trace
+import android.os.Handler
import android.os.TraceNameSupplier
+import androidx.tracing.Trace
/**
- * Run a block within a [Trace] section.
- * Calls [Trace.beginSection] before and [Trace.endSection] after the passed block.
+ * Run a block within a [Trace] section. Calls [Trace.beginSection] before and [Trace.endSection]
+ * after the passed block. If tracing is disabled, it will run the block directly to avoid using an
+ * unnecessary try-finally block.
*/
inline fun <T> traceSection(tag: String, block: () -> T): T =
- if (Trace.isTagEnabled(Trace.TRACE_TAG_APP)) {
- Trace.traceBegin(Trace.TRACE_TAG_APP, tag)
+ if (Trace.isEnabled()) {
+ Trace.beginSection(tag)
try {
block()
} finally {
- Trace.traceEnd(Trace.TRACE_TAG_APP)
+ Trace.endSection()
}
} else {
block()
@@ -42,8 +44,10 @@
}
/**
- * Helper function for creating a Runnable object that implements TraceNameSupplier.
- * This is useful for posting Runnables to Handlers with meaningful names.
+ * Helper function for creating a [Runnable] that implements [TraceNameSupplier]. This is
+ * useful when posting to a [Handler] so that the [Runnable] has a meaningful name in the
+ * trace. Otherwise, the class name of the [Runnable] is used, which is often something like
+ * `pkg.MyClass$$ExternalSyntheticLambda0`.
*/
inline fun namedRunnable(tag: String, crossinline block: () -> Unit): Runnable {
return object : Runnable, TraceNameSupplier {
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
index 5d80292..db4ab7e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
@@ -19,7 +19,7 @@
import android.animation.ValueAnimator
import android.graphics.PointF
import android.util.MathUtils
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
/**
* The fraction after which we start fading in when going from a gone widget to a visible one
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 77210b7..91078dc 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -109,6 +109,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -119,7 +120,6 @@
import com.android.systemui.Dumpable;
import com.android.systemui.Prefs;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.ActivityStarter;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index e492534..b3e7cb0 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -345,7 +345,8 @@
}
void initDesktopMode(DesktopMode desktopMode) {
- desktopMode.addListener(new DesktopModeTaskRepository.VisibleTasksListener() {
+ desktopMode.addVisibleTasksListener(
+ new DesktopModeTaskRepository.VisibleTasksListener() {
@Override
public void onVisibilityChanged(boolean hasFreeformTasks) {
mSysUiState.setFlag(SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE, hasFreeformTasks)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/InterpolatorsAndroidXTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/InterpolatorsAndroidXTest.kt
deleted file mode 100644
index 2c680be..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/InterpolatorsAndroidXTest.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2022 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.animation
-
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import java.lang.reflect.Modifier
-import junit.framework.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@SmallTest
-@RunWith(JUnit4::class)
-class InterpolatorsAndroidXTest : SysuiTestCase() {
-
- @Test
- fun testInterpolatorsAndInterpolatorsAndroidXPublicMethodsAreEqual() {
- assertEquals(
- Interpolators::class.java.getPublicMethods(),
- InterpolatorsAndroidX::class.java.getPublicMethods()
- )
- }
-
- @Test
- fun testInterpolatorsAndInterpolatorsAndroidXPublicFieldsAreEqual() {
- assertEquals(
- Interpolators::class.java.getPublicFields(),
- InterpolatorsAndroidX::class.java.getPublicFields()
- )
- }
-
- private fun <T> Class<T>.getPublicMethods() =
- declaredMethods
- .filter { Modifier.isPublic(it.modifiers) }
- .map { it.toString().replace(name, "") }
- .toSet()
-
- private fun <T> Class<T>.getPublicFields() =
- fields.filter { Modifier.isPublic(it.modifiers) }.map { it.name }.toSet()
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt
index 02d4ecd..063757a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt
@@ -31,6 +31,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.io.File
@@ -64,6 +65,7 @@
@RunWith(AndroidTestingRunner::class)
@SmallTest
class TextInterpolatorTest : SysuiTestCase() {
+ lateinit var typefaceCache: TypefaceVariantCache
private fun makeLayout(
text: String,
@@ -75,11 +77,16 @@
.setTextDirection(dir).build()
}
+ @Before
+ fun setup() {
+ typefaceCache = TypefaceVariantCacheImpl()
+ }
+
@Test
fun testStartState() {
val layout = makeLayout(TEXT, PAINT)
- val interp = TextInterpolator(layout)
+ val interp = TextInterpolator(layout, typefaceCache)
interp.basePaint.set(START_PAINT)
interp.onBasePaintModified()
@@ -98,7 +105,7 @@
fun testEndState() {
val layout = makeLayout(TEXT, PAINT)
- val interp = TextInterpolator(layout)
+ val interp = TextInterpolator(layout, typefaceCache)
interp.basePaint.set(START_PAINT)
interp.onBasePaintModified()
@@ -116,7 +123,7 @@
fun testMiddleState() {
val layout = makeLayout(TEXT, PAINT)
- val interp = TextInterpolator(layout)
+ val interp = TextInterpolator(layout, typefaceCache)
interp.basePaint.set(START_PAINT)
interp.onBasePaintModified()
@@ -138,7 +145,7 @@
fun testRebase() {
val layout = makeLayout(TEXT, PAINT)
- val interp = TextInterpolator(layout)
+ val interp = TextInterpolator(layout, typefaceCache)
interp.basePaint.set(START_PAINT)
interp.onBasePaintModified()
@@ -160,7 +167,7 @@
fun testBidi_LTR() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.LTR)
- val interp = TextInterpolator(layout)
+ val interp = TextInterpolator(layout, typefaceCache)
interp.basePaint.set(START_PAINT)
interp.onBasePaintModified()
@@ -180,7 +187,7 @@
fun testBidi_RTL() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
- val interp = TextInterpolator(layout)
+ val interp = TextInterpolator(layout, typefaceCache)
interp.basePaint.set(START_PAINT)
interp.onBasePaintModified()
@@ -200,7 +207,7 @@
fun testGlyphCallback_Empty() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
- val interp = TextInterpolator(layout).apply {
+ val interp = TextInterpolator(layout, typefaceCache).apply {
glyphFilter = { glyph, progress ->
}
}
@@ -222,7 +229,7 @@
fun testGlyphCallback_Xcoordinate() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
- val interp = TextInterpolator(layout).apply {
+ val interp = TextInterpolator(layout, typefaceCache).apply {
glyphFilter = { glyph, progress ->
glyph.x += 30f
}
@@ -247,7 +254,7 @@
fun testGlyphCallback_Ycoordinate() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
- val interp = TextInterpolator(layout).apply {
+ val interp = TextInterpolator(layout, typefaceCache).apply {
glyphFilter = { glyph, progress ->
glyph.y += 30f
}
@@ -272,7 +279,7 @@
fun testGlyphCallback_TextSize() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
- val interp = TextInterpolator(layout).apply {
+ val interp = TextInterpolator(layout, typefaceCache).apply {
glyphFilter = { glyph, progress ->
glyph.textSize += 10f
}
@@ -297,7 +304,7 @@
fun testGlyphCallback_Color() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
- val interp = TextInterpolator(layout).apply {
+ val interp = TextInterpolator(layout, typefaceCache).apply {
glyphFilter = { glyph, progress ->
glyph.color = Color.RED
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
index 6ab54a3..da9ceb4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
@@ -19,6 +19,7 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import com.android.app.animation.Interpolators
@SmallTest
@RunWith(AndroidTestingRunner::class)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index 7d9ccb6..6b5679a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -21,6 +21,7 @@
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import android.util.DisplayMetrics
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.keyguard.KeyguardUpdateMonitor
@@ -35,7 +36,6 @@
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.phone.BiometricUnlockController
-import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.leak.RotationUtils
@@ -66,7 +66,6 @@
private lateinit var staticMockSession: MockitoSession
private lateinit var controller: AuthRippleController
- @Mock private lateinit var mCentralSurfaces: CentralSurfaces
@Mock private lateinit var rippleView: AuthRippleView
@Mock private lateinit var commandRegistry: CommandRegistry
@Mock private lateinit var configurationController: ConfigurationController
@@ -92,6 +91,8 @@
@Mock
private lateinit var fpSensorProp: FingerprintSensorPropertiesInternal
+ private val displayMetrics = DisplayMetrics()
+
@Captor
private lateinit var biometricUnlockListener:
ArgumentCaptor<BiometricUnlockController.BiometricUnlockEventsListener>
@@ -109,7 +110,6 @@
`when`(udfpsControllerProvider.get()).thenReturn(udfpsController)
controller = AuthRippleController(
- mCentralSurfaces,
context,
authController,
configurationController,
@@ -120,13 +120,14 @@
notificationShadeWindowController,
udfpsControllerProvider,
statusBarStateController,
+ displayMetrics,
featureFlags,
KeyguardLogger(logcatLogBuffer(AuthRippleController.TAG)),
biometricUnlockController,
+ lightRevealScrim,
rippleView,
)
controller.init()
- `when`(mCentralSurfaces.lightRevealScrim).thenReturn(lightRevealScrim)
}
@After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
index 58eb7d4..e1c54976 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
@@ -18,7 +18,6 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
@@ -26,13 +25,13 @@
import static org.mockito.Mockito.when;
import android.app.DreamManager;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.shared.condition.Condition;
@@ -55,6 +54,9 @@
@Mock
DreamManager mDreamManager;
+ @Mock
+ KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
@@ -66,7 +68,7 @@
@Test
public void testInitialDreamingState() {
when(mDreamManager.isDreaming()).thenReturn(true);
- final DreamCondition condition = new DreamCondition(mContext, mDreamManager);
+ final DreamCondition condition = new DreamCondition(mDreamManager, mKeyguardUpdateMonitor);
condition.addCallback(mCallback);
verify(mCallback).onConditionChanged(eq(condition));
@@ -79,7 +81,7 @@
@Test
public void testInitialNonDreamingState() {
when(mDreamManager.isDreaming()).thenReturn(false);
- final DreamCondition condition = new DreamCondition(mContext, mDreamManager);
+ final DreamCondition condition = new DreamCondition(mDreamManager, mKeyguardUpdateMonitor);
condition.addCallback(mCallback);
verify(mCallback, never()).onConditionChanged(eq(condition));
@@ -91,15 +93,21 @@
*/
@Test
public void testChange() {
- final ArgumentCaptor<BroadcastReceiver> receiverCaptor =
- ArgumentCaptor.forClass(BroadcastReceiver.class);
+ final ArgumentCaptor<KeyguardUpdateMonitorCallback> callbackCaptor =
+ ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
when(mDreamManager.isDreaming()).thenReturn(true);
- final DreamCondition condition = new DreamCondition(mContext, mDreamManager);
+ final DreamCondition condition = new DreamCondition(mDreamManager, mKeyguardUpdateMonitor);
condition.addCallback(mCallback);
- verify(mContext).registerReceiver(receiverCaptor.capture(), any());
+ verify(mKeyguardUpdateMonitor).registerCallback(callbackCaptor.capture());
+
clearInvocations(mCallback);
- receiverCaptor.getValue().onReceive(mContext, new Intent(Intent.ACTION_DREAMING_STOPPED));
+ callbackCaptor.getValue().onDreamingStateChanged(false);
verify(mCallback).onConditionChanged(eq(condition));
assertThat(condition.isConditionMet()).isFalse();
+
+ clearInvocations(mCallback);
+ callbackCaptor.getValue().onDreamingStateChanged(true);
+ verify(mCallback).onConditionChanged(eq(condition));
+ assertThat(condition.isConditionMet()).isTrue();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
index d0bfaa9..5afc405 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
@@ -23,8 +23,8 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.FlakyTest
import androidx.test.filters.SmallTest
+import com.android.app.animation.Interpolators
import com.android.systemui.SysuiTestCase
-import com.android.systemui.animation.Interpolators
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt
index a5b78b74..3efe382 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.keyguard.ui
import androidx.test.filters.SmallTest
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.SysuiTestCase
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
index a72634b..1a00ac2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
@@ -110,6 +110,7 @@
lateinit var configListener: ArgumentCaptor<ConfigurationController.ConfigurationListener>
@Captor lateinit var visualStabilityCallback: ArgumentCaptor<OnReorderingAllowedListener>
@Captor lateinit var keyguardCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback>
+ @Captor lateinit var hostStateCallback: ArgumentCaptor<MediaHostStatesManager.Callback>
private val clock = FakeSystemClock()
private lateinit var mediaCarouselController: MediaCarouselController
@@ -143,6 +144,7 @@
verify(visualStabilityProvider)
.addPersistentReorderingAllowedListener(capture(visualStabilityCallback))
verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCallback))
+ verify(mediaHostStatesManager).addCallback(capture(hostStateCallback))
whenever(mediaControlPanelFactory.get()).thenReturn(panel)
whenever(panel.mediaViewController).thenReturn(mediaViewController)
whenever(mediaDataManager.smartspaceMediaData).thenReturn(smartspaceMediaData)
@@ -832,4 +834,16 @@
// Verify that seekbar listening attribute in media control panel is set to false.
verify(panel, times(MediaPlayerData.players().size)).listening = false
}
+
+ @Test
+ fun testOnHostStateChanged_updateVisibility() {
+ var stateUpdated = false
+ mediaCarouselController.updateUserVisibility = { stateUpdated = true }
+
+ // When the host state updates
+ hostStateCallback.value!!.onHostStateChanged(LOCATION_QS, mediaHostState)
+
+ // Then the carousel visibility is updated
+ assertTrue(stateUpdated)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
index eb78ded..2ce236d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
@@ -470,6 +470,21 @@
)
}
+ @Test
+ fun testQsExpandedChanged_noQqsMedia() {
+ // When we are looking at QQS with active media
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
+ whenever(statusBarStateController.isExpanded).thenReturn(true)
+
+ // When there is no longer any active media
+ whenever(mediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(false)
+ mediaHierarchyManager.qsExpanded = false
+
+ // Then the carousel is set to not visible
+ verify(mediaCarouselScrollHandler).visibleToUser = false
+ assertThat(mediaCarouselScrollHandler.visibleToUser).isFalse()
+ }
+
private fun enableSplitShade() {
context
.getOrCreateTestableResources()
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/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 068d933..f870631 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -305,6 +305,7 @@
@Mock protected ActivityStarter mActivityStarter;
@Mock protected KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor;
+ protected final int mMaxUdfpsBurnInOffsetY = 5;
protected KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
protected KeyguardInteractor mKeyguardInteractor;
protected NotificationPanelViewController.TouchHandler mTouchHandler;
@@ -365,6 +366,8 @@
when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
mDisplayMetrics.density = 100;
when(mResources.getBoolean(R.bool.config_enableNotificationShadeDrag)).thenReturn(true);
+ when(mResources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y))
+ .thenReturn(mMaxUdfpsBurnInOffsetY);
when(mResources.getDimensionPixelSize(R.dimen.notifications_top_padding_split_shade))
.thenReturn(NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE);
when(mResources.getDimensionPixelSize(R.dimen.notification_panel_margin_horizontal))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 600fb5c..48e0b53 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -29,6 +29,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
@@ -44,6 +45,7 @@
import android.animation.Animator;
import android.animation.ValueAnimator;
+import android.graphics.Point;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.MotionEvent;
@@ -61,6 +63,7 @@
import com.android.systemui.statusbar.notification.row.ExpandableView.OnHeightChangedListener;
import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.phone.KeyguardClockPositionAlgorithm;
import org.junit.Before;
import org.junit.Ignore;
@@ -251,6 +254,43 @@
}
@Test
+ public void testOnDozeAmountChanged_positionClockAndNotificationsUsesUdfpsLocation() {
+ // GIVEN UDFPS is enrolled and we're on the keyguard
+ final Point udfpsLocationCenter = new Point(0, 100);
+ final float udfpsRadius = 10f;
+ when(mUpdateMonitor.isUdfpsEnrolled()).thenReturn(true);
+ when(mAuthController.getUdfpsLocation()).thenReturn(udfpsLocationCenter);
+ when(mAuthController.getUdfpsRadius()).thenReturn(udfpsRadius);
+ mNotificationPanelViewController.getStatusBarStateListener().onStateChanged(KEYGUARD);
+
+ // WHEN the doze amount changes
+ mNotificationPanelViewController.mClockPositionAlgorithm = mock(
+ KeyguardClockPositionAlgorithm.class);
+ mNotificationPanelViewController.getStatusBarStateListener().onDozeAmountChanged(1f, 1f);
+
+ // THEN the clock positions accounts for the UDFPS location & its worst case burn in
+ final float udfpsTop = udfpsLocationCenter.y - udfpsRadius - mMaxUdfpsBurnInOffsetY;
+ verify(mNotificationPanelViewController.mClockPositionAlgorithm).setup(
+ anyInt(),
+ anyFloat(),
+ anyInt(),
+ anyInt(),
+ anyInt(),
+ /* darkAmount */ eq(1f),
+ anyFloat(),
+ anyBoolean(),
+ anyInt(),
+ anyFloat(),
+ anyInt(),
+ anyBoolean(),
+ /* udfpsTop */ eq(udfpsTop),
+ anyFloat(),
+ anyBoolean()
+ );
+ }
+
+
+ @Test
public void testSetExpandedHeight() {
mNotificationPanelViewController.setExpandedHeight(200);
assertThat((int) mNotificationPanelViewController.getExpandedHeight()).isEqualTo(200);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
index 9fe75ab..20da8a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
@@ -33,9 +33,9 @@
import androidx.constraintlayout.motion.widget.MotionLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.test.filters.SmallTest
+import com.android.app.animation.Interpolators
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
-import com.android.systemui.animation.Interpolators
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.battery.BatteryMeterView
import com.android.systemui.battery.BatteryMeterViewController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
index a1168f8..f0abf2f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
@@ -32,9 +32,9 @@
import android.view.View;
import android.view.animation.Interpolator;
+import com.android.app.animation.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.stack.AnimationFilter;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.ViewState;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 219e6a9..c83769d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -101,6 +101,7 @@
import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.biometrics.AuthRippleController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.charging.WiredChargingRippleController;
import com.android.systemui.classifier.FalsingCollectorFake;
@@ -138,6 +139,7 @@
import com.android.systemui.shade.ShadeLogger;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.LightRevealScrim;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -231,10 +233,12 @@
@Mock private IStatusBarService mBarService;
@Mock private IDreamManager mDreamManager;
@Mock private LightRevealScrimViewModel mLightRevealScrimViewModel;
+ @Mock private LightRevealScrim mLightRevealScrim;
@Mock private ScrimController mScrimController;
@Mock private DozeScrimController mDozeScrimController;
@Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
@Mock private BiometricUnlockController mBiometricUnlockController;
+ @Mock private AuthRippleController mAuthRippleController;
@Mock private NotificationListener mNotificationListener;
@Mock private KeyguardViewMediator mKeyguardViewMediator;
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@@ -345,6 +349,7 @@
mFeatureFlags.set(Flags.WM_SHADE_ALLOW_BACK_GESTURE, true);
// For the Shade to animate during the Back gesture, we must enable the animation flag.
mFeatureFlags.set(Flags.WM_SHADE_ANIMATE_BACK_GESTURE, true);
+ mFeatureFlags.set(Flags.LIGHT_REVEAL_MIGRATION, true);
IThermalService thermalService = mock(IThermalService.class);
mPowerManager = new PowerManager(mContext, mPowerManagerService, thermalService,
@@ -497,6 +502,7 @@
mScrimController,
mLockscreenWallpaperLazy,
mBiometricUnlockControllerLazy,
+ mAuthRippleController,
mDozeServiceHost,
mPowerManager, mScreenPinningRequest,
mDozeScrimController,
@@ -538,6 +544,7 @@
mDreamManager,
mCameraLauncherLazy,
() -> mLightRevealScrimViewModel,
+ mLightRevealScrim,
mAlternateBouncerInteractor,
mUserTracker,
() -> mFingerprintManager
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/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index 8cae998..9de7a87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -128,7 +128,7 @@
@Test
public void initDesktopMode_registersListener() {
mWMShell.initDesktopMode(mDesktopMode);
- verify(mDesktopMode).addListener(
+ verify(mDesktopMode).addVisibleTasksListener(
any(DesktopModeTaskRepository.VisibleTasksListener.class),
any(Executor.class));
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeLaunchAnimator.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeLaunchAnimator.kt
index 5b431e7..0983041 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeLaunchAnimator.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeLaunchAnimator.kt
@@ -14,6 +14,8 @@
package com.android.systemui.animation
+import com.android.app.animation.Interpolators
+
/** A [LaunchAnimator] to be used in tests. */
fun fakeLaunchAnimator(): LaunchAnimator {
return LaunchAnimator(TEST_TIMINGS, TEST_INTERPOLATORS)
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index efff112..d8fbd08 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -604,25 +604,21 @@
}
@Override
- @GuardedBy("CompanionDeviceManagerService.this.mTransportManager.mTransports")
public void addOnTransportsChangedListener(IOnTransportsChangedListener listener) {
mTransportManager.addListener(listener);
}
@Override
- @GuardedBy("CompanionDeviceManagerService.this.mTransportManager.mTransports")
public void removeOnTransportsChangedListener(IOnTransportsChangedListener listener) {
mTransportManager.removeListener(listener);
}
@Override
- @GuardedBy("CompanionDeviceManagerService.this.mTransportManager.mTransports")
public void sendMessage(int messageType, byte[] data, int[] associationIds) {
mTransportManager.sendMessage(messageType, data, associationIds);
}
@Override
- @GuardedBy("CompanionDeviceManagerService.this.mTransportManager.mTransports")
public void addOnMessageReceivedListener(int messageType,
IOnMessageReceivedListener listener) {
mTransportManager.addListener(messageType, listener);
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java
index 19d8b87..6f99d86 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java
@@ -17,26 +17,38 @@
package com.android.server.companion.datatransfer.contextsync;
import android.content.ComponentName;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.telecom.Call;
+import android.telecom.Connection;
import android.telecom.ConnectionService;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
+import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
import java.util.UUID;
/** Service for Telecom to bind to when call metadata is synced between devices. */
public class CallMetadataSyncConnectionService extends ConnectionService {
+ private static final String TAG = "CallMetadataSyncConnectionService";
+
+ private AudioManager mAudioManager;
private TelecomManager mTelecomManager;
- private final Map<String, PhoneAccountHandle> mPhoneAccountHandles = new HashMap<>();
+ private final Map<PhoneAccountHandleIdentifier, PhoneAccountHandle> mPhoneAccountHandles =
+ new HashMap<>();
@Override
public void onCreate() {
super.onCreate();
+
+ mAudioManager = getSystemService(AudioManager.class);
mTelecomManager = getSystemService(TelecomManager.class);
}
@@ -44,34 +56,277 @@
* Registers a {@link android.telecom.PhoneAccount} for a given call-capable app on the synced
* device.
*/
- public void registerPhoneAccount(String packageName, String humanReadableAppName) {
- final PhoneAccount phoneAccount = createPhoneAccount(packageName, humanReadableAppName);
- if (phoneAccount != null) {
- mTelecomManager.registerPhoneAccount(phoneAccount);
- mTelecomManager.enablePhoneAccount(mPhoneAccountHandles.get(packageName), true);
- }
+ private void registerPhoneAccount(int associationId, String appIdentifier,
+ String humanReadableAppName) {
+ final PhoneAccountHandleIdentifier phoneAccountHandleIdentifier =
+ new PhoneAccountHandleIdentifier(associationId, appIdentifier);
+ final PhoneAccount phoneAccount = createPhoneAccount(phoneAccountHandleIdentifier,
+ humanReadableAppName);
+ mTelecomManager.registerPhoneAccount(phoneAccount);
+ mTelecomManager.enablePhoneAccount(mPhoneAccountHandles.get(phoneAccountHandleIdentifier),
+ true);
}
/**
* Unregisters a {@link android.telecom.PhoneAccount} for a given call-capable app on the synced
* device.
*/
- public void unregisterPhoneAccount(String packageName) {
- mTelecomManager.unregisterPhoneAccount(mPhoneAccountHandles.remove(packageName));
+ private void unregisterPhoneAccount(int associationId, String appIdentifier) {
+ mTelecomManager.unregisterPhoneAccount(mPhoneAccountHandles.remove(
+ new PhoneAccountHandleIdentifier(associationId, appIdentifier)));
}
@VisibleForTesting
- PhoneAccount createPhoneAccount(String packageName, String humanReadableAppName) {
- if (mPhoneAccountHandles.containsKey(packageName)) {
+ PhoneAccount createPhoneAccount(PhoneAccountHandleIdentifier phoneAccountHandleIdentifier,
+ String humanReadableAppName) {
+ if (mPhoneAccountHandles.containsKey(phoneAccountHandleIdentifier)) {
// Already exists!
return null;
}
final PhoneAccountHandle handle = new PhoneAccountHandle(
new ComponentName(this, CallMetadataSyncConnectionService.class),
UUID.randomUUID().toString());
- mPhoneAccountHandles.put(packageName, handle);
+ mPhoneAccountHandles.put(phoneAccountHandleIdentifier, handle);
return new PhoneAccount.Builder(handle, humanReadableAppName)
.setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER
| PhoneAccount.CAPABILITY_SELF_MANAGED).build();
}
+
+ static final class PhoneAccountHandleIdentifier {
+ private final int mAssociationId;
+ private final String mAppIdentifier;
+
+ PhoneAccountHandleIdentifier(int associationId, String appIdentifier) {
+ mAssociationId = associationId;
+ mAppIdentifier = appIdentifier;
+ }
+
+ public int getAssociationId() {
+ return mAssociationId;
+ }
+
+ public String getAppIdentifier() {
+ return mAppIdentifier;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mAssociationId, mAppIdentifier);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof PhoneAccountHandleIdentifier) {
+ return ((PhoneAccountHandleIdentifier) other).getAssociationId() == mAssociationId
+ && mAppIdentifier != null
+ && mAppIdentifier.equals(
+ ((PhoneAccountHandleIdentifier) other).getAppIdentifier());
+ }
+ return false;
+ }
+ }
+
+ private static final class CallMetadataSyncConnectionIdentifier {
+ private final int mAssociationId;
+ private final long mCallId;
+
+ CallMetadataSyncConnectionIdentifier(int associationId, long callId) {
+ mAssociationId = associationId;
+ mCallId = callId;
+ }
+
+ public int getAssociationId() {
+ return mAssociationId;
+ }
+
+ public long getCallId() {
+ return mCallId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mAssociationId, mCallId);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof CallMetadataSyncConnectionIdentifier) {
+ return ((CallMetadataSyncConnectionIdentifier) other).getAssociationId()
+ == mAssociationId
+ && (((CallMetadataSyncConnectionIdentifier) other).getCallId() == mCallId);
+ }
+ return false;
+ }
+ }
+
+ private abstract static class CallMetadataSyncConnectionCallback {
+
+ abstract void sendCallAction(int associationId, long callId, int action);
+
+ abstract void sendStateChange(int associationId, long callId, int newState);
+ }
+
+ private static class CallMetadataSyncConnection extends Connection {
+
+ private final TelecomManager mTelecomManager;
+ private final AudioManager mAudioManager;
+ private final int mAssociationId;
+ private final CallMetadataSyncData.Call mCall;
+ private final CallMetadataSyncConnectionCallback mCallback;
+
+ CallMetadataSyncConnection(TelecomManager telecomManager, AudioManager audioManager,
+ int associationId, CallMetadataSyncData.Call call,
+ CallMetadataSyncConnectionCallback callback) {
+ mTelecomManager = telecomManager;
+ mAudioManager = audioManager;
+ mAssociationId = associationId;
+ mCall = call;
+ mCallback = callback;
+ }
+
+ public long getCallId() {
+ return mCall.getId();
+ }
+
+ public void initialize() {
+ final int status = mCall.getStatus();
+ if (status == android.companion.Telecom.Call.RINGING_SILENCED) {
+ mTelecomManager.silenceRinger();
+ }
+ final int state = CrossDeviceCall.convertStatusToState(status);
+ if (state == Call.STATE_RINGING) {
+ setRinging();
+ } else if (state == Call.STATE_ACTIVE) {
+ setActive();
+ } else if (state == Call.STATE_HOLDING) {
+ setOnHold();
+ } else {
+ Slog.e(TAG, "Could not initialize call to unknown state");
+ }
+
+ final Bundle extras = new Bundle();
+ extras.putLong(CrossDeviceCall.EXTRA_CALL_ID, mCall.getId());
+ putExtras(extras);
+
+ int capabilities = getConnectionCapabilities();
+ if (mCall.hasControl(android.companion.Telecom.Call.PUT_ON_HOLD)) {
+ capabilities |= CAPABILITY_HOLD;
+ } else {
+ capabilities &= ~CAPABILITY_HOLD;
+ }
+ if (mCall.hasControl(android.companion.Telecom.Call.MUTE)) {
+ capabilities |= CAPABILITY_MUTE;
+ } else {
+ capabilities &= ~CAPABILITY_MUTE;
+ }
+ mAudioManager.setMicrophoneMute(
+ mCall.hasControl(android.companion.Telecom.Call.UNMUTE));
+ if (capabilities != getConnectionCapabilities()) {
+ setConnectionCapabilities(capabilities);
+ }
+ }
+
+ public void update(CallMetadataSyncData.Call call) {
+ final int status = call.getStatus();
+ if (status == android.companion.Telecom.Call.RINGING_SILENCED
+ && mCall.getStatus() != android.companion.Telecom.Call.RINGING_SILENCED) {
+ mTelecomManager.silenceRinger();
+ }
+ mCall.setStatus(status);
+ final int state = CrossDeviceCall.convertStatusToState(status);
+ if (state != getState()) {
+ if (state == Call.STATE_RINGING) {
+ setRinging();
+ } else if (state == Call.STATE_ACTIVE) {
+ setActive();
+ } else if (state == Call.STATE_HOLDING) {
+ setOnHold();
+ } else {
+ Slog.e(TAG, "Could not update call to unknown state");
+ }
+ }
+
+ int capabilities = getConnectionCapabilities();
+ final boolean hasHoldControl = mCall.hasControl(
+ android.companion.Telecom.Call.PUT_ON_HOLD)
+ || mCall.hasControl(android.companion.Telecom.Call.TAKE_OFF_HOLD);
+ if (hasHoldControl != ((getConnectionCapabilities() & CAPABILITY_HOLD)
+ == CAPABILITY_HOLD)) {
+ if (hasHoldControl) {
+ capabilities |= CAPABILITY_HOLD;
+ } else {
+ capabilities &= ~CAPABILITY_HOLD;
+ }
+ }
+ final boolean hasMuteControl = mCall.hasControl(android.companion.Telecom.Call.MUTE);
+ if (hasMuteControl != ((getConnectionCapabilities() & CAPABILITY_MUTE)
+ == CAPABILITY_MUTE)) {
+ if (hasMuteControl) {
+ capabilities |= CAPABILITY_MUTE;
+ } else {
+ capabilities &= ~CAPABILITY_MUTE;
+ }
+ }
+ mAudioManager.setMicrophoneMute(
+ mCall.hasControl(android.companion.Telecom.Call.UNMUTE));
+ if (capabilities != getConnectionCapabilities()) {
+ setConnectionCapabilities(capabilities);
+ }
+ }
+
+ @Override
+ public void onAnswer(int videoState) {
+ sendCallAction(android.companion.Telecom.Call.ACCEPT);
+ }
+
+ @Override
+ public void onReject() {
+ sendCallAction(android.companion.Telecom.Call.REJECT);
+ }
+
+ @Override
+ public void onReject(int rejectReason) {
+ onReject();
+ }
+
+ @Override
+ public void onReject(String replyMessage) {
+ onReject();
+ }
+
+ @Override
+ public void onSilence() {
+ sendCallAction(android.companion.Telecom.Call.SILENCE);
+ }
+
+ @Override
+ public void onHold() {
+ sendCallAction(android.companion.Telecom.Call.PUT_ON_HOLD);
+ }
+
+ @Override
+ public void onUnhold() {
+ sendCallAction(android.companion.Telecom.Call.TAKE_OFF_HOLD);
+ }
+
+ @Override
+ public void onMuteStateChanged(boolean isMuted) {
+ sendCallAction(isMuted ? android.companion.Telecom.Call.MUTE
+ : android.companion.Telecom.Call.UNMUTE);
+ }
+
+ @Override
+ public void onDisconnect() {
+ sendCallAction(android.companion.Telecom.Call.END);
+ }
+
+ @Override
+ public void onStateChanged(int state) {
+ mCallback.sendStateChange(mAssociationId, mCall.getId(), state);
+ }
+
+ private void sendCallAction(int action) {
+ mCallback.sendCallAction(mAssociationId, mCall.getId(), action);
+ }
+ }
}
diff --git a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
index 9677b70..a3e095e 100644
--- a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
+++ b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
@@ -96,27 +96,29 @@
/**
* Add a listener to receive callbacks when a message is received for the message type
*/
- @GuardedBy("mTransports")
public void addListener(int message, @NonNull IOnMessageReceivedListener listener) {
mMessageListeners.put(message, listener);
- for (int i = 0; i < mTransports.size(); i++) {
- mTransports.valueAt(i).addListener(message, listener);
+ synchronized (mTransports) {
+ for (int i = 0; i < mTransports.size(); i++) {
+ mTransports.valueAt(i).addListener(message, listener);
+ }
}
}
/**
* Add a listener to receive callbacks when any of the transports is changed
*/
- @GuardedBy("mTransports")
public void addListener(IOnTransportsChangedListener listener) {
Slog.i(TAG, "Registering OnTransportsChangedListener");
mTransportsListeners.register(listener);
List<AssociationInfo> associations = new ArrayList<>();
- for (int i = 0; i < mTransports.size(); i++) {
- AssociationInfo association = mAssociationStore.getAssociationById(
- mTransports.keyAt(i));
- if (association != null) {
- associations.add(association);
+ synchronized (mTransports) {
+ for (int i = 0; i < mTransports.size(); i++) {
+ AssociationInfo association = mAssociationStore.getAssociationById(
+ mTransports.keyAt(i));
+ if (association != null) {
+ associations.add(association);
+ }
}
}
mTransportsListeners.broadcast(listener1 -> {
@@ -148,18 +150,19 @@
/**
* Send a message to remote devices through the transports
*/
- @GuardedBy("mTransports")
public void sendMessage(int message, byte[] data, int[] associationIds) {
Slog.i(TAG, "Sending message 0x" + Integer.toHexString(message)
+ " data length " + data.length);
- for (int i = 0; i < associationIds.length; i++) {
- if (mTransports.contains(associationIds[i])) {
- try {
- mTransports.get(associationIds[i]).sendMessage(message, data);
- } catch (IOException e) {
- Slog.e(TAG, "Failed to send message 0x" + Integer.toHexString(message)
- + " data length " + data.length + " to association "
- + associationIds[i]);
+ synchronized (mTransports) {
+ for (int i = 0; i < associationIds.length; i++) {
+ if (mTransports.contains(associationIds[i])) {
+ try {
+ mTransports.get(associationIds[i]).sendMessage(message, data);
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to send message 0x" + Integer.toHexString(message)
+ + " data length " + data.length + " to association "
+ + associationIds[i]);
+ }
}
}
}
@@ -215,14 +218,15 @@
}
}
- @GuardedBy("mTransports")
private void notifyOnTransportsChanged() {
List<AssociationInfo> associations = new ArrayList<>();
- for (int i = 0; i < mTransports.size(); i++) {
- AssociationInfo association = mAssociationStore.getAssociationById(
- mTransports.keyAt(i));
- if (association != null) {
- associations.add(association);
+ synchronized (mTransports) {
+ for (int i = 0; i < mTransports.size(); i++) {
+ AssociationInfo association = mAssociationStore.getAssociationById(
+ mTransports.keyAt(i));
+ if (association != null) {
+ associations.add(association);
+ }
}
}
mTransportsListeners.broadcast(listener -> {
@@ -233,14 +237,15 @@
});
}
- @GuardedBy("mTransports")
private void initializeTransport(int associationId, ParcelFileDescriptor fd) {
Slog.i(TAG, "Initializing transport");
if (!isSecureTransportEnabled()) {
Transport transport = new RawTransport(associationId, fd, mContext);
addMessageListenersToTransport(transport);
transport.start();
- mTransports.put(associationId, transport);
+ synchronized (mTransports) {
+ mTransports.put(associationId, transport);
+ }
Slog.i(TAG, "RawTransport is created");
return;
}
@@ -283,7 +288,6 @@
/**
* Depending on the remote platform info to decide which transport should be created
*/
- @GuardedBy("CompanionTransportManager.this.mTransports")
private void onPlatformInfoReceived(int associationId, byte[] data) {
if (mTempTransport.getAssociationId() != associationId) {
return;
@@ -330,7 +334,9 @@
}
addMessageListenersToTransport(transport);
transport.start();
- mTransports.put(transport.getAssociationId(), transport);
+ synchronized (mTransports) {
+ mTransports.put(transport.getAssociationId(), transport);
+ }
// Doesn't need to notifyTransportsChanged here, it'll be done in attachSystemDataTransport
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1f80aec..def2a2f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16707,6 +16707,11 @@
pw.println(String.format("Resources History for %s (%s)",
app.processName,
app.info.packageName));
+ if (app.mOptRecord.isFrozen()) {
+ pw.println(" Skipping frozen process");
+ pw.flush();
+ continue;
+ }
pw.flush();
try {
TransferPipe tp = new TransferPipe(" ");
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index d926c2c..a181402 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -141,6 +141,7 @@
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
/**
* Helper class for {@link ActivityManagerService} responsible for multi-user functionality.
@@ -157,7 +158,7 @@
private static final String TAG = TAG_WITH_CLASS_NAME ? "UserController" : TAG_AM;
// Amount of time we wait for observers to handle a user switch before
- // giving up on them and unfreezing the screen.
+ // giving up on them and dismissing the user switching dialog.
static final int DEFAULT_USER_SWITCH_TIMEOUT_MS = 3 * 1000;
/**
@@ -207,7 +208,7 @@
/**
* Amount of time waited for {@link WindowManagerService#dismissKeyguard} callbacks to be
* called after dismissing the keyguard.
- * Otherwise, we should move on to unfreeze the screen {@link #unfreezeScreen}
+ * Otherwise, we should move on to dismiss the dialog {@link #dismissUserSwitchDialog()}
* and report user switch is complete {@link #REPORT_USER_SWITCH_COMPLETE_MSG}.
*/
private static final int DISMISS_KEYGUARD_TIMEOUT_MS = 2 * 1000;
@@ -1695,14 +1696,6 @@
return false;
}
- if (foreground && isUserSwitchUiEnabled()) {
- t.traceBegin("startFreezingScreen");
- mInjector.getWindowManager().startFreezingScreen(
- R.anim.screen_user_exit, R.anim.screen_user_enter);
- t.traceEnd();
- }
- dismissUserSwitchDialog(); // so that we don't hold a reference to mUserSwitchingDialog
-
boolean needStart = false;
boolean updateUmState = false;
UserState uss;
@@ -1877,7 +1870,7 @@
if (!success) {
mInjector.getWindowManager().setSwitchingUser(false);
mTargetUserId = UserHandle.USER_NULL;
- dismissUserSwitchDialog();
+ dismissUserSwitchDialog(null);
}
}
@@ -2015,22 +2008,26 @@
mUiHandler.sendMessage(mUiHandler.obtainMessage(
START_USER_SWITCH_UI_MSG, userNames));
} else {
- mHandler.removeMessages(START_USER_SWITCH_FG_MSG);
- mHandler.sendMessage(mHandler.obtainMessage(
- START_USER_SWITCH_FG_MSG, targetUserId, 0));
+ sendStartUserSwitchFgMessage(targetUserId);
}
return true;
}
- private void dismissUserSwitchDialog() {
- mInjector.dismissUserSwitchingDialog();
+ private void sendStartUserSwitchFgMessage(int targetUserId) {
+ mHandler.removeMessages(START_USER_SWITCH_FG_MSG);
+ mHandler.sendMessage(mHandler.obtainMessage(START_USER_SWITCH_FG_MSG, targetUserId, 0));
+ }
+
+ private void dismissUserSwitchDialog(Runnable onDismissed) {
+ mInjector.dismissUserSwitchingDialog(onDismissed);
}
private void showUserSwitchDialog(Pair<UserInfo, UserInfo> fromToUserPair) {
// The dialog will show and then initiate the user switch by calling startUserInForeground
mInjector.showUserSwitchingDialog(fromToUserPair.first, fromToUserPair.second,
getSwitchingFromSystemUserMessageUnchecked(),
- getSwitchingToSystemUserMessageUnchecked());
+ getSwitchingToSystemUserMessageUnchecked(),
+ /* onShown= */ () -> sendStartUserSwitchFgMessage(fromToUserPair.second.id));
}
private void dispatchForegroundProfileChanged(@UserIdInt int userId) {
@@ -2236,7 +2233,7 @@
EventLog.writeEvent(EventLogTags.UC_CONTINUE_USER_SWITCH, oldUserId, newUserId);
- // Do the keyguard dismiss and unfreeze later
+ // Do the keyguard dismiss and dismiss the user switching dialog later
mHandler.removeMessages(COMPLETE_USER_SWITCH_MSG);
mHandler.sendMessage(mHandler.obtainMessage(
COMPLETE_USER_SWITCH_MSG, oldUserId, newUserId));
@@ -2251,35 +2248,31 @@
@VisibleForTesting
void completeUserSwitch(int oldUserId, int newUserId) {
final boolean isUserSwitchUiEnabled = isUserSwitchUiEnabled();
- final Runnable runnable = () -> {
- if (isUserSwitchUiEnabled) {
- unfreezeScreen();
- }
- mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
- mHandler.sendMessage(mHandler.obtainMessage(
- REPORT_USER_SWITCH_COMPLETE_MSG, oldUserId, newUserId));
- };
-
- // If there is no challenge set, dismiss the keyguard right away
- if (isUserSwitchUiEnabled && !mInjector.getKeyguardManager().isDeviceSecure(newUserId)) {
- // Wait until the keyguard is dismissed to unfreeze
- mInjector.dismissKeyguard(runnable);
- } else {
- runnable.run();
- }
+ // serialize each conditional step
+ await(
+ // STEP 1 - If there is no challenge set, dismiss the keyguard right away
+ isUserSwitchUiEnabled && !mInjector.getKeyguardManager().isDeviceSecure(newUserId),
+ mInjector::dismissKeyguard,
+ () -> await(
+ // STEP 2 - If user switch ui was enabled, dismiss user switch dialog
+ isUserSwitchUiEnabled,
+ this::dismissUserSwitchDialog,
+ () -> {
+ // STEP 3 - Send REPORT_USER_SWITCH_COMPLETE_MSG to broadcast
+ // ACTION_USER_SWITCHED & call UserSwitchObservers.onUserSwitchComplete
+ mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
+ mHandler.sendMessage(mHandler.obtainMessage(
+ REPORT_USER_SWITCH_COMPLETE_MSG, oldUserId, newUserId));
+ }
+ ));
}
- /**
- * Tell WindowManager we're ready to unfreeze the screen, at its leisure. Note that there is
- * likely a lot going on, and WM won't unfreeze until the drawing is all done, so
- * the actual unfreeze may still not happen for a long time; this is expected.
- */
- @VisibleForTesting
- void unfreezeScreen() {
- TimingsTraceAndSlog t = new TimingsTraceAndSlog();
- t.traceBegin("stopFreezingScreen");
- mInjector.getWindowManager().stopFreezingScreen();
- t.traceEnd();
+ private void await(boolean condition, Consumer<Runnable> conditionalStep, Runnable nextStep) {
+ if (condition) {
+ conditionalStep.accept(nextStep);
+ } else {
+ nextStep.run();
+ }
}
private void moveUserToForeground(UserState uss, int newUserId) {
@@ -3731,17 +3724,18 @@
mService.mCpHelper.installEncryptionUnawareProviders(userId);
}
- void dismissUserSwitchingDialog() {
+ void dismissUserSwitchingDialog(@Nullable Runnable onDismissed) {
synchronized (mUserSwitchingDialogLock) {
if (mUserSwitchingDialog != null) {
- mUserSwitchingDialog.dismiss();
+ mUserSwitchingDialog.dismiss(onDismissed);
mUserSwitchingDialog = null;
}
}
}
void showUserSwitchingDialog(UserInfo fromUser, UserInfo toUser,
- String switchingFromSystemUserMessage, String switchingToSystemUserMessage) {
+ String switchingFromSystemUserMessage, String switchingToSystemUserMessage,
+ @NonNull Runnable onShown) {
if (mService.mContext.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
// config_customUserSwitchUi is set to true on Automotive as CarSystemUI is
@@ -3751,11 +3745,10 @@
+ "condition if it's shown by CarSystemUI as well");
}
synchronized (mUserSwitchingDialogLock) {
- dismissUserSwitchingDialog();
- mUserSwitchingDialog = new UserSwitchingDialog(mService, mService.mContext,
- fromUser, toUser, true /* above system */, switchingFromSystemUserMessage,
- switchingToSystemUserMessage);
- mUserSwitchingDialog.show();
+ dismissUserSwitchingDialog(null);
+ mUserSwitchingDialog = new UserSwitchingDialog(mService.mContext, fromUser, toUser,
+ switchingFromSystemUserMessage, switchingToSystemUserMessage);
+ mUserSwitchingDialog.show(onShown);
}
}
diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index a5651bf..649305f 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -16,160 +16,258 @@
package com.android.server.am;
-import android.app.AlertDialog;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.Dialog;
import android.content.Context;
import android.content.pm.UserInfo;
import android.content.res.Resources;
-import android.os.Handler;
-import android.os.Message;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.graphics.drawable.Animatable2;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.SystemProperties;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
-import android.view.LayoutInflater;
+import android.util.TypedValue;
import android.view.View;
-import android.view.ViewTreeObserver;
+import android.view.Window;
import android.view.WindowManager;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.R;
-import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ObjectUtils;
+import com.android.internal.util.UserIcons;
/**
- * Dialog to show when a user switch it about to happen. The intent is to snapshot the screen
- * immediately after the dialog shows so that the user is informed that something is happening
- * in the background rather than just freeze the screen and not know if the user-switch affordance
- * was being handled.
+ * Dialog to show during the user switch. This dialog shows target user's name and their profile
+ * picture with a circular spinner animation around it if the animations for this dialog are not
+ * disabled. And covers the whole screen so that all the UI jank caused by the switch are hidden.
*/
-class UserSwitchingDialog extends AlertDialog
- implements ViewTreeObserver.OnWindowShownListener {
- private static final String TAG = "ActivityManagerUserSwitchingDialog";
-
- // Time to wait for the onWindowShown() callback before continuing the user switch
- private static final int WINDOW_SHOWN_TIMEOUT_MS = 3000;
+class UserSwitchingDialog extends Dialog {
+ private static final String TAG = "UserSwitchingDialog";
+ private static final long TRACE_TAG = Trace.TRACE_TAG_ACTIVITY_MANAGER;
// User switching doesn't happen that frequently, so it doesn't hurt to have it always on
protected static final boolean DEBUG = true;
+ private static final long DIALOG_SHOW_HIDE_ANIMATION_DURATION_MS = 300;
+ private final boolean mDisableAnimations;
- private final ActivityManagerService mService;
- private final int mUserId;
- private static final int MSG_START_USER = 1;
- @GuardedBy("this")
- private boolean mStartedUser;
- final protected UserInfo mOldUser;
- final protected UserInfo mNewUser;
- final private String mSwitchingFromSystemUserMessage;
- final private String mSwitchingToSystemUserMessage;
- final protected Context mContext;
+ protected final UserInfo mOldUser;
+ protected final UserInfo mNewUser;
+ private final String mSwitchingFromSystemUserMessage;
+ private final String mSwitchingToSystemUserMessage;
+ protected final Context mContext;
+ private final int mTraceCookie;
- public UserSwitchingDialog(ActivityManagerService service, Context context, UserInfo oldUser,
- UserInfo newUser, boolean aboveSystem, String switchingFromSystemUserMessage,
- String switchingToSystemUserMessage) {
- super(context);
+ UserSwitchingDialog(Context context, UserInfo oldUser, UserInfo newUser,
+ String switchingFromSystemUserMessage, String switchingToSystemUserMessage) {
+ // TODO(b/278857848): Make full screen user switcher cover top part of the screen as well.
+ // This problem is seen only on phones, it works fine on tablets.
+ super(context, R.style.Theme_Material_NoActionBar_Fullscreen);
mContext = context;
- mService = service;
- mUserId = newUser.id;
mOldUser = oldUser;
mNewUser = newUser;
mSwitchingFromSystemUserMessage = switchingFromSystemUserMessage;
mSwitchingToSystemUserMessage = switchingToSystemUserMessage;
+ mDisableAnimations = ActivityManager.isLowRamDeviceStatic() || SystemProperties.getBoolean(
+ "debug.usercontroller.disable_user_switching_dialog_animations", false);
+ mTraceCookie = UserHandle.MAX_SECONDARY_USER_ID * oldUser.id + newUser.id;
inflateContent();
+ configureWindow();
+ }
- if (aboveSystem) {
- getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
- }
-
- WindowManager.LayoutParams attrs = getWindow().getAttributes();
+ private void configureWindow() {
+ final Window window = getWindow();
+ final WindowManager.LayoutParams attrs = window.getAttributes();
attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR |
- WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
- getWindow().setAttributes(attrs);
+ WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+ window.setAttributes(attrs);
+ window.setBackgroundDrawableResource(android.R.color.transparent);
+ window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
}
void inflateContent() {
- // Set up the dialog contents
setCancelable(false);
- Resources res = getContext().getResources();
- // Custom view due to alignment and font size requirements
- TextView view = (TextView) LayoutInflater.from(getContext()).inflate(
- R.layout.user_switching_dialog, null);
+ setContentView(R.layout.user_switching_dialog);
- String viewMessage = null;
- if (UserManager.isDeviceInDemoMode(mContext)) {
- if (mOldUser.isDemo()) {
- viewMessage = res.getString(R.string.demo_restarting_message);
- } else {
- viewMessage = res.getString(R.string.demo_starting_message);
- }
- } else {
- if (mOldUser.id == UserHandle.USER_SYSTEM) {
- viewMessage = mSwitchingFromSystemUserMessage;
- } else if (mNewUser.id == UserHandle.USER_SYSTEM) {
- viewMessage = mSwitchingToSystemUserMessage;
- }
-
- // If switchingFromSystemUserMessage or switchingToSystemUserMessage is null, fallback
- // to system message.
- if (viewMessage == null) {
- viewMessage = res.getString(R.string.user_switching_message, mNewUser.name);
- }
-
- view.setCompoundDrawablesWithIntrinsicBounds(null,
- getContext().getDrawable(R.drawable.ic_swap_horiz), null, null);
+ final TextView textView = findViewById(R.id.message);
+ if (textView != null) {
+ final String message = getTextMessage();
+ textView.setAccessibilityPaneTitle(message);
+ textView.setText(message);
}
- view.setAccessibilityPaneTitle(viewMessage);
- view.setText(viewMessage);
- setView(view);
+
+ final ImageView imageView = findViewById(R.id.icon);
+ if (imageView != null) {
+ imageView.setImageBitmap(getUserIconRounded());
+ }
+
+ final ImageView progressCircular = findViewById(R.id.progress_circular);
+ if (progressCircular != null) {
+ if (mDisableAnimations) {
+ progressCircular.setVisibility(View.GONE);
+ } else {
+ final TypedValue value = new TypedValue();
+ getContext().getTheme().resolveAttribute(R.attr.colorAccentPrimary, value, true);
+ progressCircular.setColorFilter(value.data);
+ }
+ }
+ }
+
+ private Bitmap getUserIconRounded() {
+ final Bitmap bmp = ObjectUtils.getOrElse(BitmapFactory.decodeFile(mNewUser.iconPath),
+ defaultUserIcon(mNewUser.id));
+ final int w = bmp.getWidth();
+ final int h = bmp.getHeight();
+ final Bitmap bmpRounded = Bitmap.createBitmap(w, h, bmp.getConfig());
+ final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ paint.setShader(new BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
+ new Canvas(bmpRounded).drawRoundRect((new RectF(0, 0, w, h)), w / 2f, h / 2f, paint);
+ return bmpRounded;
+ }
+
+ private Bitmap defaultUserIcon(@UserIdInt int userId) {
+ final Resources res = getContext().getResources();
+ final Drawable icon = UserIcons.getDefaultUserIcon(res, userId, /* light= */ false);
+ return UserIcons.convertToBitmapAtUserIconSize(res, icon);
+ }
+
+ private String getTextMessage() {
+ final Resources res = getContext().getResources();
+
+ if (UserManager.isDeviceInDemoMode(mContext)) {
+ return res.getString(mOldUser.isDemo()
+ ? R.string.demo_restarting_message
+ : R.string.demo_starting_message);
+ }
+
+ final String message =
+ mOldUser.id == UserHandle.USER_SYSTEM ? mSwitchingFromSystemUserMessage
+ : mNewUser.id == UserHandle.USER_SYSTEM ? mSwitchingToSystemUserMessage : null;
+
+ return message != null ? message
+ // If switchingFromSystemUserMessage or switchingToSystemUserMessage is null,
+ // fallback to system message.
+ : res.getString(R.string.user_switching_message, mNewUser.name);
}
@Override
public void show() {
- if (DEBUG) Slog.d(TAG, "show called");
+ asyncTraceBegin("", 0);
super.show();
- final View decorView = getWindow().getDecorView();
- if (decorView != null) {
- decorView.getViewTreeObserver().addOnWindowShownListener(this);
- }
- // Add a timeout as a safeguard, in case a race in screen on/off causes the window
- // callback to never come.
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_USER),
- WINDOW_SHOWN_TIMEOUT_MS);
}
@Override
- public void onWindowShown() {
- if (DEBUG) Slog.d(TAG, "onWindowShown called");
- startUser();
+ public void dismiss() {
+ super.dismiss();
+ asyncTraceEnd("", 0);
}
- void startUser() {
- synchronized (this) {
- if (!mStartedUser) {
- Slog.i(TAG, "starting user " + mUserId);
- mService.mUserController.startUserInForeground(mUserId);
+ public void show(@NonNull Runnable onShown) {
+ if (DEBUG) Slog.d(TAG, "show called");
+ show();
+
+ if (mDisableAnimations) {
+ onShown.run();
+ } else {
+ startShowAnimation(onShown);
+ }
+ }
+
+ public void dismiss(@Nullable Runnable onDismissed) {
+ if (DEBUG) Slog.d(TAG, "dismiss called");
+
+ if (onDismissed == null) {
+ // no animation needed
+ dismiss();
+ } else if (mDisableAnimations) {
+ dismiss();
+ onDismissed.run();
+ } else {
+ startDismissAnimation(() -> {
dismiss();
- mStartedUser = true;
- final View decorView = getWindow().getDecorView();
- if (decorView != null) {
- decorView.getViewTreeObserver().removeOnWindowShownListener(this);
- }
- mHandler.removeMessages(MSG_START_USER);
- } else {
- Slog.i(TAG, "user " + mUserId + " already started");
- }
+ onDismissed.run();
+ });
}
}
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_START_USER:
- Slog.w(TAG, "user switch window not shown in "
- + WINDOW_SHOWN_TIMEOUT_MS + " ms");
- startUser();
- break;
+ private void startShowAnimation(Runnable onAnimationEnd) {
+ asyncTraceBegin("-showAnimation", 1);
+ startDialogAnimation(new AlphaAnimation(0, 1), () -> {
+ asyncTraceEnd("-showAnimation", 1);
+
+ asyncTraceBegin("-spinnerAnimation", 2);
+ startProgressAnimation(() -> {
+ asyncTraceEnd("-spinnerAnimation", 2);
+
+ onAnimationEnd.run();
+ });
+ });
+ }
+
+ private void startDismissAnimation(Runnable onAnimationEnd) {
+ asyncTraceBegin("-dismissAnimation", 3);
+ startDialogAnimation(new AlphaAnimation(1, 0), () -> {
+ asyncTraceEnd("-dismissAnimation", 3);
+
+ onAnimationEnd.run();
+ });
+ }
+
+ private void startProgressAnimation(Runnable onAnimationEnd) {
+ final ImageView progressCircular = findViewById(R.id.progress_circular);
+ final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) progressCircular.getDrawable();
+ avd.registerAnimationCallback(new Animatable2.AnimationCallback() {
+ @Override
+ public void onAnimationEnd(Drawable drawable) {
+ onAnimationEnd.run();
}
- }
- };
+ });
+ avd.start();
+ }
+
+ private void startDialogAnimation(Animation animation, Runnable onAnimationEnd) {
+ animation.setDuration(DIALOG_SHOW_HIDE_ANIMATION_DURATION_MS);
+ animation.setAnimationListener(new Animation.AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ onAnimationEnd.run();
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+
+ }
+ });
+ findViewById(R.id.content).startAnimation(animation);
+ }
+
+ private void asyncTraceBegin(String subTag, int subCookie) {
+ Trace.asyncTraceBegin(TRACE_TAG, TAG + subTag, mTraceCookie + subCookie);
+ }
+
+ private void asyncTraceEnd(String subTag, int subCookie) {
+ Trace.asyncTraceEnd(TRACE_TAG, TAG + subTag, mTraceCookie + subCookie);
+ }
}
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/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index de10b1b..6d70d21 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -345,6 +345,7 @@
if (!mCurrentDream.mIsPreviewMode && !mSentStartBroadcast) {
mContext.sendBroadcastAsUser(mDreamingStartedIntent, UserHandle.ALL,
null /* receiverPermission */, mDreamingStartedStoppedOptions);
+ mListener.onDreamStarted(mCurrentDream.mToken);
mSentStartBroadcast = true;
}
}
@@ -353,6 +354,7 @@
* Callback interface to be implemented by the {@link DreamManagerService}.
*/
public interface Listener {
+ void onDreamStarted(Binder token);
void onDreamStopped(Binder token);
}
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 0e26d46..d2dcc50 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -84,6 +84,7 @@
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Consumer;
/**
* Service api for managing dreams.
@@ -341,10 +342,24 @@
}
private void reportKeepDreamingWhenUnpluggingChanged(boolean keepDreaming) {
+ notifyDreamStateListeners(
+ listener -> listener.onKeepDreamingWhenUnpluggingChanged(keepDreaming));
+ }
+
+ private void reportDreamingStarted() {
+ notifyDreamStateListeners(listener -> listener.onDreamingStarted());
+ }
+
+ private void reportDreamingStopped() {
+ notifyDreamStateListeners(listener -> listener.onDreamingStopped());
+ }
+
+ private void notifyDreamStateListeners(
+ Consumer<DreamManagerInternal.DreamManagerStateListener> notifier) {
mHandler.post(() -> {
for (DreamManagerInternal.DreamManagerStateListener listener
: mDreamManagerStateListeners) {
- listener.onKeepDreamingWhenUnpluggingChanged(keepDreaming);
+ notifier.accept(listener);
}
});
}
@@ -767,12 +782,23 @@
private final DreamController.Listener mControllerListener = new DreamController.Listener() {
@Override
+ public void onDreamStarted(Binder token) {
+ // Note that this event is distinct from DreamManagerService#startDreamLocked as it
+ // tracks the DreamService attach point from DreamController, closest to the broadcast
+ // of ACTION_DREAMING_STARTED.
+
+ reportDreamingStarted();
+ }
+
+ @Override
public void onDreamStopped(Binder token) {
synchronized (mLock) {
if (mCurrentDream != null && mCurrentDream.token == token) {
cleanupDreamLocked();
}
}
+
+ reportDreamingStopped();
}
};
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 07891f3..d1d6f5f 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -693,6 +693,7 @@
private NotificationRecordLogger mNotificationRecordLogger;
private InstanceIdSequence mNotificationInstanceIdSequence;
private Set<String> mMsgPkgsAllowedAsConvos = new HashSet();
+ private String mDefaultSearchSelectorPkg;
// Broadcast intent receiver for notification permissions review-related intents
private ReviewNotificationPermissionsReceiver mReviewNotificationPermissionsReceiver;
@@ -2435,6 +2436,8 @@
mMsgPkgsAllowedAsConvos = Set.of(getStringArrayResource(
com.android.internal.R.array.config_notificationMsgPkgsAllowedAsConvos));
+ mDefaultSearchSelectorPkg = getContext().getString(getContext().getResources()
+ .getIdentifier("config_defaultSearchSelectorPackageName", "string", "android"));
mFlagResolver = flagResolver;
@@ -6934,7 +6937,12 @@
*/
private boolean canBeNonDismissible(ApplicationInfo ai, Notification notification) {
return notification.isMediaNotification() || isEnterpriseExempted(ai)
- || isCallNotification(ai.packageName, ai.uid, notification);
+ || isCallNotification(ai.packageName, ai.uid, notification)
+ || isDefaultSearchSelectorPackage(ai.packageName);
+ }
+
+ private boolean isDefaultSearchSelectorPackage(String pkg) {
+ return Objects.equals(mDefaultSearchSelectorPkg, pkg);
}
private boolean isEnterpriseExempted(ApplicationInfo ai) {
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/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4094b1a..0532a79 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -710,7 +710,7 @@
final int deviceId = msg.arg1;
final Long eventTime = (Long) msg.obj;
launchAssistAction(null /* hint */, deviceId, eventTime,
- AssistUtils.INVOCATION_TYPE_UNKNOWN);
+ AssistUtils.INVOCATION_TYPE_ASSIST_BUTTON);
break;
case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK:
launchVoiceAssistWithWakeLock();
@@ -2186,12 +2186,6 @@
Intent.EXTRA_DOCK_STATE_UNDOCKED));
}
- // register for dream-related broadcasts
- filter = new IntentFilter();
- filter.addAction(Intent.ACTION_DREAMING_STARTED);
- filter.addAction(Intent.ACTION_DREAMING_STOPPED);
- mContext.registerReceiver(mDreamReceiver, filter);
-
// register for multiuser-relevant broadcasts
filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
mContext.registerReceiver(mMultiuserReceiver, filter);
@@ -4576,6 +4570,12 @@
case KeyEvent.KEYCODE_BACK:
return mWakeOnBackKeyPress;
+
+ case KeyEvent.KEYCODE_STYLUS_BUTTON_PRIMARY:
+ case KeyEvent.KEYCODE_STYLUS_BUTTON_SECONDARY:
+ case KeyEvent.KEYCODE_STYLUS_BUTTON_TERTIARY:
+ case KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL:
+ return mStylusButtonsEnabled;
}
return true;
@@ -4779,21 +4779,6 @@
}
};
- BroadcastReceiver mDreamReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_DREAMING_STARTED.equals(intent.getAction())) {
- if (mKeyguardDelegate != null) {
- mKeyguardDelegate.onDreamingStarted();
- }
- } else if (Intent.ACTION_DREAMING_STOPPED.equals(intent.getAction())) {
- if (mKeyguardDelegate != null) {
- mKeyguardDelegate.onDreamingStopped();
- }
- }
- }
- };
-
BroadcastReceiver mMultiuserReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 646dc4e..495e239 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -18,6 +18,7 @@
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.service.dreams.DreamManagerInternal;
import android.util.Log;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -27,6 +28,7 @@
import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardService;
+import com.android.server.LocalServices;
import com.android.server.UiThread;
import com.android.server.policy.WindowManagerPolicy.OnKeyguardExitResult;
import com.android.server.wm.EventLogTags;
@@ -60,6 +62,19 @@
private DrawnListener mDrawnListenerWhenConnect;
+ private final DreamManagerInternal.DreamManagerStateListener mDreamManagerStateListener =
+ new DreamManagerInternal.DreamManagerStateListener() {
+ @Override
+ public void onDreamingStarted() {
+ KeyguardServiceDelegate.this.onDreamingStarted();
+ }
+
+ @Override
+ public void onDreamingStopped() {
+ KeyguardServiceDelegate.this.onDreamingStopped();
+ }
+ };
+
private static final class KeyguardState {
KeyguardState() {
reset();
@@ -158,6 +173,11 @@
} else {
if (DEBUG) Log.v(TAG, "*** Keyguard started");
}
+
+ final DreamManagerInternal dreamManager =
+ LocalServices.getService(DreamManagerInternal.class);
+
+ dreamManager.registerDreamManagerStateListener(mDreamManagerStateListener);
}
private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
diff --git a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
index d844c6f..9647a62 100644
--- a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
+++ b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
@@ -84,6 +84,7 @@
PERMISSION_POLICY_ORDERED_ID,
VIRTUAL_DEVICE_SERVICE_ORDERED_ID,
DREAM_MANAGER_ORDERED_ID,
+ PRODUCT_ORDERED_ID,
SYSTEM_LAST_ORDERED_ID, // Update this when adding new ids
// Order Ids for mainline module services
MAINLINE_FIRST_ORDERED_ID,
@@ -119,11 +120,18 @@
int DREAM_MANAGER_ORDERED_ID = 4;
/**
+ * The identifier for an interceptor which is specific to the type of android product like
+ * automotive, wear, TV etc.
+ * @hide
+ */
+ int PRODUCT_ORDERED_ID = 5;
+
+ /**
* The final id, used by the framework to determine the valid range of ids. Update this when
* adding new ids.
* @hide
*/
- int SYSTEM_LAST_ORDERED_ID = DREAM_MANAGER_ORDERED_ID;
+ int SYSTEM_LAST_ORDERED_ID = PRODUCT_ORDERED_ID;
/**
* The first mainline module id, used by the framework to determine the valid range of ids
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f93afe8..ea0731a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1996,6 +1996,24 @@
}
}
+ @Override
+ public void focusTopTask(int displayId) {
+ enforceTaskPermission("focusTopTask()");
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final DisplayContent dc = mRootWindowContainer.getDisplayContent(displayId);
+ if (dc == null) return;
+ final Task task = dc.getTask((t) -> t.isLeafTask() && t.isFocusable(),
+ true /* traverseTopToBottom */);
+ if (task == null) return;
+ setFocusedTask(task.mTaskId, null /* touchedActivity */);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
void setFocusedTask(int taskId, ActivityRecord touchedActivity) {
ProtoLog.d(WM_DEBUG_FOCUS, "setFocusedTask: taskId=%d touchedActivity=%s", taskId,
touchedActivity);
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 0ae9c4c..e8e4792 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -192,6 +192,8 @@
private void detachPlayer() {
if (mTransitionPlayer == null) return;
+ // Immediately set to null so that nothing inadvertently starts/queues.
+ mTransitionPlayer = null;
// Clean-up/finish any playing transitions.
for (int i = 0; i < mPlayingTransitions.size(); ++i) {
mPlayingTransitions.get(i).cleanUpOnFailure();
@@ -200,7 +202,6 @@
if (mCollectingTransition != null) {
mCollectingTransition.abort();
}
- mTransitionPlayer = null;
mTransitionPlayerProc = null;
mRemotePlayer.clear();
mRunningLock.doNotifyLocked();
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/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index a299592..f3b3382 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5634,7 +5634,7 @@
private void dropBufferFrom(Transaction t) {
SurfaceControl viewSurface = getClientViewRootSurface();
if (viewSurface == null) return;
- t.setBuffer(viewSurface, (android.hardware.HardwareBuffer) null);
+ t.unsetBuffer(viewSurface);
}
@Override
diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS
index 2584b86..d9acf41 100644
--- a/services/core/jni/OWNERS
+++ b/services/core/jni/OWNERS
@@ -27,3 +27,4 @@
per-file com_android_server_tv_* = file:/media/java/android/media/tv/OWNERS
per-file com_android_server_vibrator_* = file:/services/core/java/com/android/server/vibrator/OWNERS
per-file com_android_server_am_CachedAppOptimizer.cpp = timmurray@google.com, edgararriaga@google.com, dualli@google.com, carmenjackson@google.com, philipcuadra@google.com
+per-file com_android_server_companion_virtual_InputController.cpp = file:/services/companion/java/com/android/server/companion/virtual/OWNERS
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/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index f39de43..0271727 100644
--- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
@@ -19,7 +19,6 @@
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
-import android.credentials.CredentialOption;
import android.credentials.CredentialProviderInfo;
import android.credentials.GetCredentialException;
import android.credentials.GetCredentialRequest;
@@ -36,7 +35,6 @@
import java.util.ArrayList;
import java.util.Set;
-import java.util.stream.Collectors;
/**
* Central session for a single getCredentials request. This class listens to the
@@ -56,11 +54,7 @@
super(context, sessionCallback, lock, userId, callingUid, request, callback,
RequestInfo.TYPE_GET, callingAppInfo, enabledProviders, cancellationSignal,
startedTimestamp);
- int numTypes = (request.getCredentialOptions().stream()
- .map(CredentialOption::getType).collect(
- Collectors.toSet())).size(); // Dedupe type strings
- mRequestSessionMetric.collectGetFlowInitialMetricInfo(numTypes,
- /*origin=*/request.getOrigin() != null);
+ mRequestSessionMetric.collectGetFlowInitialMetricInfo(request);
}
/**
diff --git a/services/credentials/java/com/android/server/credentials/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
index 47b45ac..50e5163 100644
--- a/services/credentials/java/com/android/server/credentials/MetricUtilities.java
+++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
@@ -50,6 +50,8 @@
public static final int UNIT = 1;
// Used for zero count metric emits, such as zero amounts of various types
public static final int ZERO = 0;
+ // The number of characters at the end of the string to use as a key
+ public static final int DELTA_CUT = 20;
/**
* This retrieves the uid of any package name, given a context and a component name for the
@@ -87,6 +89,18 @@
}
/**
+ * Given the current design, we can designate how the strings in the backend should appear.
+ * This helper method lets us cut strings for our class types.
+ *
+ * @param classtype the classtype string we want to cut to generate a key
+ * @param deltaFromEnd the starting point from the end of the string we wish to begin at
+ * @return the cut up string key we want to use for metric logs
+ */
+ public static String generateMetricKey(String classtype, int deltaFromEnd) {
+ return classtype.substring(classtype.length() - deltaFromEnd);
+ }
+
+ /**
* A logging utility used primarily for the final phase of the current metric setup.
*
* @param finalPhaseMetric the coalesced data of the chosen provider
@@ -158,13 +172,17 @@
}
/**
- * A logging utility used primarily for the candidate phase of the current metric setup.
+ * A logging utility used primarily for the candidate phase of the current metric setup. This
+ * will primarily focus on track 2, where the session id is associated with known providers,
+ * but NOT the calling app.
*
* @param providers a map with known providers and their held metric objects
* @param emitSequenceId an emitted sequence id for the current session
+ * @param initialPhaseMetric contains initial phase data to avoid repetition for candidate
+ * phase, track 2, logging
*/
public static void logApiCalledCandidatePhase(Map<String, ProviderSession> providers,
- int emitSequenceId) {
+ int emitSequenceId, InitialPhaseMetric initialPhaseMetric) {
try {
if (!LOG_FLAG) {
return;
@@ -184,6 +202,7 @@
int[] candidateActionEntryCountList = new int[providerSize];
int[] candidateAuthEntryCountList = new int[providerSize];
int[] candidateRemoteEntryCountList = new int[providerSize];
+ String[] frameworkExceptionList = new String[providerSize];
int index = 0;
for (var session : providerSessions) {
CandidatePhaseMetric metric = session.mProviderSessionMetric
@@ -209,6 +228,7 @@
candidateActionEntryCountList[index] = metric.getActionEntryCount();
candidateAuthEntryCountList[index] = metric.getAuthenticationEntryCount();
candidateRemoteEntryCountList[index] = metric.getRemoteEntryCount();
+ frameworkExceptionList[index] = metric.getFrameworkException();
index++;
}
FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_CANDIDATE_PHASE_REPORTED,
@@ -229,11 +249,16 @@
/* candidate_provider_credential_entry_type_count */
candidateCredentialTypeCountList,
/* candidate_provider_remote_entry_count */ candidateRemoteEntryCountList,
- /* candidate_provider_authentication_entry_count */ candidateAuthEntryCountList,
- DEFAULT_REPEATED_STR,
- false,
- DEFAULT_REPEATED_STR,
- DEFAULT_REPEATED_INT_32
+ /* candidate_provider_authentication_entry_count */
+ candidateAuthEntryCountList,
+ /* framework_exception_per_provider */
+ frameworkExceptionList,
+ /* origin_specified originSpecified */
+ initialPhaseMetric.isOriginSpecified(),
+ /* request_unique_classtypes */
+ initialPhaseMetric.getUniqueRequestStrings(),
+ /* per_classtype_counts */
+ initialPhaseMetric.getUniqueRequestCounts()
);
} catch (Exception e) {
Log.w(TAG, "Unexpected error during metric logging: " + e);
@@ -297,10 +322,11 @@
initialPhaseMetric.getCredentialServiceStartedTimeNanoseconds(),
/* count_credential_request_classtypes */
initialPhaseMetric.getCountRequestClassType(),
- // TODO(b/271135048) - add total count of request options
- // TODO(b/271135048) - Uncomment once built past PWG review -
- DEFAULT_REPEATED_STR,
- DEFAULT_REPEATED_INT_32,
+ /* request_unique_classtypes */
+ initialPhaseMetric.getUniqueRequestStrings(),
+ /* per_classtype_counts */
+ initialPhaseMetric.getUniqueRequestCounts(),
+ /* origin_specified */
initialPhaseMetric.isOriginSpecified()
);
} catch (Exception e) {
diff --git a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
index 1c3d213c..441c87b 100644
--- a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
@@ -59,8 +59,7 @@
int numTypes = (request.getCredentialOptions().stream()
.map(CredentialOption::getType).collect(
Collectors.toSet())).size(); // Dedupe type strings
- mRequestSessionMetric.collectGetFlowInitialMetricInfo(numTypes,
- /*origin=*/request.getOrigin() != null);
+ mRequestSessionMetric.collectGetFlowInitialMetricInfo(request);
mPrepareGetCredentialCallback = prepareGetCredentialCallback;
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
index 9ec0ecd..8af6b56 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
@@ -91,6 +91,8 @@
public void onProviderResponseFailure(int errorCode, Exception exception) {
if (exception instanceof ClearCredentialStateException) {
mProviderException = (ClearCredentialStateException) exception;
+ // TODO(b/271135048) : Decide on exception type length
+ mProviderSessionMetric.collectCandidateFrameworkException(mProviderException.getType());
}
mProviderSessionMetric.collectCandidateExceptionStatus(/*hasException=*/true);
updateStatusAndInvokeCallback(toStatus(errorCode),
diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
index 09433db..520b937 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
@@ -155,6 +155,8 @@
if (exception instanceof CreateCredentialException) {
// Store query phase exception for aggregation with final response
mProviderException = (CreateCredentialException) exception;
+ // TODO(b/271135048) : Decide on exception type length
+ mProviderSessionMetric.collectCandidateFrameworkException(mProviderException.getType());
}
mProviderSessionMetric.collectCandidateExceptionStatus(/*hasException=*/true);
updateStatusAndInvokeCallback(toStatus(errorCode),
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index 0c2b563..a62d9e8 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -217,6 +217,8 @@
public void onProviderResponseFailure(int errorCode, Exception exception) {
if (exception instanceof GetCredentialException) {
mProviderException = (GetCredentialException) exception;
+ // TODO(b/271135048) : Decide on exception type length
+ mProviderSessionMetric.collectCandidateFrameworkException(mProviderException.getType());
}
mProviderSessionMetric.collectCandidateExceptionStatus(/*hasException=*/true);
updateStatusAndInvokeCallback(toStatus(errorCode),
diff --git a/services/credentials/java/com/android/server/credentials/metrics/ApiName.java b/services/credentials/java/com/android/server/credentials/metrics/ApiName.java
index ce84d9a..b99f28d 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/ApiName.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/ApiName.java
@@ -57,7 +57,7 @@
);
ApiName(int innerMetricCode) {
- this.mInnerMetricCode = innerMetricCode;
+ mInnerMetricCode = innerMetricCode;
}
/**
@@ -66,7 +66,7 @@
* @return a code corresponding to the west world metric name
*/
public int getMetricCode() {
- return this.mInnerMetricCode;
+ return mInnerMetricCode;
}
/**
diff --git a/services/credentials/java/com/android/server/credentials/metrics/ApiStatus.java b/services/credentials/java/com/android/server/credentials/metrics/ApiStatus.java
index 4097765..ece729f 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/ApiStatus.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/ApiStatus.java
@@ -32,7 +32,7 @@
private final int mInnerMetricCode;
ApiStatus(int innerMetricCode) {
- this.mInnerMetricCode = innerMetricCode;
+ mInnerMetricCode = innerMetricCode;
}
/**
@@ -41,6 +41,6 @@
* @return a code corresponding to the west world metric name
*/
public int getMetricCode() {
- return this.mInnerMetricCode;
+ return mInnerMetricCode;
}
}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java
index 10d4f9c..721d3d7 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/CandidatePhaseMetric.java
@@ -73,6 +73,8 @@
private int mAuthenticationEntryCount = -1;
// Gathered to pass on to chosen provider when required
private final IntArray mAvailableEntries = new IntArray();
+ // The *framework only* exception held by this provider, empty string by default
+ private String mFrameworkException = "";
public CandidatePhaseMetric() {
}
@@ -82,27 +84,27 @@
/* -- Timestamps -- */
public void setServiceBeganTimeNanoseconds(long serviceBeganTimeNanoseconds) {
- this.mServiceBeganTimeNanoseconds = serviceBeganTimeNanoseconds;
+ mServiceBeganTimeNanoseconds = serviceBeganTimeNanoseconds;
}
public void setStartQueryTimeNanoseconds(long startQueryTimeNanoseconds) {
- this.mStartQueryTimeNanoseconds = startQueryTimeNanoseconds;
+ mStartQueryTimeNanoseconds = startQueryTimeNanoseconds;
}
public void setQueryFinishTimeNanoseconds(long queryFinishTimeNanoseconds) {
- this.mQueryFinishTimeNanoseconds = queryFinishTimeNanoseconds;
+ mQueryFinishTimeNanoseconds = queryFinishTimeNanoseconds;
}
public long getServiceBeganTimeNanoseconds() {
- return this.mServiceBeganTimeNanoseconds;
+ return mServiceBeganTimeNanoseconds;
}
public long getStartQueryTimeNanoseconds() {
- return this.mStartQueryTimeNanoseconds;
+ return mStartQueryTimeNanoseconds;
}
public long getQueryFinishTimeNanoseconds() {
- return this.mQueryFinishTimeNanoseconds;
+ return mQueryFinishTimeNanoseconds;
}
/* -- Actual time delta latencies (for local utility) -- */
@@ -111,8 +113,8 @@
* Returns the latency in microseconds for the query phase.
*/
public int getQueryLatencyMicroseconds() {
- return (int) ((this.getQueryFinishTimeNanoseconds()
- - this.getStartQueryTimeNanoseconds()) / 1000);
+ return (int) ((getQueryFinishTimeNanoseconds()
+ - getStartQueryTimeNanoseconds()) / 1000);
}
/* --- Time Stamp Conversion to Microseconds from Reference --- */
@@ -126,32 +128,32 @@
* @return the microsecond integer timestamp from service start to query began
*/
public int getTimestampFromReferenceStartMicroseconds(long specificTimestamp) {
- if (specificTimestamp < this.mServiceBeganTimeNanoseconds) {
+ if (specificTimestamp < mServiceBeganTimeNanoseconds) {
Log.i(TAG, "The timestamp is before service started, falling back to default int");
return MetricUtilities.DEFAULT_INT_32;
}
return (int) ((specificTimestamp
- - this.mServiceBeganTimeNanoseconds) / 1000);
+ - mServiceBeganTimeNanoseconds) / 1000);
}
/* ------------- Provider Query Status ------------ */
public void setProviderQueryStatus(int providerQueryStatus) {
- this.mProviderQueryStatus = providerQueryStatus;
+ mProviderQueryStatus = providerQueryStatus;
}
public int getProviderQueryStatus() {
- return this.mProviderQueryStatus;
+ return mProviderQueryStatus;
}
/* -------------- Candidate Uid ---------------- */
public void setCandidateUid(int candidateUid) {
- this.mCandidateUid = candidateUid;
+ mCandidateUid = candidateUid;
}
public int getCandidateUid() {
- return this.mCandidateUid;
+ return mCandidateUid;
}
/* -------------- Session Id ---------------- */
@@ -254,7 +256,7 @@
* collector
*/
public void addEntry(EntryEnum e) {
- this.mAvailableEntries.add(e.getMetricCode());
+ mAvailableEntries.add(e.getMetricCode());
}
/**
@@ -267,4 +269,14 @@
public List<Integer> getAvailableEntries() {
return Arrays.stream(mAvailableEntries.toArray()).boxed().collect(Collectors.toList());
}
+
+ /* ------ Framework Exception for this Candidate ------ */
+
+ public void setFrameworkException(String frameworkException) {
+ mFrameworkException = frameworkException;
+ }
+
+ public String getFrameworkException() {
+ return mFrameworkException;
+ }
}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java
index 2eef197..c80cc24 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderFinalPhaseMetric.java
@@ -138,8 +138,8 @@
}
public int getUiPhaseLatencyMicroseconds() {
- return (int) ((this.mUiCallEndTimeNanoseconds
- - this.mUiCallStartTimeNanoseconds) / 1000);
+ return (int) ((mUiCallEndTimeNanoseconds
+ - mUiCallStartTimeNanoseconds) / 1000);
}
/**
@@ -147,8 +147,8 @@
* start time to be provided, such as from {@link CandidatePhaseMetric}.
*/
public int getEntireProviderLatencyMicroseconds() {
- return (int) ((this.mFinalFinishTimeNanoseconds
- - this.mQueryStartTimeNanoseconds) / 1000);
+ return (int) ((mFinalFinishTimeNanoseconds
+ - mQueryStartTimeNanoseconds) / 1000);
}
/**
@@ -156,8 +156,8 @@
* start time to be provided, such as from {@link InitialPhaseMetric}.
*/
public int getEntireLatencyMicroseconds() {
- return (int) ((this.mFinalFinishTimeNanoseconds
- - this.mServiceBeganTimeNanoseconds) / 1000);
+ return (int) ((mFinalFinishTimeNanoseconds
+ - mServiceBeganTimeNanoseconds) / 1000);
}
/* ----- Timestamps for Latency ----- */
@@ -183,11 +183,11 @@
}
public void setUiCallStartTimeNanoseconds(long uiCallStartTimeNanoseconds) {
- this.mUiCallStartTimeNanoseconds = uiCallStartTimeNanoseconds;
+ mUiCallStartTimeNanoseconds = uiCallStartTimeNanoseconds;
}
public void setUiCallEndTimeNanoseconds(long uiCallEndTimeNanoseconds) {
- this.mUiCallEndTimeNanoseconds = uiCallEndTimeNanoseconds;
+ mUiCallEndTimeNanoseconds = uiCallEndTimeNanoseconds;
}
public void setFinalFinishTimeNanoseconds(long finalFinishTimeNanoseconds) {
@@ -229,12 +229,12 @@
* @return the microsecond integer timestamp from service start to query began
*/
public int getTimestampFromReferenceStartMicroseconds(long specificTimestamp) {
- if (specificTimestamp < this.mServiceBeganTimeNanoseconds) {
+ if (specificTimestamp < mServiceBeganTimeNanoseconds) {
Log.i(TAG, "The timestamp is before service started, falling back to default int");
return MetricUtilities.DEFAULT_INT_32;
}
return (int) ((specificTimestamp
- - this.mServiceBeganTimeNanoseconds) / 1000);
+ - mServiceBeganTimeNanoseconds) / 1000);
}
/* ----------- Provider Status -------------- */
@@ -334,7 +334,7 @@
* chosen phase in a semantically correct way.
*/
public void setAvailableEntries(List<Integer> entries) {
- this.mAvailableEntries = new ArrayList<>(entries); // no alias copy
+ mAvailableEntries = new ArrayList<>(entries); // no alias copy
}
/**
@@ -345,7 +345,7 @@
* candidate phase.
*/
public List<Integer> getAvailableEntries() {
- return new ArrayList<>(this.mAvailableEntries); // no alias copy
+ return new ArrayList<>(mAvailableEntries); // no alias copy
}
/* -------------- Has Exception ---------------- */
diff --git a/services/credentials/java/com/android/server/credentials/metrics/EntryEnum.java b/services/credentials/java/com/android/server/credentials/metrics/EntryEnum.java
index 80f9fdc..b9125dd 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/EntryEnum.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/EntryEnum.java
@@ -56,7 +56,7 @@
);
EntryEnum(int innerMetricCode) {
- this.mInnerMetricCode = innerMetricCode;
+ mInnerMetricCode = innerMetricCode;
}
/**
@@ -65,7 +65,7 @@
* @return a code corresponding to the west world metric name
*/
public int getMetricCode() {
- return this.mInnerMetricCode;
+ return mInnerMetricCode;
}
/**
diff --git a/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java
index 0210b14..0ecd9cc 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java
@@ -16,6 +16,11 @@
package com.android.server.credentials.metrics;
+import android.util.Log;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
/**
* This handles metrics collected prior to any remote calls to providers.
* Some types are redundant across these metric collectors, but that has debug use-cases as
@@ -32,7 +37,6 @@
private int mCallerUid = -1;
// The session id to unite multiple atom emits, default to -1
private int mSessionId = -1;
- private int mCountRequestClassType = -1;
// Raw timestamps in nanoseconds, *the only* one logged as such (i.e. 64 bits) since it is a
// reference point.
@@ -46,6 +50,9 @@
// TODO(b/271135048) - Emit once metrics approved
private boolean mOriginSpecified = false;
+ // Stores the deduped request information, particularly {"req":5}.
+ private Map<String, Integer> mRequestCounts = new LinkedHashMap<>();
+
public InitialPhaseMetric() {
}
@@ -55,8 +62,8 @@
/* -- Direct Latency Utility -- */
public int getServiceStartToQueryLatencyMicroseconds() {
- return (int) ((this.mCredentialServiceStartedTimeNanoseconds
- - this.mCredentialServiceBeginQueryTimeNanoseconds) / 1000);
+ return (int) ((mCredentialServiceStartedTimeNanoseconds
+ - mCredentialServiceBeginQueryTimeNanoseconds) / 1000);
}
/* -- Timestamps -- */
@@ -64,7 +71,7 @@
public void setCredentialServiceStartedTimeNanoseconds(
long credentialServiceStartedTimeNanoseconds
) {
- this.mCredentialServiceStartedTimeNanoseconds = credentialServiceStartedTimeNanoseconds;
+ mCredentialServiceStartedTimeNanoseconds = credentialServiceStartedTimeNanoseconds;
}
public void setCredentialServiceBeginQueryTimeNanoseconds(
@@ -112,13 +119,11 @@
/* ------ Count Request Class Types ------ */
- public void setCountRequestClassType(int countRequestClassType) {
- mCountRequestClassType = countRequestClassType;
+ public int getCountRequestClassType() {
+ return mRequestCounts.size();
}
- public int getCountRequestClassType() {
- return mCountRequestClassType;
- }
+ /* ------ Origin Specified ------ */
public void setOriginSpecified(boolean originSpecified) {
mOriginSpecified = originSpecified;
@@ -127,4 +132,34 @@
public boolean isOriginSpecified() {
return mOriginSpecified;
}
+
+ /* ------ Unique Request Counts Map Information ------ */
+
+ public void setRequestCounts(Map<String, Integer> requestCounts) {
+ mRequestCounts = requestCounts;
+ }
+
+ /**
+ * Reruns the unique, deduped, request classtypes for logging.
+ * @return a string array for deduped classtypes
+ */
+ public String[] getUniqueRequestStrings() {
+ if (mRequestCounts.isEmpty()) {
+ Log.w(TAG, "There are no unique string request types collected");
+ }
+ String[] result = new String[mRequestCounts.keySet().size()];
+ mRequestCounts.keySet().toArray(result);
+ return result;
+ }
+
+ /**
+ * Reruns the unique, deduped, request classtype counts for logging.
+ * @return a string array for deduped classtype counts
+ */
+ public int[] getUniqueRequestCounts() {
+ if (mRequestCounts.isEmpty()) {
+ Log.w(TAG, "There are no unique string request type counts collected");
+ }
+ return mRequestCounts.values().stream().mapToInt(Integer::intValue).toArray();
+ }
}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java b/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java
index 76fd478..9a88255 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java
@@ -61,6 +61,18 @@
}
/**
+ * Collects the framework only exception encountered in a candidate flow.
+ * @param exceptionType the string, cut to desired length, of the exception type
+ */
+ public void collectCandidateFrameworkException(String exceptionType) {
+ try {
+ mCandidatePhasePerProviderMetric.setFrameworkException(exceptionType);
+ } catch (Exception e) {
+ Log.w(TAG, "Unexpected error during metric logging: " + e);
+ }
+ }
+
+ /**
* Used to collect metrics at the update stage when a candidate provider gives back an update.
*
* @param isFailureStatus indicates the candidate provider sent back a terminated response
diff --git a/services/credentials/java/com/android/server/credentials/metrics/ProviderStatusForMetrics.java b/services/credentials/java/com/android/server/credentials/metrics/ProviderStatusForMetrics.java
index a12a694..b1e6a4c 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/ProviderStatusForMetrics.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/ProviderStatusForMetrics.java
@@ -38,7 +38,7 @@
private final int mInnerMetricCode;
ProviderStatusForMetrics(int innerMetricCode) {
- this.mInnerMetricCode = innerMetricCode;
+ mInnerMetricCode = innerMetricCode;
}
/**
@@ -47,6 +47,6 @@
* @return a code corresponding to the west world metric name
*/
public int getMetricCode() {
- return this.mInnerMetricCode;
+ return mInnerMetricCode;
}
}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
index 10bf56c..547c09a 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
@@ -16,10 +16,12 @@
package com.android.server.credentials.metrics;
+import static com.android.server.credentials.MetricUtilities.DELTA_CUT;
+import static com.android.server.credentials.MetricUtilities.generateMetricKey;
import static com.android.server.credentials.MetricUtilities.logApiCalledCandidatePhase;
import static com.android.server.credentials.MetricUtilities.logApiCalledFinalPhase;
-import android.annotation.NonNull;
+import android.credentials.GetCredentialRequest;
import android.credentials.ui.UserSelectionDialogResult;
import android.os.IBinder;
import android.util.Log;
@@ -27,6 +29,7 @@
import com.android.server.credentials.ProviderSession;
import java.util.ArrayList;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -48,7 +51,6 @@
protected final ChosenProviderFinalPhaseMetric
mChosenProviderFinalPhaseMetric = new ChosenProviderFinalPhaseMetric();
// TODO(b/271135048) - Replace this with a new atom per each browsing emit (V4)
- @NonNull
protected List<CandidateBrowsingPhaseMetric> mCandidateBrowsingPhaseMetric = new ArrayList<>();
public RequestSessionMetric() {
@@ -161,16 +163,32 @@
}
}
+ // Used by get flows to generate the unique request count maps
+ private Map<String, Integer> getRequestCountMap(GetCredentialRequest request) {
+ Map<String, Integer> uniqueRequestCounts = new LinkedHashMap<>();
+ try {
+ request.getCredentialOptions().forEach(option -> {
+ String optionKey = generateMetricKey(option.getType(), DELTA_CUT);
+ if (!uniqueRequestCounts.containsKey(optionKey)) {
+ uniqueRequestCounts.put(optionKey, 0);
+ }
+ uniqueRequestCounts.put(optionKey, uniqueRequestCounts.get(optionKey) + 1);
+ });
+ } catch (Exception e) {
+ Log.w(TAG, "Unexpected error during get request metric logging: " + e);
+ }
+ return uniqueRequestCounts;
+ }
+
/**
* Collects initializations for Get flow metrics.
*
- * @param requestClassTypeCount the number of class types in the request
- * @param origin indicates if an origin was passed in or not
+ * @param request the get credential request containing information to parse for metrics
*/
- public void collectGetFlowInitialMetricInfo(int requestClassTypeCount, boolean origin) {
+ public void collectGetFlowInitialMetricInfo(GetCredentialRequest request) {
try {
- mInitialPhaseMetric.setCountRequestClassType(requestClassTypeCount);
- mInitialPhaseMetric.setOriginSpecified(origin);
+ mInitialPhaseMetric.setOriginSpecified(request.getOrigin() != null);
+ mInitialPhaseMetric.setRequestCounts(getRequestCountMap(request));
} catch (Exception e) {
Log.w(TAG, "Unexpected error during metric logging: " + e);
}
@@ -306,7 +324,7 @@
*/
public void logCandidatePhaseMetrics(Map<String, ProviderSession> providers) {
try {
- logApiCalledCandidatePhase(providers, ++mSequenceCounter);
+ logApiCalledCandidatePhase(providers, ++mSequenceCounter, mInitialPhaseMetric);
} catch (Exception e) {
Log.w(TAG, "Unexpected error during metric logging: " + e);
}
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/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index ab8f3f2..d12741a 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -211,8 +211,7 @@
@Test
public void testStartUser_foreground() {
mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND);
- verify(mInjector.getWindowManager()).startFreezingScreen(anyInt(), anyInt());
- verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
+ verify(mInjector, never()).dismissUserSwitchingDialog(any());
verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(anyBoolean());
verify(mInjector.getWindowManager()).setSwitchingUser(true);
verify(mInjector).clearAllLockedTasks(anyString());
@@ -224,7 +223,8 @@
public void testStartUser_background() {
boolean started = mUserController.startUser(TEST_USER_ID, USER_START_MODE_BACKGROUND);
assertWithMessage("startUser(%s, foreground=false)", TEST_USER_ID).that(started).isTrue();
- verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
+ verify(mInjector, never()).showUserSwitchingDialog(
+ any(), any(), anyString(), anyString(), any());
verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
verify(mInjector, never()).clearAllLockedTasks(anyString());
startBackgroundUserAssertions();
@@ -276,7 +276,8 @@
assertWithMessage("startUserOnDisplay(%s, %s)", TEST_USER_ID, 42).that(started).isTrue();
verifyUserAssignedToDisplay(TEST_USER_ID, 42);
- verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
+ verify(mInjector, never()).showUserSwitchingDialog(
+ any(), any(), anyString(), anyString(), any());
verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
verify(mInjector, never()).clearAllLockedTasks(anyString());
startBackgroundUserAssertions();
@@ -288,8 +289,9 @@
/* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND);
- verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
- verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
+ verify(mInjector, never()).showUserSwitchingDialog(
+ any(), any(), anyString(), anyString(), any());
+ verify(mInjector, never()).dismissUserSwitchingDialog(any());
verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
startForegroundUserAssertions();
}
@@ -310,7 +312,8 @@
// Make sure no intents have been fired for pre-created users.
assertTrue(mInjector.mSentIntents.isEmpty());
- verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
+ verify(mInjector, never()).showUserSwitchingDialog(
+ any(), any(), anyString(), anyString(), any());
verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
verify(mInjector, never()).clearAllLockedTasks(anyString());
@@ -442,7 +445,7 @@
// Verify that continueUserSwitch worked as expected
continueAndCompleteUserSwitch(userState, oldUserId, newUserId);
verify(mInjector, times(0)).dismissKeyguard(any());
- verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen();
+ verify(mInjector, times(1)).dismissUserSwitchingDialog(any());
continueUserSwitchAssertions(oldUserId, TEST_USER_ID, false);
verifySystemUserVisibilityChangesNeverNotified();
}
@@ -463,7 +466,7 @@
// Verify that continueUserSwitch worked as expected
continueAndCompleteUserSwitch(userState, oldUserId, newUserId);
verify(mInjector, times(1)).dismissKeyguard(any());
- verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen();
+ verify(mInjector, times(1)).dismissUserSwitchingDialog(any());
continueUserSwitchAssertions(oldUserId, TEST_USER_ID, false);
verifySystemUserVisibilityChangesNeverNotified();
}
@@ -483,7 +486,7 @@
mInjector.mHandler.clearAllRecordedMessages();
// Verify that continueUserSwitch worked as expected
continueAndCompleteUserSwitch(userState, oldUserId, newUserId);
- verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
+ verify(mInjector, never()).dismissUserSwitchingDialog(any());
continueUserSwitchAssertions(oldUserId, TEST_USER_ID, false);
}
@@ -985,8 +988,7 @@
mInjector.mHandler.clearAllRecordedMessages();
// Verify that continueUserSwitch worked as expected
continueAndCompleteUserSwitch(userState, oldUserId, newUserId);
- verify(mInjector.getWindowManager(), times(expectedNumberOfCalls))
- .stopFreezingScreen();
+ verify(mInjector, times(expectedNumberOfCalls)).dismissUserSwitchingDialog(any());
continueUserSwitchAssertions(oldUserId, newUserId, expectOldUserStopping);
}
@@ -1189,6 +1191,22 @@
}
@Override
+ void showUserSwitchingDialog(UserInfo fromUser, UserInfo toUser,
+ String switchingFromSystemUserMessage, String switchingToSystemUserMessage,
+ Runnable onShown) {
+ if (onShown != null) {
+ onShown.run();
+ }
+ }
+
+ @Override
+ void dismissUserSwitchingDialog(Runnable onDismissed) {
+ if (onDismissed != null) {
+ onDismissed.run();
+ }
+ }
+
+ @Override
protected LockPatternUtils getLockPatternUtils() {
return mLockPatternUtilsMock;
}
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionServiceTest.java
index 3ed95eb..bacf256 100644
--- a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionServiceTest.java
@@ -45,16 +45,22 @@
@Test
public void createPhoneAccount_success() {
final PhoneAccount phoneAccount = mSyncConnectionService.createPhoneAccount(
- "com.google.test", "Test App");
+ new CallMetadataSyncConnectionService.PhoneAccountHandleIdentifier(/*
+ associationId= */
+ 0, "com.google.test"), "Test App");
assertWithMessage("Could not create phone account").that(phoneAccount).isNotNull();
}
@Test
public void createPhoneAccount_alreadyExists_doesNotCreateAnother() {
final PhoneAccount phoneAccount = mSyncConnectionService.createPhoneAccount(
- "com.google.test", "Test App");
+ new CallMetadataSyncConnectionService.PhoneAccountHandleIdentifier(/*
+ associationId= */
+ 0, "com.google.test"), "Test App");
final PhoneAccount phoneAccount2 = mSyncConnectionService.createPhoneAccount(
- "com.google.test", "Test App #2");
+ new CallMetadataSyncConnectionService.PhoneAccountHandleIdentifier(/*
+ associationId= */
+ 0, "com.google.test"), "Test App #2");
assertWithMessage("Could not create phone account").that(phoneAccount).isNotNull();
assertWithMessage("Unexpectedly created second phone account").that(phoneAccount2).isNull();
}
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/servicestests/src/com/android/server/dreams/DreamControllerTest.java b/services/tests/servicestests/src/com/android/server/dreams/DreamControllerTest.java
index 1ef1197..d5ad815 100644
--- a/services/tests/servicestests/src/com/android/server/dreams/DreamControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/dreams/DreamControllerTest.java
@@ -25,6 +25,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.ActivityTaskManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.ServiceConnection;
@@ -54,6 +55,10 @@
private DreamController.Listener mListener;
@Mock
private Context mContext;
+
+ @Mock
+ private ActivityTaskManager mActivityTaskManager;
+
@Mock
private IBinder mIBinder;
@Mock
@@ -80,6 +85,10 @@
when(mIDreamService.asBinder()).thenReturn(mIBinder);
when(mIBinder.queryLocalInterface(anyString())).thenReturn(mIDreamService);
when(mContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(true);
+ when(mContext.getSystemService(Context.ACTIVITY_TASK_SERVICE))
+ .thenReturn(mActivityTaskManager);
+ when(mContext.getSystemServiceName(ActivityTaskManager.class))
+ .thenReturn(Context.ACTIVITY_TASK_SERVICE);
mToken = new Binder();
mDreamName = ComponentName.unflattenFromString("dream");
@@ -104,6 +113,37 @@
}
@Test
+ public void startDream_dreamListenerNotified() {
+ // Call dream controller to start dreaming.
+ mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/,
+ 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/);
+
+ // Mock service connected.
+ final ServiceConnection serviceConnection = captureServiceConnection();
+ serviceConnection.onServiceConnected(mDreamName, mIBinder);
+ mLooper.dispatchAll();
+
+ // Verify that dream service is called to attach.
+ verify(mListener).onDreamStarted(any());
+ }
+
+ @Test
+ public void stopDream_dreamListenerNotified() {
+ // Start dream.
+ mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/,
+ 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/);
+ captureServiceConnection().onServiceConnected(mDreamName, mIBinder);
+ mLooper.dispatchAll();
+
+ // Stop dream.
+ mDreamController.stopDream(true /*immediate*/, "test stop dream" /*reason*/);
+ mLooper.dispatchAll();
+
+ // Verify that dream service is called to detach.
+ verify(mListener).onDreamStopped(any());
+ }
+
+ @Test
public void startDream_attachOnServiceConnectedInPreviewMode() throws RemoteException {
// Call dream controller to start dreaming.
mDreamController.startDream(mToken, mDreamName, true /*isPreview*/, false /*doze*/,
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 dd9f3cb..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;
@@ -358,7 +357,7 @@
private static final int NOTIFICATION_LOCATION_UNKNOWN = 0;
private static final String VALID_CONVO_SHORTCUT_ID = "shortcut";
-
+ private static final String SEARCH_SELECTOR_PKG = "searchSelector";
@Mock
private NotificationListeners mListeners;
@Mock
@@ -549,6 +548,10 @@
// apps allowed as convos
mService.setStringArrayResourceValue(PKG_O);
+ TestableResources tr = mContext.getOrCreateTestableResources();
+ tr.addOverride(com.android.internal.R.string.config_defaultSearchSelectorPackageName,
+ SEARCH_SELECTOR_PKG);
+
mWorkerHandler = spy(mService.new WorkerHandler(mTestableLooper.getLooper()));
mService.init(mWorkerHandler, mRankingHandler, mPackageManager, mPackageManagerClient,
mockLightsManager, mListeners, mAssistants, mConditionProviders, mCompanionMgr,
@@ -5308,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());
}
@@ -10636,6 +10639,34 @@
}
@Test
+ public void fixSystemNotification_defaultSearchSelectior_withOnGoingFlag_nondismissible()
+ throws Exception {
+ final ApplicationInfo ai = new ApplicationInfo();
+ ai.packageName = SEARCH_SELECTOR_PKG;
+ ai.uid = mUid;
+ ai.flags |= ApplicationInfo.FLAG_SYSTEM;
+
+ when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
+ .thenReturn(ai);
+ when(mAppOpsManager.checkOpNoThrow(
+ AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid,
+ ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED);
+ // Given: a notification from an app on the system partition has the flag
+ // FLAG_ONGOING_EVENT set
+ // feature flag: ALLOW_DISMISS_ONGOING is on
+ mTestFlagResolver.setFlagOverride(ALLOW_DISMISS_ONGOING, true);
+ Notification n = new Notification.Builder(mContext, "test")
+ .setOngoing(true)
+ .build();
+
+ // When: fix the notification with NotificationManagerService
+ mService.fixNotification(n, PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true);
+
+ // Then: the notification's flag FLAG_NO_DISMISS should be set
+ assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS);
+ }
+
+ @Test
public void fixCallNotification_withOnGoingFlag_shouldNotBeNonDismissible()
throws Exception {
// Given: a call notification has the flag FLAG_ONGOING_EVENT set
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");
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 7abae18..f27c23b 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -7640,6 +7640,25 @@
public static final String KEY_EMERGENCY_SCAN_TIMER_SEC_INT =
KEY_PREFIX + "emergency_scan_timer_sec_int";
+ /**
+ * The timer to wait for the call completion on the cellular network before attempting the
+ * call over Wi-Fi. On timer expiry, if emergency call on Wi-Fi is allowed and possible,
+ * telephony shall cancel the scan on the cellular network and place the call on Wi-Fi.
+ * If dialing over cellular network is ongoing when timer expires, dialing over Wi-Fi
+ * will be requested only when the ongoing dialing fails. If emergency call on Wi-Fi is not
+ * possible, then domain selection continues to try dialing from the radio and the timer
+ * remains expired. Later when calling over Wi-Fi is possible and dialing over cellular
+ * networks fails, calling over Wi-Fi will be requested. The timer shall be restarted from
+ * initial state if calling over Wi-Fi fails.
+ * If this value is set to {@link #REDIAL_TIMER_DISABLED}, then the timer will never be
+ * started.
+ *
+ * The default value for the timer is {@link #REDIAL_TIMER_DISABLED}.
+ * @hide
+ */
+ public static final String KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT =
+ KEY_PREFIX + "maximum_cellular_search_timer_sec_int";
+
/** @hide */
@IntDef(prefix = "SCAN_TYPE_",
value = {
@@ -7734,10 +7753,12 @@
KEY_PREFIX + "emergency_requires_volte_enabled_bool";
/**
- * This values indicates that the cross SIM redialing timer shall be disabled.
+ * This values indicates that the cross SIM redialing timer and maximum celluar search
+ * timer shall be disabled.
*
* @see #KEY_CROSS_STACK_REDIAL_TIMER_SEC_INT
* @see #KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT
+ * @see #KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT
* @hide
*/
public static final int REDIAL_TIMER_DISABLED = 0;
@@ -7841,6 +7862,7 @@
defaults.putInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT, VOWIFI_REQUIRES_NONE);
defaults.putInt(KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT, 1);
defaults.putInt(KEY_EMERGENCY_SCAN_TIMER_SEC_INT, 10);
+ defaults.putInt(KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT, REDIAL_TIMER_DISABLED);
defaults.putInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT, SCAN_TYPE_NO_PREFERENCE);
defaults.putInt(KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT, 0);
defaults.putBoolean(KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL, false);
diff --git a/telephony/java/android/telephony/UiccCardInfo.java b/telephony/java/android/telephony/UiccCardInfo.java
index e5e8f0a..6c069d4 100644
--- a/telephony/java/android/telephony/UiccCardInfo.java
+++ b/telephony/java/android/telephony/UiccCardInfo.java
@@ -166,7 +166,7 @@
+ " Please Use UiccPortInfo API instead");
}
//always return ICCID from first port.
- return getPorts().stream().findFirst().get().getIccId();
+ return mPortList.isEmpty() ? null : mPortList.get(0).getIccId();
}
/**
diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java
index 1863a03b..dda7349 100644
--- a/telephony/java/android/telephony/UiccSlotInfo.java
+++ b/telephony/java/android/telephony/UiccSlotInfo.java
@@ -139,14 +139,16 @@
public UiccSlotInfo(boolean isEuicc, String cardId,
@CardStateInfo int cardStateInfo, boolean isExtendedApduSupported,
boolean isRemovable, @NonNull List<UiccPortInfo> portList) {
- this.mIsActive = portList.get(0).isActive();
this.mIsEuicc = isEuicc;
this.mCardId = cardId;
this.mCardStateInfo = cardStateInfo;
- this.mLogicalSlotIdx = portList.get(0).getLogicalSlotIndex();
this.mIsExtendedApduSupported = isExtendedApduSupported;
this.mIsRemovable = isRemovable;
this.mPortList = portList;
+ this.mIsActive = !portList.isEmpty() && portList.get(0).isActive();
+ this.mLogicalSlotIdx = portList.isEmpty()
+ ? SubscriptionManager.INVALID_PHONE_INDEX
+ : portList.get(0).getLogicalSlotIndex();
}
/**
@@ -164,8 +166,7 @@
throw new UnsupportedOperationException("getIsActive() is not supported by "
+ "UiccSlotInfo. Please Use UiccPortInfo API instead");
}
- //always return status from first port.
- return getPorts().stream().findFirst().get().isActive();
+ return mIsActive;
}
public boolean getIsEuicc() {
@@ -202,9 +203,7 @@
throw new UnsupportedOperationException("getLogicalSlotIdx() is not supported by "
+ "UiccSlotInfo. Please use UiccPortInfo API instead");
}
- //always return logical slot index from first port.
- //portList always have at least one element.
- return getPorts().stream().findFirst().get().getLogicalSlotIndex();
+ return mLogicalSlotIdx;
}
/**
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
index a72c12d..c5a21a8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -250,7 +250,10 @@
waitConditions = arrayOf(ConditionsFactory.hasPipWindow())
)
- wmHelper.StateSyncBuilder().withPipShown().waitForAndVerify()
+ wmHelper.StateSyncBuilder()
+ .withWindowSurfaceAppeared(this)
+ .withPipShown()
+ .waitForAndVerify()
}
/** Expand the PIP window back to full screen via intent and wait until the app is visible */