diff options
259 files changed, 3433 insertions, 1687 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/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/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 30fd77ca467c..de66f050c007 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -3554,6 +3554,18 @@ public class PackageInstaller { } /** + * @return the path to the validated base APK for this session, which may point at an + * APK inside the session (when the session defines the base), or it may + * point at the existing base APK (when adding splits to an existing app). + * + * @hide + */ + @RequiresPermission(Manifest.permission.READ_INSTALLED_SESSION_PATHS) + public @Nullable String getResolvedBaseApkPath() { + return resolvedBaseCodePath; + } + + /** * Get the value set in {@link SessionParams#setGrantedRuntimePermissions(String[])}. * * @hide 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/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..31220b438ac4 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 --> @@ -5418,6 +5418,15 @@ <permission android:name="android.permission.INSTALL_DPC_PACKAGES" android:protectionLevel="signature|role" /> + <!-- Allows an application to read resolved paths to the APKs (Base and any splits) + of a session based install. + <p>Not for use by third-party applications. + @hide + --> + <permission android:name="android.permission.READ_INSTALLED_SESSION_PATHS" + android:protectionLevel="signature|installer" /> + <uses-permission android:name="android.permission.READ_INSTALLED_SESSION_PATHS" /> + <!-- Allows an application to use System Data Loaders. <p>Not for use by third-party applications. @hide 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/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 549ac5858d1d..eb2412c0d598 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -307,6 +307,12 @@ "group": "WM_DEBUG_REMOTE_ANIMATIONS", "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, + "-1828118576": { + "message": "SyncGroup %d: Started %sfor listener: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" + }, "-1824578273": { "message": "Reporting new frame to %s: %s", "level": "VERBOSE", @@ -2893,12 +2899,6 @@ "group": "WM_DEBUG_BOOT", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "550717438": { - "message": "SyncGroup %d: Started for listener: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" - }, "556758086": { "message": "Applying new update lock state '%s' for %s", "level": "DEBUG", @@ -4129,6 +4129,12 @@ "group": "WM_DEBUG_ANIM", "at": "com\/android\/server\/wm\/WindowStateAnimator.java" }, + "1820873642": { + "message": "SyncGroup %d: Unfinished dependencies: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" + }, "1822314934": { "message": "Expected target rootTask=%s to restored behind rootTask=%s but it is behind rootTask=%s", "level": "WARN", 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/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java index 88373e80240a..cb3b64c3e6cd 100644 --- a/graphics/java/android/graphics/ImageFormat.java +++ b/graphics/java/android/graphics/ImageFormat.java @@ -261,8 +261,9 @@ public class ImageFormat { /** * Compressed JPEG format that includes an embedded recovery map. * - * <p>JPEG compressed main image along with XMP embedded recovery map - * following ISO TBD.</p> + * <p>JPEG compressed main image along with embedded recovery map following the + * <a href="https://developer.android.com/guide/topics/media/hdr-image-format">Ultra HDR + * Image format specification</a>.</p> */ public static final int JPEG_R = 0x1005; 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 859ad287e130..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 @@ -591,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)); 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 ceef373182fa..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 @@ -2419,12 +2419,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } } - // If the size of dismissStages > 0, the task is closed without prepare pending + // 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() > 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(); 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 619e963aaea6..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,17 +17,12 @@ 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; @@ -39,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; @@ -90,6 +80,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private AdditionalWindow mHandleMenuAppInfoPill; private AdditionalWindow mHandleMenuWindowingPill; private AdditionalWindow mHandleMenuMoreActionsPill; + private HandleMenu mHandleMenu; private Drawable mAppIcon; private CharSequence mAppName; @@ -122,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 @@ -197,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; @@ -297,7 +253,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } boolean isHandleMenuActive() { - return mHandleMenuAppInfoPill != null; + return mHandleMenu != null; } private void loadAppInfo() { @@ -327,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(); } /** @@ -464,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 @@ -488,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 @@ -501,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(); } } @@ -573,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); } } @@ -591,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; } 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/media/java/android/media/soundtrigger/TEST_MAPPING b/media/java/android/media/soundtrigger/TEST_MAPPING new file mode 100644 index 000000000000..3d7379501718 --- /dev/null +++ b/media/java/android/media/soundtrigger/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "CtsSoundTriggerTestCases" + } + ] +} diff --git a/packages/PackageInstaller/Android.bp b/packages/PackageInstaller/Android.bp index fd982f5df2d0..6ecd3280a0e7 100644 --- a/packages/PackageInstaller/Android.bp +++ b/packages/PackageInstaller/Android.bp @@ -39,8 +39,7 @@ android_app { certificate: "platform", privileged: true, - platform_apis: false, - sdk_version: "system_current", + platform_apis: true, rename_resources_package: false, static_libs: [ "xz-java", @@ -57,8 +56,7 @@ android_app { certificate: "platform", privileged: true, - platform_apis: false, - sdk_version: "system_current", + platform_apis: true, rename_resources_package: false, overrides: ["PackageInstaller"], @@ -77,8 +75,7 @@ android_app { certificate: "platform", privileged: true, - platform_apis: false, - sdk_version: "system_current", + platform_apis: true, rename_resources_package: false, overrides: ["PackageInstaller"], diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml index 9ee6fbde60a6..6ccebfd076cd 100644 --- a/packages/PackageInstaller/AndroidManifest.xml +++ b/packages/PackageInstaller/AndroidManifest.xml @@ -9,6 +9,7 @@ <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.DELETE_PACKAGES" /> <uses-permission android:name="android.permission.READ_INSTALL_SESSIONS" /> + <uses-permission android:name="android.permission.READ_INSTALLED_SESSION_PATHS" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS" /> <uses-permission android:name="android.permission.USE_RESERVED_DISK" /> diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java index c81e75bbab7a..3ba2acb113d3 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java @@ -375,16 +375,15 @@ public class PackageInstallerActivity extends AlertActivity { final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1 /* defaultValue */); final SessionInfo info = mInstaller.getSessionInfo(sessionId); - final String resolvedBaseCodePath = intent.getStringExtra( - PackageInstaller.EXTRA_RESOLVED_BASE_PATH); - if (info == null || !info.isSealed() || resolvedBaseCodePath == null) { + String resolvedPath = info.getResolvedBaseApkPath(); + if (info == null || !info.isSealed() || resolvedPath == null) { Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring"); finish(); return; } mSessionId = sessionId; - packageSource = Uri.fromFile(new File(resolvedBaseCodePath)); + packageSource = Uri.fromFile(new File(resolvedPath)); mOriginatingURI = null; mReferrerURI = null; mPendingUserActionReason = info.getPendingUserActionReason(); 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/res/drawable/keyguard_settings_popup_menu_background.xml b/packages/SystemUI/res/drawable/keyguard_settings_popup_menu_background.xml index a0ceb81d42f4..fe76ba7e5b8c 100644 --- a/packages/SystemUI/res/drawable/keyguard_settings_popup_menu_background.xml +++ b/packages/SystemUI/res/drawable/keyguard_settings_popup_menu_background.xml @@ -26,7 +26,7 @@ </item> <item> <shape android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorOnBackground" /> + <solid android:color="?androidprv:attr/materialColorSecondaryFixed" /> <corners android:radius="@dimen/keyguard_affordance_fixed_radius" /> </shape> </item> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 9cb8aa0142bf..a2eba81155c7 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -389,7 +389,7 @@ <dimen name="navigation_key_width">70dp</dimen> <!-- The width/height of the icon of a navigation button --> - <dimen name="navigation_icon_size">32dp</dimen> + <dimen name="navigation_icon_size">24dp</dimen> <!-- The padding on the side of the navigation bar. Must be greater than or equal to navigation_extra_key_width --> 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/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 0dcba50df4ca..f6435a788f87 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java @@ -278,7 +278,6 @@ public class FrameworkServicesModule { @Provides @Singleton - @Nullable static IVrManager provideIVrManager() { return IVrManager.Stub.asInterface(ServiceManager.getService(Context.VR_SERVICE)); } 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/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/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/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/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/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 006d7c82398a..29c5adaea844 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -1148,8 +1148,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { info.userId = userId; info.installerPackageName = mInstallSource.mInstallerPackageName; info.installerAttributionTag = mInstallSource.mInstallerAttributionTag; - info.resolvedBaseCodePath = (mResolvedBaseFile != null) ? - mResolvedBaseFile.getAbsolutePath() : null; + if (mContext.checkCallingOrSelfPermission( + Manifest.permission.READ_INSTALLED_SESSION_PATHS) + == PackageManager.PERMISSION_GRANTED && mResolvedBaseFile != null) { + info.resolvedBaseCodePath = mResolvedBaseFile.getAbsolutePath(); + } else { + info.resolvedBaseCodePath = null; + } info.progress = progress; info.sealed = mSealed; info.isCommitted = isCommitted(); @@ -2754,11 +2759,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { : PackageInstaller.ACTION_CONFIRM_INSTALL); intent.setPackage(mPm.getPackageInstallerPackageName()); intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); - synchronized (mLock) { - intent.putExtra(PackageInstaller.EXTRA_RESOLVED_BASE_PATH, - mResolvedBaseFile != null ? mResolvedBaseFile.getAbsolutePath() : null); - } - sendOnUserActionRequired(mContext, target, sessionId, intent); } 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/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index c6a2e0e51227..bc3a1a238c08 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -10551,8 +10551,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } @Override - boolean isSyncFinished() { - if (!super.isSyncFinished()) return false; + boolean isSyncFinished(BLASTSyncEngine.SyncGroup group) { + if (!super.isSyncFinished(group)) return false; if (mDisplayContent != null && mDisplayContent.mUnknownAppVisibilityController .isVisibilityUnknown(this)) { return false; @@ -10572,11 +10572,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } @Override - void finishSync(Transaction outMergedTransaction, boolean cancel) { + void finishSync(Transaction outMergedTransaction, BLASTSyncEngine.SyncGroup group, + boolean cancel) { // This override is just for getting metrics. allFinished needs to be checked before // finish because finish resets all the states. + final BLASTSyncEngine.SyncGroup syncGroup = getSyncGroup(); + if (syncGroup != null && group != getSyncGroup()) return; mLastAllReadyAtSync = allSyncFinished(); - super.finishSync(outMergedTransaction, cancel); + super.finishSync(outMergedTransaction, group, cancel); } @Nullable diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java index 7ecc0839fe53..778951a545fa 100644 --- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java +++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java @@ -27,7 +27,6 @@ import android.os.Handler; import android.os.Trace; import android.util.ArraySet; import android.util.Slog; -import android.util.SparseArray; import android.view.SurfaceControl; import com.android.internal.annotations.VisibleForTesting; @@ -61,6 +60,26 @@ import java.util.ArrayList; * This works primarily by setting-up state and then watching/waiting for the registered subtrees * to enter into a "finished" state (either by receiving drawn content or by disappearing). This * checks the subtrees during surface-placement. + * + * By default, all Syncs will be serialized (and it is an error to start one while another is + * active). However, a sync can be explicitly started in "parallel". This does not guarantee that + * it will run in parallel; however, it will run in parallel as long as it's watched hierarchy + * doesn't overlap with any other syncs' watched hierarchies. + * + * Currently, a sync that is started as "parallel" implicitly ignores the subtree below it's + * direct members unless those members are activities (WindowStates are considered "part of" the + * activity). This allows "stratified" parallelism where, eg, a sync that is only at Task-level + * can run in parallel with another sync that includes only the task's activities. + * + * If, at any time, a container is added to a parallel sync that *is* watched by another sync, it + * will be forced to serialize with it. This is done by adding a dependency. A sync will only + * finish if it has no active dependencies. At this point it is effectively not parallel anymore. + * + * To avoid dependency cycles, if a sync B ultimately depends on a sync A and a container is added + * to A which is watched by B, that container will, instead, be moved from B to A instead of + * creating a cyclic dependency. + * + * When syncs overlap, this will attempt to finish everything in the order they were started. */ class BLASTSyncEngine { private static final String TAG = "BLASTSyncEngine"; @@ -104,6 +123,18 @@ class BLASTSyncEngine { private SurfaceControl.Transaction mOrphanTransaction = null; private String mTraceName; + private static final ArrayList<SyncGroup> NO_DEPENDENCIES = new ArrayList<>(); + + /** + * When `true`, this SyncGroup will only wait for mRootMembers to draw; otherwise, + * it waits for the whole subtree(s) rooted at the mRootMembers. + */ + boolean mIgnoreIndirectMembers = false; + + /** List of SyncGroups that must finish before this one can. */ + @NonNull + ArrayList<SyncGroup> mDependencies = NO_DEPENDENCIES; + private SyncGroup(TransactionReadyListener listener, int id, String name) { mSyncId = id; mListener = listener; @@ -133,19 +164,43 @@ class BLASTSyncEngine { return mOrphanTransaction; } - private void tryFinish() { - if (!mReady) return; + /** + * Check if the sync-group ignores a particular container. This is used to allow syncs at + * different levels to run in parallel. The primary example is Recents while an activity + * sync is happening. + */ + boolean isIgnoring(WindowContainer wc) { + // Some heuristics to avoid unnecessary work: + // 1. For now, require an explicit acknowledgement of potential "parallelism" across + // hierarchy levels (horizontal). + if (!mIgnoreIndirectMembers) return false; + // 2. Don't check WindowStates since they are below the relevant abstraction level ( + // anything activity/token and above). + if (wc.asWindowState() != null) return false; + // Obviously, don't ignore anything that is directly part of this group. + return wc.mSyncGroup != this; + } + + /** @return `true` if it finished. */ + private boolean tryFinish() { + if (!mReady) return false; ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: onSurfacePlacement checking %s", mSyncId, mRootMembers); + if (!mDependencies.isEmpty()) { + ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Unfinished dependencies: %s", + mSyncId, mDependencies); + return false; + } for (int i = mRootMembers.size() - 1; i >= 0; --i) { final WindowContainer wc = mRootMembers.valueAt(i); - if (!wc.isSyncFinished()) { + if (!wc.isSyncFinished(this)) { ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Unfinished container: %s", mSyncId, wc); - return; + return false; } } finishNow(); + return true; } private void finishNow() { @@ -158,7 +213,7 @@ class BLASTSyncEngine { merged.merge(mOrphanTransaction); } for (WindowContainer wc : mRootMembers) { - wc.finishSync(merged, false /* cancel */); + wc.finishSync(merged, this, false /* cancel */); } final ArraySet<WindowContainer> wcAwaitingCommit = new ArraySet<>(); @@ -204,7 +259,7 @@ class BLASTSyncEngine { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "onTransactionReady"); mListener.onTransactionReady(mSyncId, merged); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); - mActiveSyncs.remove(mSyncId); + mActiveSyncs.remove(this); mHandler.removeCallbacks(mOnTimeout); // Immediately start the next pending sync-transaction if there is one. @@ -230,54 +285,115 @@ class BLASTSyncEngine { } } - private void setReady(boolean ready) { + /** returns true if readiness changed. */ + private boolean setReady(boolean ready) { if (mReady == ready) { - return; + return false; } ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Set ready %b", mSyncId, ready); mReady = ready; - if (!ready) return; - mWm.mWindowPlacerLocked.requestTraversal(); + if (ready) { + mWm.mWindowPlacerLocked.requestTraversal(); + } + return true; } private void addToSync(WindowContainer wc) { - if (!mRootMembers.add(wc)) { + if (mRootMembers.contains(wc)) { return; } ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Adding to group: %s", mSyncId, wc); - wc.setSyncGroup(this); + final SyncGroup dependency = wc.getSyncGroup(); + if (dependency != null && dependency != this && !dependency.isIgnoring(wc)) { + // This syncgroup now conflicts with another one, so the whole group now must + // wait on the other group. + Slog.w(TAG, "SyncGroup " + mSyncId + " conflicts with " + dependency.mSyncId + + ": Making " + mSyncId + " depend on " + dependency.mSyncId); + if (mDependencies.contains(dependency)) { + // nothing, it's already a dependency. + } else if (dependency.dependsOn(this)) { + Slog.w(TAG, " Detected dependency cycle between " + mSyncId + " and " + + dependency.mSyncId + ": Moving " + wc + " to " + mSyncId); + // Since dependency already depends on this, make this now `wc`'s watcher + if (wc.mSyncGroup == null) { + wc.setSyncGroup(this); + } else { + // Explicit replacement. + wc.mSyncGroup.mRootMembers.remove(wc); + mRootMembers.add(wc); + wc.mSyncGroup = this; + } + } else { + if (mDependencies == NO_DEPENDENCIES) { + mDependencies = new ArrayList<>(); + } + mDependencies.add(dependency); + } + } else { + mRootMembers.add(wc); + wc.setSyncGroup(this); + } wc.prepareSync(); if (mReady) { mWm.mWindowPlacerLocked.requestTraversal(); } } + private boolean dependsOn(SyncGroup group) { + if (mDependencies.isEmpty()) return false; + // BFS search with membership check. We don't expect cycle here (since this is + // explicitly called to avoid cycles) but just to be safe. + final ArrayList<SyncGroup> fringe = mTmpFringe; + fringe.clear(); + fringe.add(this); + for (int head = 0; head < fringe.size(); ++head) { + final SyncGroup next = fringe.get(head); + if (next == group) { + fringe.clear(); + return true; + } + for (int i = 0; i < next.mDependencies.size(); ++i) { + if (fringe.contains(next.mDependencies.get(i))) continue; + fringe.add(next.mDependencies.get(i)); + } + } + fringe.clear(); + return false; + } + void onCancelSync(WindowContainer wc) { mRootMembers.remove(wc); } private void onTimeout() { - if (!mActiveSyncs.contains(mSyncId)) return; + if (!mActiveSyncs.contains(this)) return; boolean allFinished = true; for (int i = mRootMembers.size() - 1; i >= 0; --i) { final WindowContainer<?> wc = mRootMembers.valueAt(i); - if (!wc.isSyncFinished()) { + if (!wc.isSyncFinished(this)) { allFinished = false; Slog.i(TAG, "Unfinished container: " + wc); } } + for (int i = mDependencies.size() - 1; i >= 0; --i) { + allFinished = false; + Slog.i(TAG, "Unfinished dependency: " + mDependencies.get(i).mSyncId); + } if (allFinished && !mReady) { Slog.w(TAG, "Sync group " + mSyncId + " timed-out because not ready. If you see " + "this, please file a bug."); } finishNow(); + removeFromDependencies(this); } } private final WindowManagerService mWm; private final Handler mHandler; private int mNextSyncId = 0; - private final SparseArray<SyncGroup> mActiveSyncs = new SparseArray<>(); + + /** Currently active syncs. Intentionally ordered by start time. */ + private final ArrayList<SyncGroup> mActiveSyncs = new ArrayList<>(); /** * A queue of pending sync-sets waiting for their turn to run. @@ -288,6 +404,9 @@ class BLASTSyncEngine { private final ArrayList<Runnable> mOnIdleListeners = new ArrayList<>(); + private final ArrayList<SyncGroup> mTmpFinishQueue = new ArrayList<>(); + private final ArrayList<SyncGroup> mTmpFringe = new ArrayList<>(); + BLASTSyncEngine(WindowManagerService wms) { this(wms, wms.mH); } @@ -306,32 +425,39 @@ class BLASTSyncEngine { return new SyncGroup(listener, mNextSyncId++, name); } - int startSyncSet(TransactionReadyListener listener, long timeoutMs, String name) { + int startSyncSet(TransactionReadyListener listener, long timeoutMs, String name, + boolean parallel) { final SyncGroup s = prepareSyncSet(listener, name); - startSyncSet(s, timeoutMs); + startSyncSet(s, timeoutMs, parallel); return s.mSyncId; } void startSyncSet(SyncGroup s) { - startSyncSet(s, BLAST_TIMEOUT_DURATION); + startSyncSet(s, BLAST_TIMEOUT_DURATION, false /* parallel */); } - void startSyncSet(SyncGroup s, long timeoutMs) { - if (mActiveSyncs.size() != 0) { - // We currently only support one sync at a time, so start a new SyncGroup when there is - // another may cause issue. + void startSyncSet(SyncGroup s, long timeoutMs, boolean parallel) { + final boolean alreadyRunning = mActiveSyncs.size() > 0; + if (!parallel && alreadyRunning) { + // We only support overlapping syncs when explicitly declared `parallel`. Slog.e(TAG, "SyncGroup " + s.mSyncId + ": Started when there is other active SyncGroup"); } - mActiveSyncs.put(s.mSyncId, s); - ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Started for listener: %s", - s.mSyncId, s.mListener); + mActiveSyncs.add(s); + // For now, parallel implies this. + s.mIgnoreIndirectMembers = parallel; + ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Started %sfor listener: %s", + s.mSyncId, (parallel && alreadyRunning ? "(in parallel) " : ""), s.mListener); scheduleTimeout(s, timeoutMs); } @Nullable SyncGroup getSyncSet(int id) { - return mActiveSyncs.get(id); + for (int i = 0; i < mActiveSyncs.size(); ++i) { + if (mActiveSyncs.get(i).mSyncId != id) continue; + return mActiveSyncs.get(i); + } + return null; } boolean hasActiveSync() { @@ -356,8 +482,8 @@ class BLASTSyncEngine { syncGroup.mSyncMethod = method; } - void setReady(int id, boolean ready) { - getSyncGroup(id).setReady(ready); + boolean setReady(int id, boolean ready) { + return getSyncGroup(id).setReady(ready); } void setReady(int id) { @@ -372,21 +498,68 @@ class BLASTSyncEngine { * Aborts the sync (ie. it doesn't wait for ready or anything to finish) */ void abort(int id) { - getSyncGroup(id).finishNow(); + final SyncGroup group = getSyncGroup(id); + group.finishNow(); + removeFromDependencies(group); } private SyncGroup getSyncGroup(int id) { - final SyncGroup syncGroup = mActiveSyncs.get(id); + final SyncGroup syncGroup = getSyncSet(id); if (syncGroup == null) { throw new IllegalStateException("SyncGroup is not started yet id=" + id); } return syncGroup; } + /** + * Just removes `group` from any dependency lists. Does not try to evaluate anything. However, + * it will schedule traversals if any groups were changed in a way that could make them ready. + */ + private void removeFromDependencies(SyncGroup group) { + boolean anyChange = false; + for (int i = 0; i < mActiveSyncs.size(); ++i) { + final SyncGroup active = mActiveSyncs.get(i); + if (!active.mDependencies.remove(group)) continue; + if (!active.mDependencies.isEmpty()) continue; + anyChange = true; + } + if (!anyChange) return; + mWm.mWindowPlacerLocked.requestTraversal(); + } + void onSurfacePlacement() { - // backwards since each state can remove itself if finished - for (int i = mActiveSyncs.size() - 1; i >= 0; --i) { - mActiveSyncs.valueAt(i).tryFinish(); + if (mActiveSyncs.isEmpty()) return; + // queue in-order since we want interdependent syncs to become ready in the same order they + // started in. + mTmpFinishQueue.addAll(mActiveSyncs); + // There shouldn't be any dependency cycles or duplicates, but add an upper-bound just + // in case. Assuming absolute worst case, each visit will try and revisit everything + // before it, so n + (n-1) + (n-2) ... = (n+1)*n/2 + int visitBounds = ((mActiveSyncs.size() + 1) * mActiveSyncs.size()) / 2; + while (!mTmpFinishQueue.isEmpty()) { + if (visitBounds <= 0) { + Slog.e(TAG, "Trying to finish more syncs than theoretically possible. This " + + "should never happen. Most likely a dependency cycle wasn't detected."); + } + --visitBounds; + final SyncGroup group = mTmpFinishQueue.remove(0); + final int grpIdx = mActiveSyncs.indexOf(group); + // Skip if it's already finished: + if (grpIdx < 0) continue; + if (!group.tryFinish()) continue; + // Finished, so update dependencies of any prior groups and retry if unblocked. + int insertAt = 0; + for (int i = 0; i < mActiveSyncs.size(); ++i) { + final SyncGroup active = mActiveSyncs.get(i); + if (!active.mDependencies.remove(group)) continue; + // Anything afterwards is already in queue. + if (i >= grpIdx) continue; + if (!active.mDependencies.isEmpty()) continue; + // `active` became unblocked so it can finish, since it started earlier, it should + // be checked next to maintain order. + mTmpFinishQueue.add(insertAt, mActiveSyncs.get(i)); + insertAt += 1; + } } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 76d6951c438e..f478e9bee18a 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1755,7 +1755,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } @Override - boolean isSyncFinished() { + boolean isSyncFinished(BLASTSyncEngine.SyncGroup group) { // Do not consider children because if they are requested to be synced, they should be // added to sync group explicitly. return !mRemoteDisplayChangeController.isWaitingForRemoteDisplayChange(); diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 3f7ab14d02be..c6c3b14bf98b 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -2547,8 +2547,8 @@ class TaskFragment extends WindowContainer<WindowContainer> { } @Override - boolean isSyncFinished() { - return super.isSyncFinished() && isReadyToTransit(); + boolean isSyncFinished(BLASTSyncEngine.SyncGroup group) { + return super.isSyncFinished(group) && isReadyToTransit(); } @Override diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 452bd6d7b347..b314ed17244c 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -447,7 +447,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { throw new IllegalStateException("Attempting to re-use a transition"); } mState = STATE_COLLECTING; - mSyncId = mSyncEngine.startSyncSet(this, timeoutMs, TAG); + mSyncId = mSyncEngine.startSyncSet(this, timeoutMs, TAG, false /* parallel */); mSyncEngine.setSyncMethod(mSyncId, TransitionController.SYNC_METHOD); mLogger.mSyncId = mSyncId; diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index cf6efd28acb7..f4a1765d4663 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -3835,13 +3835,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< void setSyncGroup(@NonNull BLASTSyncEngine.SyncGroup group) { ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "setSyncGroup #%d on %s", group.mSyncId, this); - if (group != null) { - if (mSyncGroup != null && mSyncGroup != group) { - // This can still happen if WMCore starts a new transition when there is ongoing - // sync transaction from Shell. Please file a bug if it happens. - throw new IllegalStateException("Can't sync on 2 engines simultaneously" - + " currentSyncId=" + mSyncGroup.mSyncId + " newSyncId=" + group.mSyncId); - } + if (mSyncGroup != null && mSyncGroup != group) { + // This can still happen if WMCore starts a new transition when there is ongoing + // sync transaction from Shell. Please file a bug if it happens. + throw new IllegalStateException("Can't sync on 2 groups simultaneously" + + " currentSyncId=" + mSyncGroup.mSyncId + " newSyncId=" + group.mSyncId); } mSyncGroup = group; } @@ -3883,12 +3881,16 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * @param cancel If true, this is being finished because it is leaving the sync group rather * than due to the sync group completing. */ - void finishSync(Transaction outMergedTransaction, boolean cancel) { + void finishSync(Transaction outMergedTransaction, BLASTSyncEngine.SyncGroup group, + boolean cancel) { if (mSyncState == SYNC_STATE_NONE) return; + final BLASTSyncEngine.SyncGroup syncGroup = getSyncGroup(); + // If it's null, then we need to clean-up anyways. + if (syncGroup != null && group != syncGroup) return; ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "finishSync cancel=%b for %s", cancel, this); outMergedTransaction.merge(mSyncTransaction); for (int i = mChildren.size() - 1; i >= 0; --i) { - mChildren.get(i).finishSync(outMergedTransaction, cancel); + mChildren.get(i).finishSync(outMergedTransaction, group, cancel); } if (cancel && mSyncGroup != null) mSyncGroup.onCancelSync(this); mSyncState = SYNC_STATE_NONE; @@ -3903,7 +3905,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * * @return {@code true} if this subtree is finished waiting for sync participants. */ - boolean isSyncFinished() { + boolean isSyncFinished(BLASTSyncEngine.SyncGroup group) { if (!isVisibleRequested()) { return true; } @@ -3917,7 +3919,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< // Loop from top-down. for (int i = mChildren.size() - 1; i >= 0; --i) { final WindowContainer child = mChildren.get(i); - final boolean childFinished = child.isSyncFinished(); + final boolean childFinished = group.isIgnoring(child) || child.isSyncFinished(group); if (childFinished && child.isVisibleRequested() && child.fillsParent()) { // Any lower children will be covered-up, so we can consider this finished. return true; @@ -3968,11 +3970,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< // This is getting removed. if (oldParent.mSyncState != SYNC_STATE_NONE) { // In order to keep the transaction in sync, merge it into the parent. - finishSync(oldParent.mSyncTransaction, true /* cancel */); + finishSync(oldParent.mSyncTransaction, getSyncGroup(), true /* cancel */); } else if (mSyncGroup != null) { // This is watched directly by the sync-group, so merge this transaction into // into the sync-group so it isn't lost - finishSync(mSyncGroup.getOrphanTransaction(), true /* cancel */); + finishSync(mSyncGroup.getOrphanTransaction(), mSyncGroup, true /* cancel */); } else { throw new IllegalStateException("This container is in sync mode without a sync" + " group: " + this); @@ -3981,7 +3983,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } else if (mSyncGroup == null) { // This is being reparented out of the sync-group. To prevent ordering issues on // this container, immediately apply/cancel sync on it. - finishSync(getPendingTransaction(), true /* cancel */); + finishSync(getPendingTransaction(), getSyncGroup(), true /* cancel */); return; } // Otherwise this is the "root" of a synced subtree, so continue on to preparation. 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..2920652674d3 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 @@ -5678,7 +5678,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } @Override - boolean isSyncFinished() { + boolean isSyncFinished(BLASTSyncEngine.SyncGroup group) { if (!isVisibleRequested() || isFullyTransparent()) { // Don't wait for invisible windows. However, we don't alter the state in case the // window becomes visible while the sync group is still active. @@ -5689,11 +5689,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // Complete the sync state immediately for a drawn window that doesn't need to redraw. onSyncFinishedDrawing(); } - return super.isSyncFinished(); + return super.isSyncFinished(group); } @Override - void finishSync(Transaction outMergedTransaction, boolean cancel) { + void finishSync(Transaction outMergedTransaction, BLASTSyncEngine.SyncGroup group, + boolean cancel) { + final BLASTSyncEngine.SyncGroup syncGroup = getSyncGroup(); + if (syncGroup != null && group != syncGroup) return; mPrepareSyncSeqId = 0; if (cancel) { // This is leaving sync so any buffers left in the sync have a chance of @@ -5701,7 +5704,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // window. To prevent this, drop the buffer. dropBufferFrom(mSyncTransaction); } - super.finishSync(outMergedTransaction, cancel); + super.finishSync(outMergedTransaction, group, cancel); } boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction, int syncSeqId) { 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/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/services/tests/voiceinteractiontests/TEST_MAPPING b/services/tests/voiceinteractiontests/TEST_MAPPING new file mode 100644 index 000000000000..6cbc49a2a7e1 --- /dev/null +++ b/services/tests/voiceinteractiontests/TEST_MAPPING @@ -0,0 +1,17 @@ +{ + "presubmit": [ + { + "name": "FrameworksVoiceInteractionTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + } + ], + "postsubmit": [ + { + "name": "FrameworksVoiceInteractionTests" + } + ] +} diff --git a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java index 77efc4b0d561..ddd630ee8635 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java @@ -48,6 +48,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; +import org.mockito.Mockito; /** * Test class for {@link BLASTSyncEngine}. @@ -225,7 +227,7 @@ public class SyncEngineTests extends WindowTestsBase { parentWC.onSyncFinishedDrawing(); topChildWC.onSyncFinishedDrawing(); // Even though bottom isn't finished, we should see callback because it is occluded by top. - assertFalse(botChildWC.isSyncFinished()); + assertFalse(botChildWC.isSyncFinished(botChildWC.getSyncGroup())); bse.onSurfacePlacement(); verify(listener, times(1)).onTransactionReady(eq(id), notNull()); @@ -416,9 +418,217 @@ public class SyncEngineTests extends WindowTestsBase { assertTrue(bse.isReady(nextId[0])); } + @Test + public void testStratifiedParallel() { + TestWindowContainer parentWC = new TestWindowContainer(mWm, true /* waiter */); + TestWindowContainer childWC = new TestWindowContainer(mWm, true /* waiter */); + parentWC.addChild(childWC, POSITION_TOP); + childWC.mVisibleRequested = true; + childWC.mFillsParent = true; + + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); + + BLASTSyncEngine.TransactionReadyListener listenerChild = mock( + BLASTSyncEngine.TransactionReadyListener.class); + BLASTSyncEngine.TransactionReadyListener listenerParent = mock( + BLASTSyncEngine.TransactionReadyListener.class); + + // Start a sync-set for the "inner" stuff + int childSync = startSyncSet(bse, listenerChild); + bse.addToSyncSet(childSync, childWC); + bse.setReady(childSync); + + // Start sync-set for the "outer" stuff but explicitly parallel (it should ignore child) + int parentSync = startSyncSet(bse, listenerParent, true /* parallel */); + bse.addToSyncSet(parentSync, parentWC); + bse.setReady(parentSync); + + bse.onSurfacePlacement(); + // Nothing should have happened yet + verify(listenerChild, times(0)).onTransactionReady(anyInt(), any()); + verify(listenerParent, times(0)).onTransactionReady(anyInt(), any()); + + // Now, make PARENT ready, since they are in parallel, this should work + parentWC.onSyncFinishedDrawing(); + bse.onSurfacePlacement(); + + // Parent should become ready while child is still waiting. + verify(listenerParent, times(1)).onTransactionReady(eq(parentSync), notNull()); + verify(listenerChild, times(0)).onTransactionReady(anyInt(), any()); + + // Child should still work + childWC.onSyncFinishedDrawing(); + bse.onSurfacePlacement(); + verify(listenerChild, times(1)).onTransactionReady(eq(childSync), notNull()); + } + + @Test + public void testDependencies() { + TestWindowContainer parentWC = new TestWindowContainer(mWm, true /* waiter */); + TestWindowContainer childWC = new TestWindowContainer(mWm, true /* waiter */); + TestWindowContainer childWC2 = new TestWindowContainer(mWm, true /* waiter */); + parentWC.addChild(childWC, POSITION_TOP); + childWC.mVisibleRequested = true; + childWC.mFillsParent = true; + childWC2.mVisibleRequested = true; + childWC2.mFillsParent = true; + + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); + + BLASTSyncEngine.TransactionReadyListener listener = mock( + BLASTSyncEngine.TransactionReadyListener.class); + + // This is non-parallel, so it is waiting on the child as-well + int sync1 = startSyncSet(bse, listener); + bse.addToSyncSet(sync1, parentWC); + bse.setReady(sync1); + + // Create one which will end-up depending on the *next* sync + int sync2 = startSyncSet(bse, listener, true /* parallel */); + + // If another sync tries to sync on the same subtree, it must now serialize with the other. + int sync3 = startSyncSet(bse, listener, true /* parallel */); + bse.addToSyncSet(sync3, childWC); + bse.addToSyncSet(sync3, childWC2); + bse.setReady(sync3); + + // This will depend on sync3. + int sync4 = startSyncSet(bse, listener, true /* parallel */); + bse.addToSyncSet(sync4, childWC2); + bse.setReady(sync4); + + // This makes sync2 depend on sync3. Since both sync2 and sync4 depend on sync3, when sync3 + // finishes, sync2 should run first since it was created first. + bse.addToSyncSet(sync2, childWC2); + bse.setReady(sync2); + + childWC.onSyncFinishedDrawing(); + childWC2.onSyncFinishedDrawing(); + bse.onSurfacePlacement(); + + // Nothing should be ready yet since everything ultimately depends on sync1. + verify(listener, times(0)).onTransactionReady(anyInt(), any()); + + parentWC.onSyncFinishedDrawing(); + bse.onSurfacePlacement(); + + // They should all be ready, now, so just verify that the order is expected + InOrder readyOrder = Mockito.inOrder(listener); + // sync1 is the first one, so it should call ready first. + readyOrder.verify(listener).onTransactionReady(eq(sync1), any()); + // everything else depends on sync3, so it should call ready next. + readyOrder.verify(listener).onTransactionReady(eq(sync3), any()); + // both sync2 and sync4 depend on sync3, but sync2 started first, so it should go next. + readyOrder.verify(listener).onTransactionReady(eq(sync2), any()); + readyOrder.verify(listener).onTransactionReady(eq(sync4), any()); + } + + @Test + public void testStratifiedParallelParentFirst() { + TestWindowContainer parentWC = new TestWindowContainer(mWm, true /* waiter */); + TestWindowContainer childWC = new TestWindowContainer(mWm, true /* waiter */); + parentWC.addChild(childWC, POSITION_TOP); + childWC.mVisibleRequested = true; + childWC.mFillsParent = true; + + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); + + BLASTSyncEngine.TransactionReadyListener listener = mock( + BLASTSyncEngine.TransactionReadyListener.class); + + // This is parallel, so it should ignore children + int sync1 = startSyncSet(bse, listener, true /* parallel */); + bse.addToSyncSet(sync1, parentWC); + bse.setReady(sync1); + + int sync2 = startSyncSet(bse, listener, true /* parallel */); + bse.addToSyncSet(sync2, childWC); + bse.setReady(sync2); + + childWC.onSyncFinishedDrawing(); + bse.onSurfacePlacement(); + + // Sync2 should have run in parallel + verify(listener, times(1)).onTransactionReady(eq(sync2), any()); + verify(listener, times(0)).onTransactionReady(eq(sync1), any()); + + parentWC.onSyncFinishedDrawing(); + bse.onSurfacePlacement(); + + verify(listener, times(1)).onTransactionReady(eq(sync1), any()); + } + + @Test + public void testDependencyCycle() { + TestWindowContainer parentWC = new TestWindowContainer(mWm, true /* waiter */); + TestWindowContainer childWC = new TestWindowContainer(mWm, true /* waiter */); + TestWindowContainer childWC2 = new TestWindowContainer(mWm, true /* waiter */); + TestWindowContainer childWC3 = new TestWindowContainer(mWm, true /* waiter */); + parentWC.addChild(childWC, POSITION_TOP); + childWC.mVisibleRequested = true; + childWC.mFillsParent = true; + childWC2.mVisibleRequested = true; + childWC2.mFillsParent = true; + childWC3.mVisibleRequested = true; + childWC3.mFillsParent = true; + + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); + + BLASTSyncEngine.TransactionReadyListener listener = mock( + BLASTSyncEngine.TransactionReadyListener.class); + + // This is non-parallel, so it is waiting on the child as-well + int sync1 = startSyncSet(bse, listener); + bse.addToSyncSet(sync1, parentWC); + bse.setReady(sync1); + + // Sync 2 depends on sync1 AND childWC2 + int sync2 = startSyncSet(bse, listener, true /* parallel */); + bse.addToSyncSet(sync2, childWC); + bse.addToSyncSet(sync2, childWC2); + bse.setReady(sync2); + + // Sync 3 depends on sync2 AND childWC3 + int sync3 = startSyncSet(bse, listener, true /* parallel */); + bse.addToSyncSet(sync3, childWC2); + bse.addToSyncSet(sync3, childWC3); + bse.setReady(sync3); + + // Now make sync1 depend on WC3 (which would make it depend on sync3). This would form + // a cycle, so it should instead move childWC3 into sync1. + bse.addToSyncSet(sync1, childWC3); + + // Sync3 should no-longer have childWC3 as a root-member since a window can currently only + // be directly watched by 1 syncgroup maximum (due to implementation of isSyncFinished). + assertFalse(bse.getSyncSet(sync3).mRootMembers.contains(childWC3)); + + childWC3.onSyncFinishedDrawing(); + childWC2.onSyncFinishedDrawing(); + parentWC.onSyncFinishedDrawing(); + bse.onSurfacePlacement(); + + // make sure sync3 hasn't run even though all its (original) members are ready + verify(listener, times(0)).onTransactionReady(anyInt(), any()); + + // Now finish the last container and make sure everything finishes (didn't "deadlock" due + // to a dependency cycle. + childWC.onSyncFinishedDrawing(); + bse.onSurfacePlacement(); + + InOrder readyOrder = Mockito.inOrder(listener); + readyOrder.verify(listener).onTransactionReady(eq(sync1), any()); + readyOrder.verify(listener).onTransactionReady(eq(sync2), any()); + readyOrder.verify(listener).onTransactionReady(eq(sync3), any()); + } + static int startSyncSet(BLASTSyncEngine engine, BLASTSyncEngine.TransactionReadyListener listener) { - return engine.startSyncSet(listener, BLAST_TIMEOUT_DURATION, "Test"); + return engine.startSyncSet(listener, BLAST_TIMEOUT_DURATION, "Test", false /* parallel */); + } + + static int startSyncSet(BLASTSyncEngine engine, + BLASTSyncEngine.TransactionReadyListener listener, boolean parallel) { + return engine.startSyncSet(listener, BLAST_TIMEOUT_DURATION, "Test", parallel); } static class TestWindowContainer extends WindowContainer { diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index 653b52b06720..0dac346bb717 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -1196,7 +1196,8 @@ public class TransitionTests extends WindowTestsBase { player.start(); player.finish(); - app.getTask().finishSync(mWm.mTransactionFactory.get(), false /* cancel */); + app.getTask().finishSync(mWm.mTransactionFactory.get(), app.getTask().getSyncGroup(), + false /* cancel */); // The open transition is finished. Continue to play seamless display change transition, // so the previous async rotation controller should still exist. diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java index 984b868ab67f..453096306694 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java @@ -394,7 +394,7 @@ public class WallpaperControllerTests extends WindowTestsBase { assertTrue(token.isVisible()); final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); - token.finishSync(t, false /* cancel */); + token.finishSync(t, token.getSyncGroup(), false /* cancel */); transit.onTransactionReady(transit.getSyncId(), t); dc.mTransitionController.finishTransition(transit); assertFalse(wallpaperWindow.isVisible()); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index d19c996ce939..600681fb332c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -1006,7 +1006,8 @@ public class WindowOrganizerTests extends WindowTestsBase { BLASTSyncEngine.TransactionReadyListener transactionListener = mock(BLASTSyncEngine.TransactionReadyListener.class); - final int id = bse.startSyncSet(transactionListener, BLAST_TIMEOUT_DURATION, "Test"); + final int id = bse.startSyncSet(transactionListener, BLAST_TIMEOUT_DURATION, "Test", + false /* parallel */); bse.addToSyncSet(id, task); bse.setReady(id); bse.onSurfacePlacement(); 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; } /** |