diff options
270 files changed, 3799 insertions, 1724 deletions
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 3312294865d6..9e59ee496de1 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -2547,7 +2547,7 @@ public class AppOpsManager { .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 d62e15a94f89..3249b41da934 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -174,6 +174,9 @@ interface IActivityTaskManager { 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 746dcb6f2e13..d8cedb8fa5d2 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -44,6 +44,7 @@ import org.json.JSONObject; 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 @@ public final class NotificationChannel implements Parcelable { 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 @@ public final class NotificationChannel implements Parcelable { /** * @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 @@ public final class NotificationChannel implements Parcelable { */ @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 @@ public final class NotificationChannel implements Parcelable { 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 @@ public final class NotificationChannel implements Parcelable { 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 @@ public final class NotificationChannel implements Parcelable { // 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 @@ public final class NotificationChannel implements Parcelable { 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 a8a2ad1bb8df..7b6835792370 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -8394,8 +8394,7 @@ public class DevicePolicyManager { * <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 @@ public class DevicePolicyManager { 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 7701125780f4..875550aea5f5 100644 --- a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java +++ b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java @@ -46,6 +46,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; 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 @@ public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl { 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 2efb26593780..3487b013fa0b 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -4677,22 +4677,16 @@ public final class Settings { "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 82571db469be..e9bb28c252e0 100644 --- a/core/java/android/service/dreams/DreamManagerInternal.java +++ b/core/java/android/service/dreams/DreamManagerInternal.java @@ -84,6 +84,19 @@ public abstract class DreamManagerInternal { * * @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 e31adcfd699e..f2373fbfa858 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -341,6 +341,9 @@ public final class DisplayInfo implements Parcelable { @Nullable public DisplayShape displayShape; + /** + * Refresh rate range limitation based on the current device layout + */ @Nullable public SurfaceControl.RefreshRateRange layoutLimitedRefreshRate; @@ -354,7 +357,7 @@ public final class DisplayInfo implements Parcelable { * 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 @@ public final class DisplayInfo implements Parcelable { && 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 @@ public final class DisplayInfo implements Parcelable { displayShape = other.displayShape; layoutLimitedRefreshRate = other.layoutLimitedRefreshRate; hdrSdrRatio = other.hdrSdrRatio; - refreshRateThermalThrottling = other.refreshRateThermalThrottling; + thermalRefreshRateThrottling = other.thermalRefreshRateThrottling; } public void readFromParcel(Parcel source) { @@ -554,7 +557,7 @@ public final class DisplayInfo implements Parcelable { 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 @@ public final class DisplayInfo implements Parcelable { dest.writeTypedObject(displayShape, flags); dest.writeTypedObject(layoutLimitedRefreshRate, flags); dest.writeFloat(hdrSdrRatio); - dest.writeSparseArray(refreshRateThermalThrottling); + dest.writeSparseArray(thermalRefreshRateThrottling); } @Override @@ -884,8 +887,8 @@ public final class DisplayInfo implements Parcelable { } 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 77f3b1da92b4..dd4f9644da96 100644 --- a/core/java/android/view/HandwritingInitiator.java +++ b/core/java/android/view/HandwritingInitiator.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; 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 @@ public class HandwritingInitiator { mImm.startStylusHandwriting(view); mState.mHasInitiatedHandwriting = true; mState.mShouldInitHandwriting = false; + if (view instanceof TextView) { + ((TextView) view).hideHint(); + } } /** @@ -323,6 +327,9 @@ public class HandwritingInitiator { 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 bc6a3b540ce7..99deac4c8cf4 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -220,6 +220,7 @@ public final class SurfaceControl implements Parcelable { 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 @@ public final class SurfaceControl implements Parcelable { } /** + * 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 @@ public final class SurfaceControl implements Parcelable { * 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 @@ public final class SurfaceControl implements Parcelable { * 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 @@ public final class SurfaceControl implements Parcelable { * 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. + * + * <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) * - * Must be finite && >= 1.0f + * <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 6bd9538a9f65..c0ac04ccd4d8 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -647,11 +647,18 @@ public final class ViewRootImpl implements ViewParent, 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 @@ public final class ViewRootImpl implements ViewParent, } 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 @@ public final class ViewRootImpl implements ViewParent, mActiveSurfaceSyncGroup.markSyncReady(); mActiveSurfaceSyncGroup = null; } + if (mHasPendingTransactions) { + mPendingTransaction.apply(); + } WindowManagerGlobal.getInstance().doRemoveView(this); } @@ -11114,12 +11128,11 @@ public final class ViewRootImpl implements ViewParent, } 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 @@ public final class ViewRootImpl implements ViewParent, 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 @@ public final class ViewRootImpl implements ViewParent, + 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/widget/TextView.java b/core/java/android/widget/TextView.java index 3fbb50581b25..34fe935b55a0 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -806,6 +806,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private CharSequence mHint; @UnsupportedAppUsage private Layout mHintLayout; + private boolean mHideHint; private MovementMethod mMovement; @@ -7180,6 +7181,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } private void setHintInternal(CharSequence hint) { + mHideHint = false; mHint = TextUtils.stringOrSpannedString(hint); if (mLayout != null) { @@ -7379,6 +7383,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** + * 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } private boolean isShowingHint() { - return TextUtils.isEmpty(mText) && !TextUtils.isEmpty(mHint); + return TextUtils.isEmpty(mText) && !TextUtils.isEmpty(mHint) && !mHideHint; } /** @@ -12437,6 +12454,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener sendOnTextChanged(buffer, start, before, after); onTextChanged(buffer, start, before, after); + mHideHint = false; clearGesturePreviewHighlight(); } @@ -12577,6 +12595,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 d4ff794ea5ec..57cc38cc6dfd 100644 --- a/core/java/com/android/internal/app/AssistUtils.java +++ b/core/java/com/android/internal/app/AssistUtils.java @@ -57,6 +57,8 @@ public class AssistUtils { 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 000000000000..39d8380c7e95 --- /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 0a0785e16f2a..80f540cca79b 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.graphics.HardwareRendererObserver; 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.FrameMetrics; 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 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener } } + 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 class FrameTracker extends SurfaceControl.OnJankDataListener 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 4b9e77e83166..c769fb95e018 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_IN 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.UiThread; 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 @@ import java.util.concurrent.TimeUnit; * 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 @@ public class InteractionJankMonitor { "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 @@ public class InteractionJankMonitor { /** 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 @@ public class InteractionJankMonitor { 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 @@ public class InteractionJankMonitor { 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 @@ public class InteractionJankMonitor { 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 @@ public class InteractionJankMonitor { 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 @@ public class InteractionJankMonitor { 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 @@ public class InteractionJankMonitor { } } - 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 @@ public class InteractionJankMonitor { 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 @@ public class InteractionJankMonitor { } /** + * 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 000000000000..99b9f2f35fd4 --- /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 8e96ac136370..193099baad48 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -616,6 +616,12 @@ static void nativeSetBuffer(JNIEnv* env, jclass clazz, jlong transactionObj, jlo 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 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (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 11fcd1e248db..997a0c9bf46d 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/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java index 8ae63816ba16..c0125afef2e8 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 android.view.stylus.HandwritingTestUtil.createView; 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.InputDevice; 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 androidx.test.platform.app.InstrumentationRegistry; 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 @@ public class HandwritingInitiatorTest { 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 03d366e6e552..57a1376a6cd1 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.PackageManager; 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 androidx.test.runner.AndroidJUnit4; 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 @@ import java.util.Collections; @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 @@ public class AccessibilityShortcutChooserActivityTest { @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 @@ public class AccessibilityShortcutChooserActivityTest { 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); - - 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()); + openShortcutsList(); + + // 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 @@ public class AccessibilityShortcutChooserActivityTest { 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); - - 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()); + openShortcutsList(); + 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); - - 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()); + openShortcutsList(); + 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 56c3068fe5e9..302c72ead52e 100644 --- a/graphics/java/android/graphics/ImageDecoder.java +++ b/graphics/java/android/graphics/ImageDecoder.java @@ -42,7 +42,6 @@ import android.media.MediaCodecInfo; 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 @@ public final class ImageDecoder implements AutoCloseable { } 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/desktopmode/DesktopMode.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java index cbd544cc4b86..e732a0354806 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 @@ public interface DesktopMode { * @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 2bdbde1b71d4..86ea72582a52 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.ActivityManager.RunningTaskInfo; 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.ArrayList; 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 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll * @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 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll } /** + * 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 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll 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.addVisibleTasksListener(listener, callbackExecutor); + }); + } + + @Override + public void addDesktopGestureExclusionRegionListener(Consumer<Region> listener, Executor callbackExecutor) { mMainExecutor.execute(() -> { - DesktopModeController.this.addListener(listener, callbackExecutor); + 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 47342c9f21ee..12f8ea23ac8f 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 @@ class DesktopModeTaskRepository { 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 @@ class DesktopModeTaskRepository { } /** + * 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 @@ class DesktopModeTaskRepository { } /** + * 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 0400963a47e8..0d5602365578 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.app.WindowConfiguration.WindowingMode 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 @@ class DesktopTasksController( 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 @@ class DesktopTasksController( * @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 4f362d4ed0d8..eb4d2a16c522 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.IBinder; 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 class RecentsTransitionHandler implements Transitions.TransitionHandler { 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 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { 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 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { // 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 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { 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 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { 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 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { 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 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { 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 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { 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 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { 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 e4f27240b2cb..cca63ef2b5d6 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.IBinder; 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 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, 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 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, 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 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, 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 49a5eac5fd07..8fb56fc2561b 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.Context; 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.desktopmode.DesktopTasksController; 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 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { 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 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { 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 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { 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 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { 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 af3fb0ead55c..f9fdd831a42c 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.MotionEvent; 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mOnCaptionTouchListener = onCaptionTouchListener; } + void setCornersListener(TaskCornersListener cornersListener) { + mCornersListener = cornersListener; + } + void setDragPositioningCallback(DragPositioningCallback dragPositioningCallback) { mDragPositioningCallback = dragPositioningCallback; } @@ -189,20 +165,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin .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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin * 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin */ 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin public void close() { closeDragResizeListener(); closeHandleMenu(); + mCornersListener.onTaskCornersRemoved(mTaskInfo.taskId); super.close(); } @@ -598,6 +418,15 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin : 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 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin 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 d5437c72acac..34c8c087cf95 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 @@ class DragResizeInputListener implements AutoCloseable { * @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 @@ class DragResizeInputListener implements AutoCloseable { } 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 000000000000..ed3cca078084 --- /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 9a1b4ffbd50c..e772fc25f8cf 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 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> 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 c57e6f09347a..38d17de166e9 100644 --- a/libs/hwui/jni/BitmapFactory.cpp +++ b/libs/hwui/jni/BitmapFactory.cpp @@ -401,6 +401,14 @@ static jobject doDecode(JNIEnv* env, std::unique_ptr<SkStreamRewindable> stream, 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 45bffc44967d..a079cb4b513d 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 jfieldID gOptions_bitmapFieldID; 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 db1c188e425e..6744c6c0b9ec 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 @@ static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong 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 @@ int register_android_graphics_ImageDecoder(JNIEnv* env) { gImageDecoder_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder")); gImageDecoder_constructorMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "<init>", "(JIIZZ)V"); gImageDecoder_postProcessMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "postProcessAndRelease", "(Landroid/graphics/Canvas;)I"); + gImageDecoder_isP010SupportedForHEVCMethodID = + GetStaticMethodIDOrDie(env, gImageDecoder_class, "isP010SupportedForHEVC", "()Z"); gSize_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/util/Size")); gSize_constructorMethodID = GetMethodIDOrDie(env, gSize_class, "<init>", "(II)V"); diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java index 6a5535d345db..e4cc9f15aea1 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 @@ public class SystemSettings { 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 85623b26c589..4b720636c1d4 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 @@ public class SystemSettingsValidators { 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 6d375ac215a4..48259e165670 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 com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManage 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 @@ public class SettingsHelper { 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 @@ public class SettingsHelper { 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 @@ public class SettingsHelper { 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 284b06b86cb6..d1bd5e661072 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 android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OV 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 @@ public class SettingsProvider extends ContentProvider { } 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 @@ public class SettingsProvider extends ContentProvider { 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 @@ public class SettingsProvider extends ContentProvider { } } 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 @@ public class SettingsProvider extends ContentProvider { 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 @@ public class SettingsProvider extends ContentProvider { 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 @@ public class SettingsProvider extends ContentProvider { 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 706666cbebab..36aa2ac74406 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -97,8 +97,7 @@ public class SettingsBackupTest { 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 ee76dbf8ce70..bc81c4441af5 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 @@ public class SettingsHelperTest { 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 62c6c1df91b2..865b0dfe0ee8 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -173,6 +173,7 @@ android_library { "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 24de487945db..4652ef195a0c 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 5b5871f95fb3..8eb012d2e41c 100644 --- a/packages/SystemUI/animation/Android.bp +++ b/packages/SystemUI/animation/Android.bp @@ -43,6 +43,7 @@ android_library { "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 296c2ae5cf99..2e803798fccb 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.Interpolator 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 42a86363bf01..48dd08f206c1 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.WindowInsets 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 9dbb9205b90e..000000000000 --- 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 8da87feb1fee..000000000000 --- 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 3417ffd6b83a..142fd21d4a16 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.util.MathUtils 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 3ee97be360f0..9346a2f7ebb7 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.Canvas 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 @@ typealias GlyphCallback = (TextAnimator.PositionedGlyph, Float) -> Unit * ``` * </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 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) { } 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 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) { 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 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) { } 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 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) { 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 23f16f2a3137..a041926bf5d2 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 com.android.internal.graphics.ColorUtils 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 58ffef25cb42..8e79e3ce1742 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.util.IntProperty 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 f3d8b1782486..dd32851a97cf 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 @@ package com.android.systemui.animation.back 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/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt index 86bd5f2bff5a..3688f9e35e63 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.text.format.DateFormat 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 @@ class AnimatableClockView @JvmOverloads constructor( 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 index bf922bc98bcb..08ee60204178 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 f59bf8e766fe..64d766dcd488 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.content.res.TypedArray 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 a6c782d88e18..a30cae950dfe 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -15,9 +15,9 @@ import android.widget.RelativeLayout; 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 03947542d21e..09820305f34e 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java @@ -32,9 +32,9 @@ import android.view.animation.Interpolator; 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 33bea027cd20..1d7c35d0c90d 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java @@ -45,11 +45,11 @@ import android.widget.TextView; 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 0a91150e6c39..b4ddc9a975c2 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.util.AttributeSet; 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 ba5a8c94dc23..78021ad21a77 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.START; 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.constraintlayout.widget.ConstraintSet; 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.Utils; 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 c9128e5881cc..96ac8ad56651 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.util.MathUtils 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 65a71664e245..b4f124aa598a 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.core.SliceQuery; 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 edfcb8d0d1a6..89e7e17a7ce1 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.annotation.VisibleForTesting; 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 651c9796140e..aa652fabb294 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java @@ -21,7 +21,7 @@ import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; 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 ad669099284f..e76112366e9e 100644 --- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java +++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java @@ -30,7 +30,7 @@ import android.widget.TextView; 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 14810d9baf02..c4ecb393751c 100644 --- a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java +++ b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java @@ -35,9 +35,9 @@ import android.widget.LinearLayout; 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 12dd8f06de17..4c16d41c8672 100644 --- a/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java +++ b/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java @@ -16,6 +16,7 @@ package com.android.systemui; 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.LayoutInflater; 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 @@ public class AutoReinflateContainer extends FrameLayout implements } @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 @@ public class AutoReinflateContainer extends FrameLayout implements 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 ef16a3a3c63d..aade71a83c28 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.AccessibilityController; 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.LeakDetector; 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 @@ public class Dependency { @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 @@ public class Dependency { 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 de82ca014722..c1871e09a791 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.Surface 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 a3e7d71a92f6..e72ad820c410 100644 --- a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt +++ b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt @@ -34,7 +34,7 @@ import androidx.core.graphics.ColorUtils 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 2503520ba1d9..9adfcc9a2054 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -43,8 +43,8 @@ import android.view.accessibility.AccessibilityEvent; 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 6e8275f64eea..7bfd84e4b647 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 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest 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 d6f0b59accb1..d49197557dc4 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.View; 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 0002ae95f476..2aac056b0bde 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 android.widget.TextView; 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 aeebb010eb1e..be585ed133d7 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.widget.ScrollView; 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 d0ac2968ae8e..782a10bd7e4c 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt @@ -32,7 +32,7 @@ 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 diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt index b0071340cf1a..5ede16d221b7 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.util.AttributeSet 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 ef7dcb7aac93..1dbafc6519f0 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.animation.ValueAnimator 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 ba8e60a08a1d..52db4ab8b593 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.NonNull; 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 3b50bbcd9251..eaab75af4a51 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 android.view.MotionEvent 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/udfps/EllipseOverlapDetector.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetector.kt index 9847c10abd5c..baf8d743938d 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetector.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetector.kt @@ -22,9 +22,7 @@ import android.util.Log import com.android.systemui.biometrics.EllipseOverlapDetectorParams import com.android.systemui.dagger.SysUISingleton import kotlin.math.cos -import kotlin.math.pow import kotlin.math.sin -import kotlin.math.sqrt private enum class SensorPixelPosition { OUTSIDE, // Pixel that falls outside of sensor circle @@ -42,8 +40,8 @@ private val TAG = "EllipseOverlapDetector" @SysUISingleton class EllipseOverlapDetector(private val params: EllipseOverlapDetectorParams) : OverlapDetector { override fun isGoodOverlap(touchData: NormalizedTouchData, nativeSensorBounds: Rect): Boolean { - // First, check if entire ellipse is within the sensor - if (isEllipseWithinSensor(touchData, nativeSensorBounds)) { + // First, check if touch is within bounding box, + if (nativeSensorBounds.contains(touchData.x.toInt(), touchData.y.toInt())) { return true } @@ -119,28 +117,4 @@ class EllipseOverlapDetector(private val params: EllipseOverlapDetectorParams) : return result <= 1 } - - /** Returns whether the entire ellipse is contained within the sensor area */ - private fun isEllipseWithinSensor( - touchData: NormalizedTouchData, - nativeSensorBounds: Rect - ): Boolean { - val a2 = (touchData.minor / 2.0).pow(2.0) - val b2 = (touchData.major / 2.0).pow(2.0) - - val sin2a = sin(touchData.orientation.toDouble()).pow(2.0) - val cos2a = cos(touchData.orientation.toDouble()).pow(2.0) - - val cx = sqrt(a2 * cos2a + b2 * sin2a) - val cy = sqrt(a2 * sin2a + b2 * cos2a) - - val ellipseRect = - Rect( - (-cx + touchData.x).toInt(), - (-cy + touchData.y).toInt(), - (cx + touchData.x).toInt(), - (cy + touchData.y).toInt() - ) - return nativeSensorBounds.contains(ellipseRect) - } } 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 e2d36dc6abe1..9292bd7ecd60 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.ImageView 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 11ef749573b7..7bf8f4dac1fb 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.FrameLayout; 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 1fa9ac574c7e..1ffbe3230bda 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 @@ public class EditTextActivity extends Activity } 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 8d0edf829416..b447d66c08dd 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.Lifecycle 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 6a9aaf865251..e6361f46c8ad 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.ColorInt 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 fa36eee7c644..1461135d3d3b 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.ViewGroup 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 0be3bb69d136..0dcba50df4ca 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.PackageManager; 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.Main; 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 @@ public class FrameworkServicesModule { @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 5b56c04ae8aa..83f39b522f09 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 android.view.animation.Interpolator 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 15a32d21213f..c22019e96d74 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 android.view.ViewGroup; 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 5bbfbda82944..3ef19b760826 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 @@ import javax.inject.Inject; * {@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 05153b6932b6..2ecb0a0043a2 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 @@ object Flags { // 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 d3b6fc237084..5189944e908b 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.Lifecycle; 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.MultiListLayout.MultiListAdapter; 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 2d1b7ae610c0..9844ca02482b 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 androidx.core.math.MathUtils 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 @@ class KeyguardUnlockAnimationController @Inject constructor( // 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 7a2013e2c612..99a9bed5a2bb 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.NonNull; 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.Dumpable; 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 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, } 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 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, } 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 e6568f20bc20..cde67f979132 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 c2d139c21074..7e9cbc1a9772 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 86f65dde4031..aca40195dbcf 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 3beac0b1322e..fc7bfb4e45f4 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 b5bcd45f03dd..39c630b1fa6f 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 87f3164b33d2..0505d37262b0 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 1fbfff95ab7e..944adbab3906 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 94961cbf4240..d4af38185f0f 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 38b9d508f81c..9d7477c13be6 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 d96609c24dbd..c8d37a165a0e 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.isVisible 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 9aecb5db0209..85fb5655899f 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.dagger.qualifiers.Main 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 @@ constructor( private val clockController: ClockEventController, private val clockRegistry: ClockRegistry, private val broadcastDispatcher: BroadcastDispatcher, + private val lockscreenSmartspaceController: LockscreenSmartspaceController, @Assisted bundle: Bundle, ) { @@ -67,7 +69,7 @@ constructor( 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 @@ constructor( 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 @@ constructor( bottomAreaViewModel.enablePreviewMode( initiallySelectedSlotId = bundle.getString( - KeyguardQuickAffordancePreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID, + KeyguardPreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID, ), shouldHighlightSelectedAffordance = shouldHighlightSelectedAffordance, ) @@ -108,9 +111,10 @@ constructor( val rootView = FrameLayout(context) setUpBottomArea(rootView) - if (!shouldHideClock) { - setUpClock(rootView) - } + + setupSmartspace(rootView) + + setUpClock(rootView) rootView.measure( View.MeasureSpec.makeMeasureSpec( @@ -147,9 +151,62 @@ constructor( 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 @@ constructor( 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 6d958824f78c..3869b23900d1 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.SysUISingleton 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 @@ constructor( } 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 8d6545a49a8a..2c9a9b3271e6 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 f16827d4a54a..c1357863f3a5 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 bc9dc4f69102..c6187dde035b 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 a60665a81f0e..d3ea89ce1935 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 ddce516a0fb2..6845c55b8385 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 df93d235245c..68810f909016 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 37d956bd09eb..e38abc2228c4 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.animation.ObjectAnimator 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 3669493f4e41..b46ebb22ff05 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.AttributeSet 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 dd5c2bf497cb..937a618df68f 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.graphics.drawable.Drawable 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 ab394428ad8d..0aa434976ce7 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 @@ constructor( } } + /** Whether the media card currently has the "expanded" layout */ @VisibleForTesting var currentlyExpanded = true set(value) { @@ -501,6 +502,7 @@ constructor( 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 40027a1d8f2c..f9d3094d6f00 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.Nullable; 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.ActivityIntentHelper; 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 54237ce7cf25..fe8ebafdf9b4 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.View 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 @@ constructor( if (value && (isLockScreenShadeVisibleToUser() || isHomeScreenShadeVisibleToUser())) { mediaCarouselController.logSmartspaceImpression(value) } - mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser() + updateUserVisibility() } /** @@ -460,8 +460,7 @@ constructor( ) { mediaCarouselController.logSmartspaceImpression(qsExpanded) } - mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = - isVisibleToUser() + updateUserVisibility() } override fun onDozeAmountChanged(linear: Float, eased: Float) { @@ -480,8 +479,7 @@ constructor( qsExpanded = false closeGuts() } - mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = - isVisibleToUser() + updateUserVisibility() } override fun onExpandedChanged(isExpanded: Boolean) { @@ -489,8 +487,7 @@ constructor( if (isHomeScreenShadeVisibleToUser()) { mediaCarouselController.logSmartspaceImpression(qsExpanded) } - mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = - isVisibleToUser() + updateUserVisibility() } } ) @@ -532,9 +529,7 @@ constructor( } ) - mediaCarouselController.updateUserVisibility = { - mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser() - } + mediaCarouselController.updateUserVisibility = this::updateUserVisibility mediaCarouselController.updateHostVisibility = { mediaHosts.forEach { it?.updateViewVisibility() } } @@ -1180,11 +1175,15 @@ constructor( 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 e9b2cf2b18d1..583c626d2156 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.lerp 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 78082c3eb3c6..77ff0362851a 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_ASSERTIVE 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 eadcb93a7f94..1be8b70c1d42 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.annotation.UserIdInt 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 @@ constructor( 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 64f97f2faacc..2d75359bf835 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 @@ constructor( } 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 94f01b87f936..146b5f57630e 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 android.widget.FrameLayout; 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 02180160fc11..10084bd4ccad 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.animation.ValueAnimator; 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 b9ef916eebdf..41e3e6d83eea 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.EdgeBackGestureHandlerProto; 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 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack 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 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack 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 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack 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 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack WindowManager windowManager, IWindowManager windowManagerService, Optional<Pip> pipOptional, + Optional<DesktopMode> desktopModeOptional, FalsingManager falsingManager, Provider<NavigationBarEdgePanel> navigationBarEdgePanelProvider, Provider<BackGestureTfClassifierProvider> backGestureTfClassifierProviderProvider, @@ -372,6 +379,7 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack mWindowManager = windowManager; mWindowManagerService = windowManagerService; mPipOptional = pipOptional; + mDesktopModeOptional = desktopModeOptional; mFalsingManager = falsingManager; mNavBarEdgePanelProvider = navigationBarEdgePanelProvider; mBackGestureTfClassifierProviderProvider = backGestureTfClassifierProviderProvider; @@ -580,6 +588,9 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack mMainExecutor::execute, mOnPropertiesChangedListener); mPipOptional.ifPresent( pip -> pip.setOnIsInPipStateChangedListener(mOnIsInPipStateChangedListener)); + mDesktopModeOptional.ifPresent( + dm -> dm.addDesktopGestureExclusionRegionListener( + mDesktopCornersChangedListener, mMainExecutor)); try { mWindowManagerService.registerSystemGestureExclusionListener( @@ -802,11 +813,17 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack 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 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack 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 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack 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 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack WindowManager windowManager, IWindowManager windowManagerService, Optional<Pip> pipOptional, + Optional<DesktopMode> desktopModeOptional, FalsingManager falsingManager, Provider<NavigationBarEdgePanel> navBarEdgePanelProvider, Provider<BackGestureTfClassifierProvider> @@ -1246,6 +1266,7 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack mWindowManager = windowManager; mWindowManagerService = windowManagerService; mPipOptional = pipOptional; + mDesktopModeOptional = desktopModeOptional; mFalsingManager = falsingManager; mNavBarEdgePanelProvider = navBarEdgePanelProvider; mBackGestureTfClassifierProviderProvider = backGestureTfClassifierProviderProvider; @@ -1270,6 +1291,7 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack 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 590efbb66454..ff22398cc3be 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.FloatPropertyCompat; 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 aab898e2efcf..8aec0c61c75c 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 @@ constructor( /** @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 000000000000..26b35cc8ffd1 --- /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 1839dfd3fe32..a166393ec29c 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 @@ import dagger.multibindings.IntoMap @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/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java index a7aac5a4824d..463c79c6696a 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 android.view.View.OnLayoutChangeListener; 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 584d27f84ceb..09cc2c52ff0a 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 android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS; 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.Lifecycle; 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 b445000c467d..5850a846eed6 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 @@ constructor( 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 d28ccff1bfae..be92bd48a619 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.MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE; 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.Color; 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.accessibility.AccessibilityNodeInfo; 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.Dumpable; 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.Utils; 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 java.util.function.Consumer; import javax.inject.Inject; import javax.inject.Provider; +import kotlin.Unit; + import kotlinx.coroutines.CoroutineDispatcher; @CentralSurfacesComponent.CentralSurfacesScope @@ -410,7 +408,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump 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 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump ? 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 ef14d1cb7f63..7a79e8514510 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.WindowMetrics; 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.internal.policy.SystemBarUtils; 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 f0815e93dccd..4131e7dbc98c 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.view.WindowInsets 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/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java index 63179dac7b8c..c1ebf1236def 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 @@ package com.android.systemui.statusbar; 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 54b341f529b0..1a32d70a9745 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.ViewAnimationUtils; 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 9421524c73a7..823bb355a307 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.AttributeSet 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 faf592e47eb4..22589686520b 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.Dumpable 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 72ae16e607c8..fb88a96c38c2 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.util.Log; 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 8dc78426da7d..d37cbcc00360 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.FloatPropertyCompat 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 7eb63da38028..5c3bacc1fe1b 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 android.view.animation.PathInterpolator; 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 976924a2159d..f9d4f1a89ee2 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 androidx.annotation.VisibleForTesting 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 575f354c6620..f1e51e21a9e5 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.Context 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 572c0e0da262..3d574caf3192 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.util.MathUtils 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 77550038c94a..91c08a062b54 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 android.view.animation.Interpolator; 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 79d01b4a73fd..d6a14604ffb0 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 android.view.animation.Interpolator; 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.jank.InteractionJankMonitor.Configuration; 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 2fa27ee454e8..67ab0601cbf8 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.View; 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 bfc4e9c47db5..eddb6835318d 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.view.View 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 0446165be5fc..b09b9f42e6af 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.util.Pools; 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 c22dbf615190..785e65dd4026 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 @@ package com.android.systemui.statusbar.notification 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 c22cd1ba4bc8..5a14200677b2 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.View; 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 3fc7b132f38f..a0456985e8d9 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.graphics.ColorMatrixColorFilter; 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 fe0b28d16239..9ba219903272 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 android.view.animation.Interpolator 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 5d07cac78682..57d20246ea14 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.util.Property; 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 9f9fba437869..90eb630949fa 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.ImageView; 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 dc1627438490..16f1a45ba83f 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.animation.ValueAnimator 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 766ad88f8a55..f70d5e69afe6 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.View; 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 e468a59d4eb1..2695410c8ac4 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 android.widget.ImageView; 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.util.ContrastColorUtil; 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 b56bae12be6c..7a2bee91e972 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 android.widget.Toast; 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 5edff5f4e5d2..9dbbc5874f28 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 android.widget.FrameLayout; 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 f21db0bde59a..9bc03336c3b0 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.IMPORTANCE_UNSPECIFIED; 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 596bdc09efe4..047db2046529 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 android.widget.FrameLayout; 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 8a50f2f527fa..99a77550cc76 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_DEFAULT; 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 bafc474d7123..5a129fccff06 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.view.ViewGroup; 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 5f4c9267ee4a..d5d7f75fbaa1 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.ImageView; 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 5aaf63f8d32d..b24cec150941 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.util.AttributeSet; 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 9a777ea6230b..84fe9ef6f1ac 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 android.widget.TextView; 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 7f3381ccd38a..d73bbebe40b4 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.PropertyValuesHolder; 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 0b435fe9dcc6..9a33a9440602 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.graphics.Rect; 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 5c322d71fd59..24e8f39cb4d0 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.view.animation.Interpolator; 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.Dependency; 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 ee72943bef57..f07dd00827b0 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.animation.ValueAnimator; 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 d07da381a186..f4605be2b9c5 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.util.Property; 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 9dce332985f9..459071280a1e 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.os.SystemClock; 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 5654772695ff..2387495de69b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -1637,10 +1637,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { 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( @@ -1682,11 +1679,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { 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 90a6d0fac7ca..c1859b2ee3a2 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 static com.android.systemui.statusbar.notification.NotificationUtils.inte 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 9d30cb4c4852..61c1cc82482a 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 android.widget.TextView; 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 13566ef8c630..720eeba0fd4e 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 android.widget.TextView; 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 e835c5cebbc3..5232fb633e63 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.Animator; 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 6bf54430ab38..7bc4fc3c5e47 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.os.SystemClock; 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 cc4f901668ab..46a2457670b0 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.AttributeSet; 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 55dc18859c25..560ea8aae594 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.NonNull; 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 006a029de8e0..bef422ce3004 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 android.view.animation.Interpolator; 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 5e5317d764fe..07a6d0a5a470 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.Animation; 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 8fa803ea3a8f..cdf66526ab63 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 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 b16d16a01df8..ddb6d93e3c4e 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 dagger.Subcomponent; 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 @@ import javax.inject.Scope; * 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 @@ public interface CentralSurfacesComponent { @interface CentralSurfacesScope {} /** - * Performs initialization logic after {@link CentralSurfacesComponent} has been constructed. - */ - interface Startable { - void start(); - void stop(); - } - - /** * Creates a {@link NotificationShadeWindowView}. */ NotificationShadeWindowView getNotificationShadeWindowView(); @@ -143,11 +133,6 @@ public interface CentralSurfacesComponent { @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 7ded90f7cf25..000000000000 --- 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/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java index 453dd1bb6f81..831d40259cb5 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 android.widget.LinearLayout; 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 4dd63be47735..e1ec94fada81 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 android.view.View; 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 928e0115287d..66b52563c0a9 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.LayoutInflater; 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.KeyguardVisibilityHelper; 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 850a4b499562..363b06ab780b 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.AttributeSet; 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 403a7e8116c8..e311bad9e865 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.AnimatorSet; 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.logging.UiEventLogger; 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 16123882046c..46954b5b81ef 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 @@ package com.android.systemui.temporarydisplay.chipbar 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 e819f946a6d6..4fbbc8915c19 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 android.widget.TextView 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 64234c205617..41c6b5d8493b 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 @@ class TraceUtils { } /** - * 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 5d8029293107..db4ab7edbcf1 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 @@ package com.android.systemui.util.animation 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 77210b78832b..91078dc65477 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 android.widget.Toast; 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.settingslib.Utils; 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 e492534b3ff6..b3e7cb0c77eb 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 @@ public final class WMShell implements } 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 2c680be97e95..000000000000 --- 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 02d4ecd665fc..063757acc1a1 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 android.text.TextPaint 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 @@ private val END_PAINT = TextPaint(PAINT).apply { @RunWith(AndroidTestingRunner::class) @SmallTest class TextInterpolatorTest : SysuiTestCase() { + lateinit var typefaceCache: TypefaceVariantCache private fun makeLayout( text: String, @@ -75,11 +77,16 @@ class TextInterpolatorTest : SysuiTestCase() { .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 @@ class TextInterpolatorTest : SysuiTestCase() { 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 @@ class TextInterpolatorTest : SysuiTestCase() { 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 @@ class TextInterpolatorTest : SysuiTestCase() { 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 @@ class TextInterpolatorTest : SysuiTestCase() { 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 @@ class TextInterpolatorTest : SysuiTestCase() { 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 @@ class TextInterpolatorTest : SysuiTestCase() { 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 @@ class TextInterpolatorTest : SysuiTestCase() { 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 @@ class TextInterpolatorTest : SysuiTestCase() { 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 @@ class TextInterpolatorTest : SysuiTestCase() { 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 @@ class TextInterpolatorTest : SysuiTestCase() { 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 6ab54a374d30..da9ceb47446a 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.After 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/udfps/EllipseOverlapDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetectorTest.kt index 4b41537208da..fb3c1854e996 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetectorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetectorTest.kt @@ -61,7 +61,7 @@ class EllipseOverlapDetectorTest(val testCase: TestCase) : SysuiTestCase() { @JvmStatic fun data(): List<TestCase> = listOf( - genTestCases( + genPositiveTestCases( innerXs = listOf(SENSOR.left, SENSOR.right, SENSOR.centerX()), innerYs = listOf(SENSOR.top, SENSOR.bottom, SENSOR.centerY()), outerXs = listOf(SENSOR.left - 1, SENSOR.right + 1), @@ -70,9 +70,7 @@ class EllipseOverlapDetectorTest(val testCase: TestCase) : SysuiTestCase() { major = 300f, expected = true ), - genTestCases( - innerXs = listOf(SENSOR.left, SENSOR.right), - innerYs = listOf(SENSOR.top, SENSOR.bottom), + genNegativeTestCase( outerXs = listOf(SENSOR.left - 1, SENSOR.right + 1), outerYs = listOf(SENSOR.top - 1, SENSOR.bottom + 1), minor = 100f, @@ -107,7 +105,7 @@ private val TOUCH_DATA = private val SENSOR = Rect(100 /* left */, 200 /* top */, 300 /* right */, 400 /* bottom */) -private fun genTestCases( +private fun genPositiveTestCases( innerXs: List<Int>, innerYs: List<Int>, outerXs: List<Int>, @@ -122,3 +120,15 @@ private fun genTestCases( } } } + +private fun genNegativeTestCase( + outerXs: List<Int>, + outerYs: List<Int>, + minor: Float, + major: Float, + expected: Boolean +): List<EllipseOverlapDetectorTest.TestCase> { + return outerXs.flatMap { x -> + outerYs.map { y -> EllipseOverlapDetectorTest.TestCase(x, y, minor, major, expected) } + } +} 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 58eb7d4f3ea7..e1c54976d734 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 @@ package com.android.systemui.dreams.conditions; 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.verify; 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 @@ public class DreamConditionTest extends SysuiTestCase { @Mock DreamManager mDreamManager; + @Mock + KeyguardUpdateMonitor mKeyguardUpdateMonitor; + @Before public void setup() { MockitoAnnotations.initMocks(this); @@ -66,7 +68,7 @@ public class DreamConditionTest extends SysuiTestCase { @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 @@ public class DreamConditionTest extends SysuiTestCase { @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 @@ public class DreamConditionTest extends SysuiTestCase { */ @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 d0bfaa9bedc9..5afc4059357c 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 android.util.Log.TerribleFailureHandler 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 a5b78b74fcdf..3efe38295f3d 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 a72634bcb807..1a00ac2722fe 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 @@ class MediaCarouselControllerTest : SysuiTestCase() { 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 @@ class MediaCarouselControllerTest : SysuiTestCase() { 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 @@ class MediaCarouselControllerTest : SysuiTestCase() { // 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 eb78ded008b2..2ce236d4ba89 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 @@ class MediaHierarchyManagerTest : SysuiTestCase() { ) } + @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 7dc622b86b4e..55f221df1f0a 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 @@ internal class NoteTaskControllerTest : SysuiTestCase() { } } + // 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 db6fc136e651..38a666eeb410 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.junit.runner.RunWith 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 @@ class NotificationPanelUnfoldAnimationControllerTest : SysuiTestCase() { @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 @@ class NotificationPanelUnfoldAnimationControllerTest : SysuiTestCase() { 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 @@ class NotificationPanelUnfoldAnimationControllerTest : SysuiTestCase() { 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 @@ class NotificationPanelUnfoldAnimationControllerTest : SysuiTestCase() { 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 @@ class NotificationPanelUnfoldAnimationControllerTest : SysuiTestCase() { 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 068d933652ac..f870631bd72b 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 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { @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 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { 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 600fb5c2e1bc..48e0b53fc931 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.android.systemui.statusbar.StatusBarState.SHADE_LOCKED; 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 static org.mockito.Mockito.when; 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; 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 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo } @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 9fe75abddf9c..20da8a619100 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 android.widget.TextView 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 a1168f809971..f0abf2f4a24f 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.util.Property; 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/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java index 780e0c56a239..6fda56c8717a 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 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest { .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 71ac7c48d5ea..683136d7af0f 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.Before; 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 @@ import java.util.function.Consumer; @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 8cae99893496..9de7a87c8b82 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 @@ public class WMShellTest extends SysuiTestCase { @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 5b431e72e2ac..09830413bdc8 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/datatransfer/contextsync/CallMetadataSyncConnectionService.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java index 19d8b8783d81..6f99d8677646 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 @@ public class CallMetadataSyncConnectionService extends ConnectionService { * 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/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 1f80aec3d443..def2a2f150b7 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index a021174e3031..ca482dc41ce5 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 @@ public class DisplayDeviceConfig { 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 @@ public class DisplayDeviceConfig { /** 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 @@ public class DisplayDeviceConfig { 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 @@ public class DisplayDeviceConfig { other.timeMaxMillis = timeMaxMillis; other.timeMinMillis = timeMinMillis; other.transitionPoint = transitionPoint; - other.thermalStatusLimit = thermalStatusLimit; other.allowInLowPowerMode = allowInLowPowerMode; other.minimumHdrPercentOfScreen = minimumHdrPercentOfScreen; } @@ -3029,7 +3022,6 @@ public class DisplayDeviceConfig { + ", 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 f1efec04fa69..78c5f0eee492 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 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call 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 59e112ecbccb..a76f907a41f5 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 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal 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 ca208ac73290..11160a532609 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.hardware.display.BrightnessInfo; 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 @@ class HighBrightnessModeController { 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 @@ class HighBrightnessModeController { 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 @@ class HighBrightnessModeController { 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 @@ class HighBrightnessModeController { void stop() { registerHdrListener(null /*displayToken*/); - mSkinThermalStatusObserver.stopObserving(); mSettingsObserver.stopObserving(); } @@ -278,15 +268,10 @@ class HighBrightnessModeController { 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 @@ class HighBrightnessModeController { 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 @@ class HighBrightnessModeController { } lastStartTime = dumpHbmEvent(pw, event); } - - mSkinThermalStatusObserver.dump(pw); } private long dumpHbmEvent(PrintWriter pw, HbmEvent event) { @@ -367,7 +349,7 @@ class HighBrightnessModeController { // See {@link #getHdrBrightnessValue}. return !mIsHdrLayerPresent && (mIsAutoBrightnessEnabled && mIsTimeAvailable && mIsInAllowedAmbientRange - && mIsThermalStatusWithinLimit && !mIsBlockedByLowPowerMode); + && !mIsBlockedByLowPowerMode); } private boolean deviceSupportsHbm() { @@ -469,7 +451,6 @@ class HighBrightnessModeController { + ", isAutoBrightnessEnabled: " + mIsAutoBrightnessEnabled + ", mIsTimeAvailable: " + mIsTimeAvailable + ", mIsInAllowedAmbientRange: " + mIsInAllowedAmbientRange - + ", mIsThermalStatusWithinLimit: " + mIsThermalStatusWithinLimit + ", mIsBlockedByLowPowerMode: " + mIsBlockedByLowPowerMode + ", mBrightness: " + mBrightness + ", mUnthrottledBrightness: " + mUnthrottledBrightness @@ -499,13 +480,12 @@ class HighBrightnessModeController { } 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 @@ class HighBrightnessModeController { 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 @@ class HighBrightnessModeController { 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 @@ class HighBrightnessModeController { 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 @@ class HighBrightnessModeController { } } - 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 @@ class HighBrightnessModeController { 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 dab00d8070d4..0b6d1c851dc4 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 @@ final class LogicalDisplay { */ 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 @@ final class LogicalDisplay { */ 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 @@ final class LogicalDisplay { mBaseDisplayInfo.removeMode = Display.REMOVE_MODE_DESTROY_CONTENT; } + mBaseDisplayInfo.layoutLimitedRefreshRate = mLayoutLimitedRefreshRate; + mBaseDisplayInfo.thermalRefreshRateThrottling = mThermalRefreshRateThrottling; + mPrimaryDisplayDeviceInfo = deviceInfo; mInfo.set(null); mDirty = false; @@ -952,6 +968,8 @@ final class LogicalDisplay { 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 01892945ed17..06b7698e9df2 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.R; 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 class DisplayModeDirector { 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 @@ public class DisplayModeDirector { @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 class DisplayModeDirector { 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 @@ public class DisplayModeDirector { @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 @@ public class DisplayModeDirector { } 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 class DisplayModeDirector { } 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 @@ public class DisplayModeDirector { 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 @@ public class DisplayModeDirector { } 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 @@ public class DisplayModeDirector { 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 @@ public class DisplayModeDirector { } 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 @@ public class DisplayModeDirector { @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 @@ public class DisplayModeDirector { 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 @@ public class DisplayModeDirector { } 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 @@ public class DisplayModeDirector { } @Override - public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, + public void registerSmoothDisplayObserver(@NonNull ContentResolver cr, + @NonNull ContentObserver observer) { + cr.registerContentObserver(SMOOTH_DISPLAY_URI, false /*notifyDescendants*/, + observer, UserHandle.USER_SYSTEM); + } + + @Override + public void registerForcePeakRefreshRateObserver(@NonNull ContentResolver cr, @NonNull ContentObserver observer) { - cr.registerContentObserver(PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/, + 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 @@ public class DisplayModeDirector { @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 c04735d8f7e2..8a3b329211cf 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 @@ final class SkinThermalStatusObserver extends IThermalEventListener.Stub impleme 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 @@ final class SkinThermalStatusObserver extends IThermalEventListener.Stub impleme 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 de10b1b19a33..6d70d21e3b84 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 @@ final class DreamController { if (!mCurrentDream.mIsPreviewMode && !mSentStartBroadcast) { mContext.sendBroadcastAsUser(mDreamingStartedIntent, UserHandle.ALL, null /* receiverPermission */, mDreamingStartedStoppedOptions); + mListener.onDreamStarted(mCurrentDream.mToken); mSentStartBroadcast = true; } } @@ -353,6 +354,7 @@ final class DreamController { * 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 0e26d4661017..d2dcc508d01f 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.ArrayList; 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 @@ public final class DreamManagerService extends SystemService { } 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 @@ public final class DreamManagerService extends SystemService { 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/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index f733199d9967..2460ce56f165 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.PackageManager; 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.text.format.DateUtils; 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 @@ public class PreferencesHelper implements RankingConfig { 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 @@ public class PreferencesHelper implements RankingConfig { 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 064be7c5ddc7..39cd88810961 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 @@ public final class DexOptHelper { 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 eea6720d6cc4..ef7d41309e85 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_FIXED; 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 @@ class PackageManagerShellCommand extends ShellCommand { 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 d62d53ec8495..0532a79fa8ef 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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); @@ -4785,21 +4779,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; - 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 646dc4e98c39..495e239d4cd7 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.IBinder; 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.IKeyguardDismissCallback; 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 @@ public class KeyguardServiceDelegate { 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 @@ public class KeyguardServiceDelegate { } 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 d844c6f17a5d..9647a620b6c8 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 @@ public interface ActivityInterceptorCallback { 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 @@ public interface ActivityInterceptorCallback { 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 f93afe81f804..ea0731ae346a 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 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } + @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 0ae9c4c41972..e8e4792690be 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 @@ class TransitionController { 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 @@ class TransitionController { 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 85c601fe0a5c..dbd9e4b8ea68 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 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio 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 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio 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 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } 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 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio 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 a29959297dc7..f3b338294393 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP 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/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd index 981844cf9338..f96ca582c28f 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 8cb483770c85..ad6434e0c545 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 @@ package com.android.server.display.config { 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 @@ package com.android.server.display.config { 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/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java index c07f06b332fb..50e5163cea55 100644 --- a/services/credentials/java/com/android/server/credentials/MetricUtilities.java +++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java @@ -178,9 +178,11 @@ public class MetricUtilities { * * @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; @@ -200,6 +202,7 @@ public class MetricUtilities { 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 @@ -225,7 +228,7 @@ public class MetricUtilities { candidateActionEntryCountList[index] = metric.getActionEntryCount(); candidateAuthEntryCountList[index] = metric.getAuthenticationEntryCount(); candidateRemoteEntryCountList[index] = metric.getRemoteEntryCount(); - // frameworkExceptionList[index] = metric.getFrameworkException(); + frameworkExceptionList[index] = metric.getFrameworkException(); index++; } FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_CANDIDATE_PHASE_REPORTED, @@ -246,11 +249,16 @@ public class MetricUtilities { /* 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); diff --git a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java index 9ec0ecd93b3c..8af6b56f881d 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 final class ProviderClearSession extends ProviderSession<ClearCredentialS 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 09433dbb0c52..520b937d24c5 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 @@ public final class ProviderCreateSession extends ProviderSession< 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 0c2b5633d501..a62d9e805a93 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 final class ProviderGetSession extends ProviderSession<BeginGetCredential 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 ce84d9af8c14..b99f28d07f75 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 @@ CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_IS_ENABLED_CREDENT ); ApiName(int innerMetricCode) { - this.mInnerMetricCode = innerMetricCode; + mInnerMetricCode = innerMetricCode; } /** @@ -66,7 +66,7 @@ CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_IS_ENABLED_CREDENT * @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 4097765b8736..ece729fe5b32 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 @@ public enum ApiStatus { private final int mInnerMetricCode; ApiStatus(int innerMetricCode) { - this.mInnerMetricCode = innerMetricCode; + mInnerMetricCode = innerMetricCode; } /** @@ -41,6 +41,6 @@ public enum ApiStatus { * @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 10d4f9c7590e..721d3d782653 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 @@ public class CandidatePhaseMetric { 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 @@ public class CandidatePhaseMetric { /* -- 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 @@ public class CandidatePhaseMetric { * 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 @@ public class CandidatePhaseMetric { * @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 @@ public class CandidatePhaseMetric { * collector */ public void addEntry(EntryEnum e) { - this.mAvailableEntries.add(e.getMetricCode()); + mAvailableEntries.add(e.getMetricCode()); } /** @@ -267,4 +269,14 @@ public class CandidatePhaseMetric { 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 2eef19732723..c80cc24fa455 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 class ChosenProviderFinalPhaseMetric { } public int getUiPhaseLatencyMicroseconds() { - return (int) ((this.mUiCallEndTimeNanoseconds - - this.mUiCallStartTimeNanoseconds) / 1000); + return (int) ((mUiCallEndTimeNanoseconds + - mUiCallStartTimeNanoseconds) / 1000); } /** @@ -147,8 +147,8 @@ public class ChosenProviderFinalPhaseMetric { * 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 @@ public class ChosenProviderFinalPhaseMetric { * 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 class ChosenProviderFinalPhaseMetric { } 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 @@ public class ChosenProviderFinalPhaseMetric { * @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 @@ public class ChosenProviderFinalPhaseMetric { * 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 @@ public class ChosenProviderFinalPhaseMetric { * 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 80f9fdc85a7a..b9125ddf1145 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 @@ public enum EntryEnum { ); EntryEnum(int innerMetricCode) { - this.mInnerMetricCode = innerMetricCode; + mInnerMetricCode = innerMetricCode; } /** @@ -65,7 +65,7 @@ public enum EntryEnum { * @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/ProviderSessionMetric.java b/services/credentials/java/com/android/server/credentials/metrics/ProviderSessionMetric.java index 76fd4786f9ee..9a88255ce973 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 @@ public class ProviderSessionMetric { } /** + * 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 a12a6942a5c2..b1e6a4c78fb0 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 @@ public enum ProviderStatusForMetrics { private final int mInnerMetricCode; ProviderStatusForMetrics(int innerMetricCode) { - this.mInnerMetricCode = innerMetricCode; + mInnerMetricCode = innerMetricCode; } /** @@ -47,6 +47,6 @@ public enum ProviderStatusForMetrics { * @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 18e04df9416a..547c09a625f6 100644 --- a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java +++ b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java @@ -324,7 +324,7 @@ public class RequestSessionMetric { */ 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 4d739d2c3685..f6bc93ab2491 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * 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 000000000000..17fba9f43707 --- /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/companion/datatransfer/contextsync/CallMetadataSyncConnectionServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionServiceTest.java index 3ed95eb3c878..bacf2568d9ca 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 @@ public class CallMetadataSyncConnectionServiceTest { @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 16aadacb5af6..d85db64b74cd 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 @@ public class DevicePolicyManagerTest extends DpmTestBase { 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 @@ public class DevicePolicyManagerTest extends DpmTestBase { 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 3b10db4dceb8..e2a66f03f5ca 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.DisplayDeviceConfig.HDR_PERCENT_OF_SCRE 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 static org.mockito.Mockito.when; 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.Before; 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 @@ public class HighBrightnessModeControllerTest { 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 @@ public class HighBrightnessModeControllerTest { @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 @@ public class HighBrightnessModeControllerTest { 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 @@ public class HighBrightnessModeControllerTest { } @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(); - - // 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); + // Disabled thermal throttling + hbmc.onBrightnessChanged(/*brightness=*/ 1f, /*unthrottledBrightness*/ 1f, + BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE); - 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 @@ public class HighBrightnessModeControllerTest { 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 @@ public class HighBrightnessModeControllerTest { 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 @@ public class HighBrightnessModeControllerTest { 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 @@ public class HighBrightnessModeControllerTest { 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 ff89be75c5d4..5ea30298890f 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 static org.mockito.Mockito.when; 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 @@ public class LogicalDisplayTest { 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 @@ public class LogicalDisplayTest { 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 @@ public class LogicalDisplayTest { } @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 6907145542cc..4cfcee5005b4 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 androidx.test.filters.SmallTest; 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 @@ public class DisplayModeDirectorTest { 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 @@ public class DisplayModeDirectorTest { LocalServices.addService(SensorManagerInternal.class, mSensorManagerInternalMock); LocalServices.removeServiceForTest(DisplayManagerInternal.class); LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock); + + clearSmoothDisplaySetting(); + clearForcePeakRefreshRateSetting(); } private DisplayModeDirector createDirectorFromRefreshRateArray( @@ -919,7 +924,6 @@ public class DisplayModeDirectorTest { 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 @@ public class DisplayModeDirectorTest { 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 class DisplayModeDirectorTest { 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 @@ public class DisplayModeDirectorTest { 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 @@ public class DisplayModeDirectorTest { } @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 @@ public class DisplayModeDirectorTest { 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 @@ public class DisplayModeDirectorTest { 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 @@ public class DisplayModeDirectorTest { 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 class DisplayModeDirectorTest { 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 @@ public class DisplayModeDirectorTest { } @Override - public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, + public void registerSmoothDisplayObserver(@NonNull ContentResolver cr, + @NonNull ContentObserver observer) { + mSmoothDisplaySettingObserver = observer; + } + + @Override + public void registerForcePeakRefreshRateObserver(@NonNull ContentResolver cr, @NonNull ContentObserver observer) { - mPeakRefreshRateObserver = 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 @@ public class DisplayModeDirectorTest { } 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 fd1889ca0982..13540d60b930 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 class SkinThermalStatusObserverTest { 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 1ef11974292b..d5ad815d3cdb 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.mock; 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 @@ public class DreamControllerTest { private DreamController.Listener mListener; @Mock private Context mContext; + + @Mock + private ActivityTaskManager mActivityTaskManager; + @Mock private IBinder mIBinder; @Mock @@ -80,6 +85,10 @@ public class DreamControllerTest { 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 @@ public class DreamControllerTest { } @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 94f52bbc6021..5dbc6ab4a6d0 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_HIGH; import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.IMPORTANCE_MAX; import static android.app.NotificationManager.IMPORTANCE_NONE; -import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS; import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; @@ -5312,7 +5311,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { parser.setInput(new BufferedInputStream( new ByteArrayInputStream(baos.toByteArray())), null); NotificationChannel restored = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT); - restored.populateFromXmlForRestore(parser, getContext()); + restored.populateFromXmlForRestore(parser, true, getContext()); assertNull(restored.getSound()); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index f6d10b9f371c..c78b03e4b5cb 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.BufferedInputStream; 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 @@ public class PreferencesHelperTest extends UiServiceTestCase { 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 @@ public class PreferencesHelperTest extends UiServiceTestCase { 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 @@ public class PreferencesHelperTest extends UiServiceTestCase { 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 @@ public class PreferencesHelperTest extends UiServiceTestCase { } @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 7abae1854025..f27c23b29d67 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -7640,6 +7640,25 @@ public class CarrierConfigManager { 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 @@ public class CarrierConfigManager { 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 @@ public class CarrierConfigManager { 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 e5e8f0a41048..6c069d4ee843 100644 --- a/telephony/java/android/telephony/UiccCardInfo.java +++ b/telephony/java/android/telephony/UiccCardInfo.java @@ -166,7 +166,7 @@ public final class UiccCardInfo implements Parcelable { + " 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 1863a03b58fe..dda73497e647 100644 --- a/telephony/java/android/telephony/UiccSlotInfo.java +++ b/telephony/java/android/telephony/UiccSlotInfo.java @@ -139,14 +139,16 @@ public class UiccSlotInfo implements Parcelable { 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 @@ public class UiccSlotInfo implements Parcelable { 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 @@ public class UiccSlotInfo implements Parcelable { 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 a72c12dcb463..c5a21a80d8d0 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 @@ open class PipAppHelper(instrumentation: Instrumentation) : 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 */ |