diff options
277 files changed, 4614 insertions, 2045 deletions
diff --git a/apct-tests/perftests/core/src/android/os/TracePerfTest.java b/apct-tests/perftests/core/src/android/os/TracePerfTest.java index d9051240d399..00e1c1fdbf4b 100644 --- a/apct-tests/perftests/core/src/android/os/TracePerfTest.java +++ b/apct-tests/perftests/core/src/android/os/TracePerfTest.java @@ -147,7 +147,7 @@ public class TracePerfTest { .addField(1 /* sending_thread_name */, "foo") .endNested() .endProto() - .addTerminatingFlow(5) + .setTerminatingFlow(5) .emit(); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); @@ -158,7 +158,7 @@ public class TracePerfTest { .addField(1 /* sending_thread_name */, "foo") .endNested() .endProto() - .addTerminatingFlow(5) + .setTerminatingFlow(5) .emit(); } } diff --git a/apct-tests/perftests/healthconnect/OWNERS b/apct-tests/perftests/healthconnect/OWNERS index acfe799314ec..7c9e7692a9fc 100644 --- a/apct-tests/perftests/healthconnect/OWNERS +++ b/apct-tests/perftests/healthconnect/OWNERS @@ -1,5 +1,4 @@ # Bug component: 1219472 -arkivanov@google.com jstembridge@google.com itsleo@google.com diff --git a/api/OWNERS b/api/OWNERS index f2bcf13d2d2e..31ffa8cd4e9f 100644 --- a/api/OWNERS +++ b/api/OWNERS @@ -1,4 +1,3 @@ -hansson@google.com # Modularization team file:platform/packages/modules/common:/OWNERS diff --git a/cmds/idmap2/OWNERS b/cmds/idmap2/OWNERS index 062ffd41348a..def9f401e51f 100644 --- a/cmds/idmap2/OWNERS +++ b/cmds/idmap2/OWNERS @@ -1,4 +1,3 @@ set noparent -toddke@google.com patb@google.com zyy@google.com diff --git a/core/api/current.txt b/core/api/current.txt index 13127537e6d9..3da5a5cca861 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -16993,7 +16993,7 @@ package android.graphics { method public void setFilterBitmap(boolean); method public void setFlags(int); method public void setFontFeatureSettings(String); - method @FlaggedApi("com.android.text.flags.typeface_redesign_readonly") public boolean setFontVariationOverride(@Nullable String); + method @FlaggedApi("com.android.text.flags.typeface_redesign_readonly") public void setFontVariationOverride(@Nullable String); method public boolean setFontVariationSettings(String); method public void setHinting(int); method public void setLetterSpacing(float); @@ -23332,12 +23332,12 @@ package android.media { public static final class MediaCodecInfo.CodecCapabilities { ctor public MediaCodecInfo.CodecCapabilities(); method public static android.media.MediaCodecInfo.CodecCapabilities createFromProfileLevel(String, int, int); - method public android.media.MediaCodecInfo.AudioCapabilities getAudioCapabilities(); + method @Nullable public android.media.MediaCodecInfo.AudioCapabilities getAudioCapabilities(); method public android.media.MediaFormat getDefaultFormat(); - method public android.media.MediaCodecInfo.EncoderCapabilities getEncoderCapabilities(); + method @Nullable public android.media.MediaCodecInfo.EncoderCapabilities getEncoderCapabilities(); method public int getMaxSupportedInstances(); method public String getMimeType(); - method public android.media.MediaCodecInfo.VideoCapabilities getVideoCapabilities(); + method @Nullable public android.media.MediaCodecInfo.VideoCapabilities getVideoCapabilities(); method public boolean isFeatureRequired(String); method public boolean isFeatureSupported(String); method public boolean isFormatSupported(android.media.MediaFormat); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 514a58244aa2..00ec48b79541 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -2128,6 +2128,12 @@ package android.media { method public android.media.PlaybackParams setAudioStretchMode(int); } + public class Utils { + ctor public Utils(); + field public static final String SYNCHRONIZED_VIBRATION = "synchronized"; + field public static final String VIBRATION_URI_PARAM = "vibration_uri"; + } + public final class VolumePolicy implements android.os.Parcelable { ctor public VolumePolicy(boolean, boolean, boolean, int); method public int describeContents(); diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 69d3e8d4c0d2..f9ec214390f9 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -550,35 +550,35 @@ public class ActivityManager { public static final int START_ASSISTANT_NOT_ACTIVE_SESSION = FIRST_START_FATAL_ERROR_CODE + 11; /** - * Result for IActivityManaqer.startActivity: the activity was started + * Result for IActivityManager.startActivity: the activity was started * successfully as normal. * @hide */ public static final int START_SUCCESS = FIRST_START_SUCCESS_CODE; /** - * Result for IActivityManaqer.startActivity: the caller asked that the Intent not + * Result for IActivityManager.startActivity: the caller asked that the Intent not * be executed if it is the recipient, and that is indeed the case. * @hide */ public static final int START_RETURN_INTENT_TO_CALLER = FIRST_START_SUCCESS_CODE + 1; /** - * Result for IActivityManaqer.startActivity: activity was started or brought forward in an + * Result for IActivityManager.startActivity: activity was started or brought forward in an * existing task which was brought to the foreground. * @hide */ public static final int START_TASK_TO_FRONT = FIRST_START_SUCCESS_CODE + 2; /** - * Result for IActivityManaqer.startActivity: activity wasn't really started, but + * Result for IActivityManager.startActivity: activity wasn't really started, but * the given Intent was given to the existing top activity. * @hide */ public static final int START_DELIVERED_TO_TOP = FIRST_START_SUCCESS_CODE + 3; /** - * Result for IActivityManaqer.startActivity: request was canceled because + * Result for IActivityManager.startActivity: request was canceled because * app switches are temporarily canceled to ensure the user's last request * (such as pressing home) is performed. * @hide @@ -586,7 +586,7 @@ public class ActivityManager { public static final int START_SWITCHES_CANCELED = FIRST_START_NON_FATAL_ERROR_CODE; /** - * Result for IActivityManaqer.startActivity: a new activity was attempted to be started + * Result for IActivityManager.startActivity: a new activity was attempted to be started * while in Lock Task Mode. * @hide */ @@ -594,55 +594,55 @@ public class ActivityManager { FIRST_START_NON_FATAL_ERROR_CODE + 1; /** - * Result for IActivityManaqer.startActivity: a new activity start was aborted. Never returned + * Result for IActivityManager.startActivity: a new activity start was aborted. Never returned * externally. * @hide */ public static final int START_ABORTED = FIRST_START_NON_FATAL_ERROR_CODE + 2; /** - * Flag for IActivityManaqer.startActivity: do special start mode where + * Flag for IActivityManager.startActivity: do special start mode where * a new activity is launched only if it is needed. * @hide */ public static final int START_FLAG_ONLY_IF_NEEDED = 1<<0; /** - * Flag for IActivityManaqer.startActivity: launch the app for + * Flag for IActivityManager.startActivity: launch the app for * debugging. * @hide */ public static final int START_FLAG_DEBUG = 1<<1; /** - * Flag for IActivityManaqer.startActivity: launch the app for + * Flag for IActivityManager.startActivity: launch the app for * allocation tracking. * @hide */ public static final int START_FLAG_TRACK_ALLOCATION = 1<<2; /** - * Flag for IActivityManaqer.startActivity: launch the app with + * Flag for IActivityManager.startActivity: launch the app with * native debugging support. * @hide */ public static final int START_FLAG_NATIVE_DEBUGGING = 1<<3; /** - * Flag for IActivityManaqer.startActivity: launch the app for + * Flag for IActivityManager.startActivity: launch the app for * debugging and suspend threads. * @hide */ public static final int START_FLAG_DEBUG_SUSPEND = 1 << 4; /** - * Result for IActivityManaqer.broadcastIntent: success! + * Result for IActivityManager.broadcastIntent: success! * @hide */ public static final int BROADCAST_SUCCESS = 0; /** - * Result for IActivityManaqer.broadcastIntent: attempt to broadcast + * Result for IActivityManager.broadcastIntent: attempt to broadcast * a sticky intent without appropriate permission. * @hide */ @@ -656,20 +656,20 @@ public class ActivityManager { public static final int BROADCAST_FAILED_USER_STOPPED = -2; /** - * Type for IActivityManaqer.getIntentSender: this PendingIntent type is unknown. + * Type for IActivityManager.getIntentSender: this PendingIntent type is unknown. * @hide */ public static final int INTENT_SENDER_UNKNOWN = 0; /** - * Type for IActivityManaqer.getIntentSender: this PendingIntent is + * Type for IActivityManager.getIntentSender: this PendingIntent is * for a sendBroadcast operation. * @hide */ public static final int INTENT_SENDER_BROADCAST = 1; /** - * Type for IActivityManaqer.getIntentSender: this PendingIntent is + * Type for IActivityManager.getIntentSender: this PendingIntent is * for a startActivity operation. * @hide */ @@ -677,21 +677,21 @@ public class ActivityManager { public static final int INTENT_SENDER_ACTIVITY = 2; /** - * Type for IActivityManaqer.getIntentSender: this PendingIntent is + * Type for IActivityManager.getIntentSender: this PendingIntent is * for an activity result operation. * @hide */ public static final int INTENT_SENDER_ACTIVITY_RESULT = 3; /** - * Type for IActivityManaqer.getIntentSender: this PendingIntent is + * Type for IActivityManager.getIntentSender: this PendingIntent is * for a startService operation. * @hide */ public static final int INTENT_SENDER_SERVICE = 4; /** - * Type for IActivityManaqer.getIntentSender: this PendingIntent is + * Type for IActivityManager.getIntentSender: this PendingIntent is * for a startForegroundService operation. * @hide */ diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index b8c20bd97264..cc3745675bc9 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -488,6 +488,8 @@ public class ActivityOptions extends ComponentOptions { private static final String KEY_ALLOW_PASS_THROUGH_ON_TOUCH_OUTSIDE = "android.activity.allowPassThroughOnTouchOutside"; + private static final String KEY_FLEXIBLE_LAUNCH_SIZE = "android.activity.flexibleLaunchSize"; + /** * @see #setLaunchCookie * @hide @@ -588,6 +590,7 @@ public class ActivityOptions extends ComponentOptions { @BackgroundActivityStartMode private int mPendingIntentCreatorBackgroundActivityStartMode = MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; + private boolean mFlexibleLaunchSize = false; private boolean mDisableStartingWindow; private boolean mAllowPassThroughOnTouchOutside; @@ -1451,6 +1454,7 @@ public class ActivityOptions extends ComponentOptions { mPendingIntentCreatorBackgroundActivityStartMode = opts.getInt( KEY_PENDING_INTENT_CREATOR_BACKGROUND_ACTIVITY_START_MODE, MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED); + mFlexibleLaunchSize = opts.getBoolean(KEY_FLEXIBLE_LAUNCH_SIZE, /* defaultValue = */ false); mDisableStartingWindow = opts.getBoolean(KEY_DISABLE_STARTING_WINDOW); mAllowPassThroughOnTouchOutside = opts.getBoolean(KEY_ALLOW_PASS_THROUGH_ON_TOUCH_OUTSIDE); mAnimationAbortListener = IRemoteCallback.Stub.asInterface( @@ -2346,6 +2350,24 @@ public class ActivityOptions extends ComponentOptions { } /** + * Sets whether the size of the launch bounds is flexible, meaning it can be overridden to a + * different size during the launch params calculation. + * @hide + */ + public ActivityOptions setFlexibleLaunchSize(boolean isFlexible) { + mFlexibleLaunchSize = isFlexible; + return this; + } + + /** + * Gets whether the size of the launch bounds is flexible. + * @hide + */ + public boolean getFlexibleLaunchSize() { + return mFlexibleLaunchSize; + } + + /** * Update the current values in this ActivityOptions from those supplied * in <var>otherOptions</var>. Any values * defined in <var>otherOptions</var> replace those in the base options. @@ -2601,6 +2623,9 @@ public class ActivityOptions extends ComponentOptions { b.putInt(KEY_PENDING_INTENT_CREATOR_BACKGROUND_ACTIVITY_START_MODE, mPendingIntentCreatorBackgroundActivityStartMode); } + if (mFlexibleLaunchSize) { + b.putBoolean(KEY_FLEXIBLE_LAUNCH_SIZE, mFlexibleLaunchSize); + } if (mDisableStartingWindow) { b.putBoolean(KEY_DISABLE_STARTING_WINDOW, mDisableStartingWindow); } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 1a6e9b07067f..dc5974fde0b0 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -22,14 +22,12 @@ import static android.os.StrictMode.vmIncorrectContextUseEnabled; import static android.permission.flags.Flags.shouldRegisterAttributionSource; import static android.view.WindowManager.LayoutParams.WindowType; -import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.UiContext; -import android.companion.virtual.VirtualDevice; import android.companion.virtual.VirtualDeviceManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.AttributionSource; @@ -2367,47 +2365,11 @@ class ContextImpl extends Context { Log.v(TAG, "Treating renounced permission " + permission + " as denied"); return PERMISSION_DENIED; } - int deviceId = resolveDeviceIdForPermissionCheck(permission); + int deviceId = PermissionManager.resolveDeviceIdForPermissionCheck(this, getDeviceId(), + permission); return PermissionManager.checkPermission(permission, pid, uid, deviceId); } - private int resolveDeviceIdForPermissionCheck(String permission) { - // When checking a device-aware permission on a remote device, if the permission is CAMERA - // or RECORD_AUDIO we need to check remote device's corresponding capability. If the remote - // device doesn't have capability fall back to checking permission on the default device. - // Note: we only perform permission check redirection when the device id is not explicitly - // set in the context. - int deviceId = getDeviceId(); - if (deviceId != Context.DEVICE_ID_DEFAULT - && !mIsExplicitDeviceId - && PermissionManager.DEVICE_AWARE_PERMISSIONS.contains(permission)) { - VirtualDeviceManager virtualDeviceManager = - getSystemService(VirtualDeviceManager.class); - if (virtualDeviceManager == null) { - Slog.e( - TAG, - "VDM is not enabled when device id is not default. deviceId = " - + deviceId); - } else { - VirtualDevice virtualDevice = virtualDeviceManager.getVirtualDevice(deviceId); - if (virtualDevice != null) { - if ((Objects.equals(permission, Manifest.permission.RECORD_AUDIO) - && !virtualDevice.hasCustomAudioInputSupport()) - || (Objects.equals(permission, Manifest.permission.CAMERA) - && !virtualDevice.hasCustomCameraSupport())) { - deviceId = Context.DEVICE_ID_DEFAULT; - } - } else { - Slog.e( - TAG, - "virtualDevice is not found when device id is not default. deviceId = " - + deviceId); - } - } - } - return deviceId; - } - /** @hide */ @Override public int checkPermission(String permission, int pid, int uid, IBinder callerToken) { @@ -2511,7 +2473,8 @@ class ContextImpl extends Context { @Override public int getPermissionRequestState(String permission) { Objects.requireNonNull(permission, "Permission name can't be null"); - int deviceId = resolveDeviceIdForPermissionCheck(permission); + int deviceId = PermissionManager.resolveDeviceIdForPermissionCheck(this, getDeviceId(), + permission); PermissionManager permissionManager = getSystemService(PermissionManager.class); return permissionManager.getPermissionRequestState(getOpPackageName(), permission, deviceId); diff --git a/core/java/android/app/DreamManager.java b/core/java/android/app/DreamManager.java index c597a9dcae7e..555006b97911 100644 --- a/core/java/android/app/DreamManager.java +++ b/core/java/android/app/DreamManager.java @@ -71,8 +71,11 @@ public class DreamManager { @TestApi @RequiresPermission(WRITE_SECURE_SETTINGS) public void setScreensaverEnabled(boolean enabled) { - Settings.Secure.putIntForUser(mContext.getContentResolver(), - Settings.Secure.SCREENSAVER_ENABLED, enabled ? 1 : 0, UserHandle.USER_CURRENT); + try { + mService.setScreensaverEnabled(enabled); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } } /** diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 1b71e73db852..cc72d8f1ad8c 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -9526,14 +9526,21 @@ public class Notification implements Parcelable .viewType(viewType) .highlightExpander(isConversationLayout) .hideProgress(true) - .text(null) .hideLeftIcon(isOneToOne) .hideRightIcon(hideRightIcons || isOneToOne); if (notificationsRedesignTemplates()) { + String lastMessage = !mMessages.isEmpty() + ? mMessages.getLast().mText.toString() : null; + p.title(conversationTitle) + // The text is not actually displayed like this (since we're using a + // MessagingLinearLayout instead of the regular text), but we're using it to + // know whether the notification will have a second line in practice. + .text(lastMessage) .hideAppName(isCollapsed); } else { p.title(isLegacyHeaderless ? conversationTitle : null) + .text(null) .headerTextSecondary(isLegacyHeaderless ? null : conversationTitle); } RemoteViews contentView = mBuilder.applyStandardTemplateWithActions( diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java index c573161f30cc..38141cf20ce3 100644 --- a/core/java/android/app/PropertyInvalidatedCache.java +++ b/core/java/android/app/PropertyInvalidatedCache.java @@ -293,6 +293,7 @@ public class PropertyInvalidatedCache<Query, Result> { // The test mode. This is only used to ensure that the test functions setTestMode() and // testPropertyName() are used correctly. + @GuardedBy("sGlobalLock") private static boolean sTestMode = false; /** @@ -668,7 +669,7 @@ public class PropertyInvalidatedCache<Query, Result> { // True if this handler is in test mode. If it is in test mode, then nonces are stored // and retrieved from mTestNonce. @GuardedBy("mLock") - private boolean mTestMode = false; + private boolean mTestMode; // This is the local value of the nonce, as last set by the NonceHandler. It is always // updated by the setNonce() operation. The getNonce() operation returns this value in @@ -692,6 +693,9 @@ public class PropertyInvalidatedCache<Query, Result> { NonceHandler(@NonNull String name) { mName = name; + synchronized (sGlobalLock) { + mTestMode = sTestMode; + } } /** @@ -1414,9 +1418,13 @@ public class PropertyInvalidatedCache<Query, Result> { /** * Enable or disable testing. The protocol requires that the mode toggle: for instance, it is - * illegal to clear the test mode if the test mode is already off. The purpose is solely to - * ensure that test clients do not forget to use the test mode properly, even though the - * current logic does not care. + * illegal to clear the test mode if the test mode is already off. Enabling test mode puts + * all caches in the process into test mode; all nonces are initialized to UNSET and + * subsequent reads and writes are to process memory. This has the effect of disabling all + * caches that are not local to the process. Disabling test mode restores caches to normal + * operation. + * @param mode The desired test mode. + * @throws IllegalStateException if the supplied mode is already set. * @hide */ @VisibleForTesting @@ -1431,10 +1439,8 @@ public class PropertyInvalidatedCache<Query, Result> { } } sTestMode = mode; - if (mode) { - // No action when testing begins. - } else { - resetAfterTestLocked(); + if (Flags.picTestMode() || !mode) { + setTestModeLocked(mode); } } } @@ -1445,11 +1451,11 @@ public class PropertyInvalidatedCache<Query, Result> { * that were not originally in test mode. */ @GuardedBy("sGlobalLock") - private static void resetAfterTestLocked() { + private static void setTestModeLocked(boolean mode) { for (Iterator<String> e = sHandlers.keys().asIterator(); e.hasNext(); ) { String s = e.next(); final NonceHandler h = sHandlers.get(s); - h.setTestMode(false); + h.setTestMode(mode); } } diff --git a/core/java/android/app/admin/PolicyUpdateReceiver.java b/core/java/android/app/admin/PolicyUpdateReceiver.java index be13988d7c76..630ab0ece07d 100644 --- a/core/java/android/app/admin/PolicyUpdateReceiver.java +++ b/core/java/android/app/admin/PolicyUpdateReceiver.java @@ -20,10 +20,12 @@ import android.annotation.BroadcastBehavior; import android.annotation.NonNull; import android.annotation.SdkConstant; import android.annotation.TestApi; +import android.app.admin.flags.Flags; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.text.TextUtils; import android.util.Log; import java.util.Objects; @@ -46,6 +48,10 @@ import java.util.Objects; public abstract class PolicyUpdateReceiver extends BroadcastReceiver { private static String TAG = "PolicyUpdateReceiver"; + //TODO(b/378931989): Switch to android.app.admin.DevicePolicyIdentifiers.MEMORY_TAGGING_POLICY + //when the appropriate flag is launched. + private static final String MEMORY_TAGGING_POLICY = "memoryTagging"; + /** * Action for a broadcast sent to admins to communicate back the result of setting a policy in * {@link DevicePolicyManager}. @@ -156,15 +162,28 @@ public abstract class PolicyUpdateReceiver extends BroadcastReceiver { @Override public final void onReceive(Context context, Intent intent) { Objects.requireNonNull(intent.getAction()); + String policyKey; switch (intent.getAction()) { case ACTION_DEVICE_POLICY_SET_RESULT: Log.i(TAG, "Received ACTION_DEVICE_POLICY_SET_RESULT"); - onPolicySetResult(context, getPolicyKey(intent), getPolicyExtraBundle(intent), + policyKey = getPolicyKey(intent); + if (!shouldPropagatePolicy(policyKey)) { + Log.d(TAG, TextUtils.formatSimple( + "Skipping propagation of policy %s", policyKey)); + break; + } + onPolicySetResult(context, policyKey, getPolicyExtraBundle(intent), getTargetUser(intent), getPolicyChangedReason(intent)); break; case ACTION_DEVICE_POLICY_CHANGED: Log.i(TAG, "Received ACTION_DEVICE_POLICY_CHANGED"); - onPolicyChanged(context, getPolicyKey(intent), getPolicyExtraBundle(intent), + policyKey = getPolicyKey(intent); + if (!shouldPropagatePolicy(policyKey)) { + Log.d(TAG, TextUtils.formatSimple( + "Skipping propagation of policy %s", policyKey)); + break; + } + onPolicyChanged(context, policyKey, getPolicyExtraBundle(intent), getTargetUser(intent), getPolicyChangedReason(intent)); break; default: @@ -217,6 +236,14 @@ public abstract class PolicyUpdateReceiver extends BroadcastReceiver { return new TargetUser(targetUserId); } + /** + * @hide + */ + private boolean shouldPropagatePolicy(String policyKey) { + return !MEMORY_TAGGING_POLICY.equals(policyKey) || Flags.setMtePolicyCoexistence(); + } + + // TODO(b/260847505): Add javadocs to explain which DPM APIs are supported /** * Callback triggered after an admin has set a policy using one of the APIs in diff --git a/core/java/android/app/contextualsearch/flags.aconfig b/core/java/android/app/contextualsearch/flags.aconfig index 1de034b23a7a..1a14b20d6c09 100644 --- a/core/java/android/app/contextualsearch/flags.aconfig +++ b/core/java/android/app/contextualsearch/flags.aconfig @@ -23,6 +23,18 @@ flag { bug: "371065456" } + +flag { + name: "report_secure_surfaces_in_assist_structure" + namespace: "windowing_frontend" + description: "SurfaceView reports when the surface is using a SECURE flag." + bug: "390504528" + metadata { + purpose: PURPOSE_BUGFIX + } +} + + flag { name: "contextual_search_prevent_self_capture" namespace: "sysui_integrations" diff --git a/core/java/android/app/performance.aconfig b/core/java/android/app/performance.aconfig index 2569f7b99dca..82875ebb0f77 100644 --- a/core/java/android/app/performance.aconfig +++ b/core/java/android/app/performance.aconfig @@ -50,3 +50,10 @@ flag { description: "Cache null returns from binder calls" bug: "372923336" } + +flag { + namespace: "system_performance" + name: "pic_test_mode" + description: "Updated test mode for PIC" + bug: "396173886" +} diff --git a/core/java/android/app/servertransaction/ClientTransaction.java b/core/java/android/app/servertransaction/ClientTransaction.java index 6e3e86cfbffc..e726bc9df4d5 100644 --- a/core/java/android/app/servertransaction/ClientTransaction.java +++ b/core/java/android/app/servertransaction/ClientTransaction.java @@ -236,9 +236,17 @@ public class ClientTransaction implements Parcelable { * 2. The transaction message is scheduled. * 3. The client calls {@link TransactionExecutor#execute(ClientTransaction)}, which executes * all callbacks and necessary lifecycle transitions. + * + * @return {@link RemoteException} if the transaction failed. */ - public void schedule() throws RemoteException { - mClient.scheduleTransaction(this); + @Nullable + public RemoteException schedule() { + try { + mClient.scheduleTransaction(this); + return null; + } catch (RemoteException e) { + return e; + } } // Parcelable implementation diff --git a/core/java/android/content/integrity/OWNERS b/core/java/android/content/integrity/OWNERS index 20c758aedd67..ca65fdab99b1 100644 --- a/core/java/android/content/integrity/OWNERS +++ b/core/java/android/content/integrity/OWNERS @@ -1,5 +1,4 @@ # Bug component: 722021 toddke@android.com -toddke@google.com patb@google.com diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig index 255a08cf170f..42bef0e91539 100644 --- a/core/java/android/content/pm/flags.aconfig +++ b/core/java/android/content/pm/flags.aconfig @@ -400,3 +400,11 @@ flag { bug: "378539511" is_fixed_read_only: true } + +flag { + name: "cloud_compilation_verification" + namespace: "art_mainline" + description: "Feature flag to enable the Cloud Compilation install-time verification in the package manager." + bug: "377474232" + is_fixed_read_only: true +} diff --git a/core/java/android/content/pm/parsing/OWNERS b/core/java/android/content/pm/parsing/OWNERS index 8049d5cb7fa2..b8fa1a93ed78 100644 --- a/core/java/android/content/pm/parsing/OWNERS +++ b/core/java/android/content/pm/parsing/OWNERS @@ -1,5 +1,3 @@ # Bug component: 36137 -chiuwinson@google.com patb@google.com -toddke@google.com diff --git a/core/java/android/content/pm/permission/OWNERS b/core/java/android/content/pm/permission/OWNERS index cf7e6890876a..8ef84745c99f 100644 --- a/core/java/android/content/pm/permission/OWNERS +++ b/core/java/android/content/pm/permission/OWNERS @@ -3,6 +3,5 @@ include platform/frameworks/base:/core/java/android/permission/OWNERS toddke@android.com -toddke@google.com patb@google.com diff --git a/core/java/android/gesture/OWNERS b/core/java/android/gesture/OWNERS index 168630af6da4..ffa753aa65b2 100644 --- a/core/java/android/gesture/OWNERS +++ b/core/java/android/gesture/OWNERS @@ -3,5 +3,4 @@ romainguy@google.com adamp@google.com aurimas@google.com -nduca@google.com sumir@google.com diff --git a/core/java/android/metrics/OWNERS b/core/java/android/metrics/OWNERS index ba867e0cad2b..98aaf3f47b21 100644 --- a/core/java/android/metrics/OWNERS +++ b/core/java/android/metrics/OWNERS @@ -1,4 +1,3 @@ # Bug component: 26805 cwren@android.com -cwren@google.com diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 1e6469c57fa9..0ceafa01017e 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -1515,7 +1515,7 @@ public class Build { VERSION_CODES.VANILLA_ICE_CREAM * SDK_INT_MULTIPLIER; /** - * The upcoming, not yet finalized, version of Android. + * Android 36.0. */ public static final int BAKLAVA = VERSION_CODES.BAKLAVA * SDK_INT_MULTIPLIER; } diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java index 74972346bf2e..ce1717b60bfd 100644 --- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java +++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java @@ -92,11 +92,8 @@ public final class MessageQueue { // queue for async messages when inserting a message at the tail. private int mAsyncMessageCount; - /** - * @hide - */ private final AtomicLong mMessageCount = new AtomicLong(); - private final Thread mThread; + private final String mThreadName; private final long mTid; /** @@ -133,7 +130,7 @@ public final class MessageQueue { mUseConcurrent = sIsProcessAllowedToUseConcurrent; mQuitAllowed = quitAllowed; mPtr = nativeInit(); - mThread = Thread.currentThread(); + mThreadName = Thread.currentThread().getName(); mTid = Process.myTid(); } @@ -223,10 +220,10 @@ public final class MessageQueue { traceMessageCount(); PerfettoTrace.instant(PerfettoTrace.MQ_CATEGORY, "message_queue_send") - .addFlow(msg.mEventId.get()) + .setFlow(msg.mEventId.get()) .beginProto() .beginNested(2004 /* message_queue */) - .addField(2 /* receiving_thread_name */, mThread.getName()) + .addField(2 /* receiving_thread_name */, mThreadName) .addField(3 /* message_code */, msg.what) .addField(4 /* message_delay_ms */, when - SystemClock.uptimeMillis()) .endNested() @@ -237,7 +234,7 @@ public final class MessageQueue { /** @hide */ private void traceMessageCount() { PerfettoTrace.counter(PerfettoTrace.MQ_CATEGORY, mMessageCount.get()) - .usingThreadCounterTrack(mTid, mThread.getName()) + .usingThreadCounterTrack(mTid, mThreadName) .emit(); } diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java index 8cfd32449537..48e6249d004a 100644 --- a/core/java/android/os/IBinder.java +++ b/core/java/android/os/IBinder.java @@ -451,7 +451,7 @@ public interface IBinder { * @param executor The executor on which to run the callback. * @param callback The callback used to deliver state change notifications. * - * <p>@throws {@link UnsupportedOperationException} if the kernel binder driver does not support + * @throws {@link UnsupportedOperationException} if the kernel binder driver does not support * this feature. */ @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK) diff --git a/core/java/android/os/IpcDataCache.java b/core/java/android/os/IpcDataCache.java index 240bc4f74820..2e7c3be53d90 100644 --- a/core/java/android/os/IpcDataCache.java +++ b/core/java/android/os/IpcDataCache.java @@ -719,9 +719,13 @@ public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query, /** * Enable or disable testing. The protocol requires that the mode toggle: for instance, it is - * illegal to clear the test mode if the test mode is already off. The purpose is solely to - * ensure that test clients do not forget to use the test mode properly, even though the - * current logic does not care. + * illegal to clear the test mode if the test mode is already off. Enabling test mode puts + * all caches in the process into test mode; all nonces are initialized to UNSET and + * subsequent reads and writes are to process memory. This has the effect of disabling all + * caches that are not local to the process. Disabling test mode restores caches to normal + * operation. + * @param mode The desired test mode. + * @throws IllegalStateException if the supplied mode is already set. * @hide */ @TestApi diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java index 1329b90538bb..3ff6e052335e 100644 --- a/core/java/android/os/Looper.java +++ b/core/java/android/os/Looper.java @@ -205,7 +205,7 @@ public final class Looper { .addField(1 /* sending_thread_name */, msg.mSendingThreadName) .endNested() .endProto() - .addTerminatingFlow(msg.mEventId.get()) + .setTerminatingFlow(msg.mEventId.get()) .emit(); // This must be in a local variabe, in case a UI event sets the logger diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java index b22d1774d967..69e84e3b097a 100644 --- a/core/java/android/os/Message.java +++ b/core/java/android/os/Message.java @@ -23,7 +23,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; /** * @@ -43,7 +43,7 @@ public final class Message implements Parcelable { * * @hide Only for use within the system server. */ - public final AtomicInteger mEventId = new AtomicInteger(); + public final AtomicLong mEventId = new AtomicLong(); /** * User-defined message code so that the recipient can identify diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS index 727dcbaca4bf..a6785bab56f3 100644 --- a/core/java/android/os/OWNERS +++ b/core/java/android/os/OWNERS @@ -78,7 +78,7 @@ per-file Trace.java = file:/TRACE_OWNERS per-file PatternMatcher* = file:/PACKAGE_MANAGER_OWNERS # PermissionEnforcer -per-file PermissionEnforcer.java = tweek@google.com, brufino@google.com +per-file PermissionEnforcer.java = tweek@google.com # RemoteCallbackList per-file RemoteCallbackList.java = shayba@google.com diff --git a/core/java/android/os/PerfettoTrackEventExtra.java b/core/java/android/os/PerfettoTrackEventExtra.java index f4b5dfe76f88..2848bcb8ad34 100644 --- a/core/java/android/os/PerfettoTrackEventExtra.java +++ b/core/java/android/os/PerfettoTrackEventExtra.java @@ -172,7 +172,6 @@ public final class PerfettoTrackEventExtra { private final Pool<FieldDouble> mFieldDoubleCache; private final Pool<FieldString> mFieldStringCache; private final Pool<FieldNested> mFieldNestedCache; - private final Pool<Flow> mFlowCache; private final Pool<Builder> mBuilderCache; private Builder() { @@ -187,7 +186,6 @@ public final class PerfettoTrackEventExtra { mFieldDoubleCache = mExtra.mFieldDoubleCache; mFieldStringCache = mExtra.mFieldStringCache; mFieldNestedCache = mExtra.mFieldNestedCache; - mFlowCache = mExtra.mFlowCache; mBuilderCache = mExtra.mBuilderCache; mCounterInt64 = mExtra.getCounterInt64(); @@ -227,7 +225,6 @@ public final class PerfettoTrackEventExtra { mFieldStringCache.reset(); mFieldNestedCache.reset(); mBuilderCache.reset(); - mFlowCache.reset(); mExtra.reset(); // Reset after on init in case the thread created builders without calling emit @@ -325,39 +322,7 @@ public final class PerfettoTrackEventExtra { /** * Adds a flow with {@code id}. */ - public Builder addFlow(int id) { - if (!mIsCategoryEnabled) { - return this; - } - if (DEBUG) { - checkParent(); - } - Flow flow = mFlowCache.get(sFlowSupplier); - flow.setProcessFlow(id); - mExtra.addPerfettoPointer(flow); - return this; - } - - /** - * Adds a terminating flow with {@code id}. - */ - public Builder addTerminatingFlow(int id) { - if (!mIsCategoryEnabled) { - return this; - } - if (DEBUG) { - checkParent(); - } - Flow flow = mFlowCache.get(sFlowSupplier); - flow.setProcessTerminatingFlow(id); - mExtra.addPerfettoPointer(flow); - return this; - } - - /** - * Adds a flow with {@code id}. - */ - public Builder setFlow(int id) { + public Builder setFlow(long id) { if (!mIsCategoryEnabled) { return this; } @@ -372,7 +337,7 @@ public final class PerfettoTrackEventExtra { /** * Adds a terminating flow with {@code id}. */ - public Builder setTerminatingFlow(int id) { + public Builder setTerminatingFlow(long id) { if (!mIsCategoryEnabled) { return this; } @@ -670,7 +635,6 @@ public final class PerfettoTrackEventExtra { private final Pool<FieldDouble> mFieldDoubleCache = new Pool(DEFAULT_EXTRA_CACHE_SIZE); private final Pool<FieldString> mFieldStringCache = new Pool(DEFAULT_EXTRA_CACHE_SIZE); private final Pool<FieldNested> mFieldNestedCache = new Pool(DEFAULT_EXTRA_CACHE_SIZE); - private final Pool<Flow> mFlowCache = new Pool(DEFAULT_EXTRA_CACHE_SIZE); private final Pool<Builder> mBuilderCache = new Pool(DEFAULT_EXTRA_CACHE_SIZE); private static final NativeAllocationRegistry sRegistry = diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java index 77b6d70339ab..2736b60cd1f6 100644 --- a/core/java/android/os/PowerManagerInternal.java +++ b/core/java/android/os/PowerManagerInternal.java @@ -357,4 +357,9 @@ public abstract class PowerManagerInternal { * This may affect dream eligibility. */ public abstract void setDevicePostured(boolean isPostured); + + /** + * Notifies PowerManager that settings have changed and that it should refresh its state. + */ + public abstract void updateSettings(); } diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 518820430419..561a2c96e6a7 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -16,6 +16,7 @@ package android.permission; +import static android.companion.virtual.VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT; import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT; import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE; import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED; @@ -2039,12 +2040,49 @@ public final class PermissionManager { new PackageNamePermissionQuery(permName, pkgName, persistentDeviceId, userId)); } + /** + * When checking a device-aware permission on a remote device, if the permission is CAMERA + * or RECORD_AUDIO we need to check remote device's corresponding capability. If the remote + * device doesn't have capability fall back to checking permission on the default device. + * + * @hide + */ + public static int resolveDeviceIdForPermissionCheck(@NonNull Context context, int deviceId, + @Nullable String permission) { + if (deviceId == Context.DEVICE_ID_DEFAULT || !DEVICE_AWARE_PERMISSIONS.contains( + permission)) { + return Context.DEVICE_ID_DEFAULT; + } + + VirtualDeviceManager virtualDeviceManager = + context.getSystemService(VirtualDeviceManager.class); + if (virtualDeviceManager == null) { + Slog.e(LOG_TAG, "VDM is not enabled when device id is not default. deviceId = " + + deviceId); + } else { + VirtualDevice virtualDevice = virtualDeviceManager.getVirtualDevice(deviceId); + if (virtualDevice != null) { + if ((Objects.equals(permission, Manifest.permission.RECORD_AUDIO) + && !virtualDevice.hasCustomAudioInputSupport()) + || (Objects.equals(permission, Manifest.permission.CAMERA) + && !virtualDevice.hasCustomCameraSupport())) { + deviceId = Context.DEVICE_ID_DEFAULT; + } + } else { + Slog.e(LOG_TAG, + "virtualDevice is not found when device id is not default. deviceId = " + + deviceId); + } + } + return deviceId; + } + @Nullable private String getPersistentDeviceId(int deviceId) { String persistentDeviceId = null; if (deviceId == Context.DEVICE_ID_DEFAULT) { - persistentDeviceId = VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT; + persistentDeviceId = PERSISTENT_DEVICE_ID_DEFAULT; } else { VirtualDeviceManager virtualDeviceManager = mContext.getSystemService( VirtualDeviceManager.class); diff --git a/core/java/android/preference/OWNERS b/core/java/android/preference/OWNERS index b4cb9ec7ceda..38a5abd8ff56 100644 --- a/core/java/android/preference/OWNERS +++ b/core/java/android/preference/OWNERS @@ -1,5 +1,4 @@ lpf@google.com -pavlis@google.com clarabayarri@google.com -per-file SeekBarVolumizer.java = jmtrivi@google.com
\ No newline at end of file +per-file SeekBarVolumizer.java = jmtrivi@google.com diff --git a/core/java/android/print/OWNERS b/core/java/android/print/OWNERS index ce79f5d0c669..15f640650868 100644 --- a/core/java/android/print/OWNERS +++ b/core/java/android/print/OWNERS @@ -1,5 +1,4 @@ # Bug component: 47273 anothermark@google.com -kumarashishg@google.com bmgordon@google.com diff --git a/core/java/android/printservice/OWNERS b/core/java/android/printservice/OWNERS index ce79f5d0c669..15f640650868 100644 --- a/core/java/android/printservice/OWNERS +++ b/core/java/android/printservice/OWNERS @@ -1,5 +1,4 @@ # Bug component: 47273 anothermark@google.com -kumarashishg@google.com bmgordon@google.com diff --git a/core/java/android/security/advancedprotection/AdvancedProtectionManager.java b/core/java/android/security/advancedprotection/AdvancedProtectionManager.java index ea01fc98eda0..770e234381c4 100644 --- a/core/java/android/security/advancedprotection/AdvancedProtectionManager.java +++ b/core/java/android/security/advancedprotection/AdvancedProtectionManager.java @@ -16,7 +16,6 @@ package android.security.advancedprotection; -import static android.app.admin.DevicePolicyIdentifiers.MEMORY_TAGGING_POLICY; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.os.UserManager.DISALLOW_CELLULAR_2G; import static android.os.UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY; @@ -59,6 +58,10 @@ import java.util.concurrent.Executor; public final class AdvancedProtectionManager { private static final String TAG = "AdvancedProtectionMgr"; + //TODO(b/378931989): Switch to android.app.admin.DevicePolicyIdentifiers.MEMORY_TAGGING_POLICY + //when the appropriate flag is launched. + private static final String MEMORY_TAGGING_POLICY = "memoryTagging"; + /** * Advanced Protection's identifier for setting policies or restrictions in * {@link DevicePolicyManager}. @@ -359,8 +362,7 @@ public final class AdvancedProtectionManager { featureId = FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES; } else if (DISALLOW_CELLULAR_2G.equals(identifier)) { featureId = FEATURE_ID_DISALLOW_CELLULAR_2G; - } else if (android.app.admin.flags.Flags.setMtePolicyCoexistence() && MEMORY_TAGGING_POLICY - .equals(identifier)) { + } else if (MEMORY_TAGGING_POLICY.equals(identifier)) { featureId = FEATURE_ID_ENABLE_MTE; } else { throw new UnsupportedOperationException("Unsupported identifier: " + identifier); diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl index 3ca9d937b0ca..fdacd600b9f5 100644 --- a/core/java/android/service/dreams/IDreamManager.aidl +++ b/core/java/android/service/dreams/IDreamManager.aidl @@ -59,4 +59,6 @@ interface IDreamManager { float screenBrightnessFloat, int screenBrightnessInt, boolean useNormalBrightnessForDoze); oneway void finishSelfOneway(in IBinder token, boolean immediate); + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)") + void setScreensaverEnabled(boolean enabled); } diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 41a64e22e058..744cdf6629e7 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -1323,14 +1323,13 @@ public abstract class WallpaperService extends Service { redrawNeeded ? 1 : 0)); return; } - - final int transformHint = SurfaceControl.rotationToBufferTransform( - (mDisplay.getInstallOrientation() + mDisplay.getRotation()) % 4); - mSurfaceControl.setTransformHint(transformHint); WindowLayout.computeSurfaceSize(mLayout, maxBounds, mWidth, mHeight, mWinFrames.frame, false /* dragResizing */, mSurfaceSize); if (mSurfaceControl.isValid()) { + final int transformHint = SurfaceControl.rotationToBufferTransform( + (mDisplay.getInstallOrientation() + mDisplay.getRotation()) % 4); + mSurfaceControl.setTransformHint(transformHint); if (mBbqSurfaceControl == null) { mBbqSurfaceControl = new SurfaceControl.Builder() .setName("Wallpaper BBQ wrapper") diff --git a/core/java/android/text/OWNERS b/core/java/android/text/OWNERS index 0935ffd9dd81..b493ef7009d9 100644 --- a/core/java/android/text/OWNERS +++ b/core/java/android/text/OWNERS @@ -4,7 +4,6 @@ grantapher@google.com halilibo@google.com haoyuchang@google.com justinghan@google.com -klippenstein@google.com nona@google.com seanmcq@google.com siyamed@google.com diff --git a/core/java/android/util/apk/OWNERS b/core/java/android/util/apk/OWNERS index 0f4e869f8b9a..f267f9a4edb6 100644 --- a/core/java/android/util/apk/OWNERS +++ b/core/java/android/util/apk/OWNERS @@ -1,3 +1,2 @@ include /core/java/android/content/pm/OWNERS -cbrubaker@google.com mpgroover@google.com diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS index 80484a6328e0..3353923292e1 100644 --- a/core/java/android/view/OWNERS +++ b/core/java/android/view/OWNERS @@ -3,7 +3,6 @@ romainguy@google.com adamp@google.com aurimas@google.com -nduca@google.com sumir@google.com ogunwale@google.com jjaggi@google.com diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index b98f4db5dce6..4f6c730857a8 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -2247,6 +2247,27 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall t.reparent(sc, mBlastSurfaceControl).show(sc); } + /** + * Populates a {@link ViewStructure} for content capture. + * + * <p>If {@link #setSecure(boolean)} has been enabled, will add a property to the + * {@link android.app.assist.AssistStructure.ViewNode} to indicate that content will not + * be available for this part of the screen. + * + * @hide + */ + @Override + protected void onProvideStructure(@NonNull ViewStructure structure, + @ViewStructureType int viewFor, int flags) { + super.onProvideStructure(structure, viewFor, flags); + if (android.app.contextualsearch.flags.Flags.reportSecureSurfacesInAssistStructure()) { + if ((mSurfaceFlags & SurfaceControl.SECURE) != 0) { + structure.getExtras().putBoolean( + ViewStructure.EXTRA_CONTAINS_SECURE_LAYERS, true); + } + } + } + /** @hide */ @Override public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index c048d7987515..f50d77e6aead 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -34463,7 +34463,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @FlaggedApi(android.app.jank.Flags.FLAG_DETAILED_APP_JANK_METRICS_API) public void reportAppJankStats(@NonNull AppJankStats appJankStats) { - getRootView().reportAppJankStats(appJankStats); + View rootView = getRootView(); + if (rootView == this) return; + + rootView.reportAppJankStats(appJankStats); } /** @@ -34471,6 +34474,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @hide */ public @Nullable JankTracker getJankTracker() { - return getRootView().getJankTracker(); + View rootView = getRootView(); + if (rootView == this) { + return null; + } + return rootView.getJankTracker(); } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 7fd7be8585a4..e157da72196a 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -153,6 +153,7 @@ import android.annotation.UiContext; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.ResourcesManager; +import android.app.UiModeManager; import android.app.WindowConfiguration; import android.app.compat.CompatChanges; import android.app.servertransaction.WindowStateTransactionItem; @@ -196,6 +197,7 @@ import android.hardware.display.DisplayManagerGlobal; import android.hardware.input.InputManagerGlobal; import android.hardware.input.InputSettings; import android.media.AudioManager; +import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Bundle; @@ -472,8 +474,6 @@ public final class ViewRootImpl implements ViewParent, @Nullable private ContentObserver mForceInvertObserver; - private static final int INVALID_VALUE = Integer.MIN_VALUE; - private int mForceInvertEnabled = INVALID_VALUE; /** * Callback for notifying about global configuration changes. */ @@ -555,6 +555,8 @@ public final class ViewRootImpl implements ViewParent, @UiContext public final Context mContext; + private UiModeManager mUiModeManager; + @UnsupportedAppUsage final IWindowSession mWindowSession; @NonNull Display mDisplay; @@ -1804,23 +1806,6 @@ public final class ViewRootImpl implements ViewParent, } } - private boolean isForceInvertEnabled() { - if (mForceInvertEnabled == INVALID_VALUE) { - reloadForceInvertEnabled(); - } - return mForceInvertEnabled == 1; - } - - private void reloadForceInvertEnabled() { - if (forceInvertColor()) { - mForceInvertEnabled = Settings.Secure.getIntForUser( - mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED, - /* def= */ 0, - UserHandle.myUserId()); - } - } - /** * Register any kind of listeners if setView was success. */ @@ -1856,17 +1841,22 @@ public final class ViewRootImpl implements ViewParent, mForceInvertObserver = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange) { - reloadForceInvertEnabled(); updateForceDarkMode(); } }; - mContext.getContentResolver().registerContentObserver( - Settings.Secure.getUriFor( - Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED - ), - false, - mForceInvertObserver, - UserHandle.myUserId()); + + final Uri[] urisToObserve = { + Settings.Secure.getUriFor( + Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED), + Settings.Secure.getUriFor(Settings.Secure.UI_NIGHT_MODE) + }; + for (Uri uri : urisToObserve) { + mContext.getContentResolver().registerContentObserver( + uri, + false, + mForceInvertObserver, + UserHandle.myUserId()); + } } } } @@ -2073,21 +2063,25 @@ public final class ViewRootImpl implements ViewParent, return getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; } - /** Returns true if force dark should be enabled according to various settings */ + /** + * Determines the type of force dark to apply, considering force inversion, system night mode, + * and app-specific settings (including developer opt-outs). + * + * @return A {@link ForceDarkType.ForceDarkTypeDef} constant indicating the force dark type. + */ @VisibleForTesting public @ForceDarkType.ForceDarkTypeDef int determineForceDarkType() { if (forceInvertColor()) { // Force invert ignores all developer opt-outs. // We also ignore dark theme, since the app developer can override the user's preference - // for dark mode in configuration.uiMode. Instead, we assume that the force invert - // setting will be enabled at the same time dark theme is in the Settings app. - if (isForceInvertEnabled()) { + // for dark mode in configuration.uiMode. Instead, we assume that both force invert and + // the system's dark theme are enabled. + if (getUiModeManager().getForceInvertState() == UiModeManager.FORCE_INVERT_TYPE_DARK) { return ForceDarkType.FORCE_INVERT_COLOR_DARK; } } boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES; - if (useAutoDark) { boolean forceDarkAllowedDefault = SystemProperties.getBoolean(ThreadedRenderer.DEBUG_FORCE_DARK, false); @@ -9401,6 +9395,13 @@ public final class ViewRootImpl implements ViewParent, return mAudioManager; } + private UiModeManager getUiModeManager() { + if (mUiModeManager == null) { + mUiModeManager = mContext.getSystemService(UiModeManager.class); + } + return mUiModeManager; + } + private Vibrator getSystemVibrator() { if (mVibrator == null) { mVibrator = mContext.getSystemService(Vibrator.class); diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java index 43a946a234ba..53953a9379df 100644 --- a/core/java/android/view/ViewStructure.java +++ b/core/java/android/view/ViewStructure.java @@ -77,6 +77,19 @@ public abstract class ViewStructure { "android.view.ViewStructure.extra.FIRST_ACTIVE_POSITION"; /** + * Key used for confirming whether the view draws graphics containing secure layers. + * + * <p>Secure layers cannot be read back into main memory and will show up as blank regions + * in assist screenshots. + * + * @see android.view.SurfaceControl#SECURE + * + * @hide + */ + public static final String EXTRA_CONTAINS_SECURE_LAYERS = + "android.view.ViewStructure.extra.CONTAINS_SECURE_LAYERS"; + + /** * Key used for writing the type of the view that generated the virtual structure of its * children. * diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 196ae5e59fa7..83dc79beb75e 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -631,6 +631,12 @@ public interface WindowManager extends ViewManager { int TRANSIT_FLAG_AOD_APPEARING = (1 << 15); // 0x8000 /** + * Transition flag: Indicates that the task shouldn't move to front when launching the activity. + * @hide + */ + int TRANSIT_FLAG_AVOID_MOVE_TO_FRONT = (1 << 16); // 0x10000 + + /** * @hide */ @IntDef(flag = true, prefix = { "TRANSIT_FLAG_" }, value = { @@ -650,6 +656,7 @@ public interface WindowManager extends ViewManager { TRANSIT_FLAG_KEYGUARD_UNOCCLUDING, TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH, TRANSIT_FLAG_AOD_APPEARING, + TRANSIT_FLAG_AVOID_MOVE_TO_FRONT, }) @Retention(RetentionPolicy.SOURCE) @interface TransitionFlags {} diff --git a/core/java/android/view/inspector/OWNERS b/core/java/android/view/inspector/OWNERS index 705f4b342d42..f3450344ea81 100644 --- a/core/java/android/view/inspector/OWNERS +++ b/core/java/android/view/inspector/OWNERS @@ -2,5 +2,4 @@ romainguy@google.com alanv@google.com adamp@google.com aurimas@google.com -nduca@google.com sumir@google.com diff --git a/core/java/android/webkit/TEST_MAPPING b/core/java/android/webkit/TEST_MAPPING index 38580595dc2d..c9b54760491a 100644 --- a/core/java/android/webkit/TEST_MAPPING +++ b/core/java/android/webkit/TEST_MAPPING @@ -17,15 +17,6 @@ "exclude-annotation": "android.test.FlakyTest" } ] - }, - { - "name": "GtsWebViewHostTestCases", - "keywords": ["internal"], - "options": [ - { - "exclude-annotation": "android.test.FlakyTest" - } - ] } ] } diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 14b208aecf5c..ab7a4f289d73 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -1458,13 +1458,14 @@ public abstract class WebSettings { public abstract void setNeedInitialFocus(boolean flag); /** - * Sets the priority of the Render thread. Unlike the other settings, this + * Sets the CPU scheduling priority of the Render thread. Unlike the other settings, this * one only needs to be called once per process. The default value is * {@link RenderPriority#NORMAL}. * * @param priority the priority - * @deprecated It is not recommended to adjust thread priorities, and this will - * not be supported in future versions. + * @deprecated This is no longer supported. See {@link WebView#setRendererPriorityPolicy} if you + * instead want to control how freely the system should kill the renderer process + * under low memory conditions. */ @Deprecated public abstract void setRenderPriority(RenderPriority priority); diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index b6663992b851..5e22c287140a 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -2287,26 +2287,53 @@ public class WebView extends AbsoluteLayout public @interface RendererPriority {} /** - * The renderer associated with this WebView is bound with - * {@link Context#BIND_WAIVE_PRIORITY}. At this priority level - * {@link WebView} renderers will be strong targets for out of memory - * killing. + * This is the lowest binding priority for the WebView renderer process. This is equivalent to + * {@link Context#BIND_WAIVE_PRIORITY}. At this priority level {@link WebView} renderers will be + * frequent targets for being killed when the system is running low on memory. + * + * <p>If using this priority, we recommend handling the {@link + * WebViewClient#onRenderProcessGone} callback to recover from low memory kills as well as other + * types of renderer crashes. * - * Use with {@link #setRendererPriorityPolicy}. + * @see #setRendererPriorityPolicy + * @see #getRendererPriorityPolicy + * @see RenderProcessGoneDetail#rendererPriorityAtExit */ public static final int RENDERER_PRIORITY_WAIVED = 0; + /** - * The renderer associated with this WebView is bound with - * the default priority for services. + * This is the medium binding priority for the WebView renderer process. This is equivalent to + * the standard priority used by the system for calls to {@link + * Context#bindService(Intent,android.content.ServiceConnection,int)} when no flags are + * provided. At this priority level {@link WebView} renderers will be slightly more likely + * targets for being killed when the system is running low on memory. * - * Use with {@link #setRendererPriorityPolicy}. + * <p>If using this priority, we recommend handling the {@link + * WebViewClient#onRenderProcessGone} callback to recover from low memory kills as well as other + * types of renderer crashes. + * + * @see #setRendererPriorityPolicy + * @see #getRendererPriorityPolicy + * @see RenderProcessGoneDetail#rendererPriorityAtExit */ public static final int RENDERER_PRIORITY_BOUND = 1; + /** - * The renderer associated with this WebView is bound with - * {@link Context#BIND_IMPORTANT}. + * This is the highest binding priority for the WebView renderer process, and the default value + * WebView uses to bind to the renderer process. This is equivalent to {@link + * Context#BIND_IMPORTANT}. At this priority level {@link WebView} renderers are less likely to + * be killed when the system is running low on memory and will have the same priority as your + * app's main process. + * + * <p>It's still possible for the renderer process to be killed when the system is running low + * on memory, however specifying this priority makes this situation less likely. It's also still + * possible for the renderer process to crash for other reasons. You may optionally still choose + * to handle {@link WebViewClient#onRenderProcessGone} in order to recover from a killed or + * crashed renderer process. * - * Use with {@link #setRendererPriorityPolicy}. + * @see #setRendererPriorityPolicy + * @see #getRendererPriorityPolicy + * @see RenderProcessGoneDetail#rendererPriorityAtExit */ public static final int RENDERER_PRIORITY_IMPORTANT = 2; @@ -2316,7 +2343,7 @@ public class WebView extends AbsoluteLayout * process renderer should be considered to be a target for OOM * killing. * - * Because a renderer can be associated with more than one + * <p>Because a renderer can be associated with more than one * WebView, the final priority it is computed as the maximum of * any attached WebViews. When a WebView is destroyed it will * cease to be considerered when calculating the renderer @@ -2324,7 +2351,7 @@ public class WebView extends AbsoluteLayout * the priority of the renderer will be reduced to * {@link #RENDERER_PRIORITY_WAIVED}. * - * The default policy is to set the priority to + * <p>The default policy is to set the priority to * {@link #RENDERER_PRIORITY_IMPORTANT} regardless of visibility, * and this should not be changed unless the caller also handles * renderer crashes with @@ -2338,6 +2365,8 @@ public class WebView extends AbsoluteLayout * when this WebView is not visible, it will be treated as * if it had requested a priority of * {@link #RENDERER_PRIORITY_WAIVED}. + * @see #getRendererPriorityPolicy + * @see RenderProcessGoneDetail#rendererPriorityAtExit */ public void setRendererPriorityPolicy( @RendererPriority int rendererRequestedPriority, @@ -2349,6 +2378,8 @@ public class WebView extends AbsoluteLayout * Get the requested renderer priority for this WebView. * * @return the requested renderer priority policy. + * @see #setRendererPriorityPolicy + * @see RenderProcessGoneDetail#rendererPriorityAtExit */ @InspectableProperty(hasAttributeId = false, enumMapping = { @InspectableProperty.EnumEntry(name = "waived", value = RENDERER_PRIORITY_WAIVED), diff --git a/core/java/android/window/DesktopModeFlags.java b/core/java/android/window/DesktopModeFlags.java index e74a87536c57..696b7b8bb965 100644 --- a/core/java/android/window/DesktopModeFlags.java +++ b/core/java/android/window/DesktopModeFlags.java @@ -61,6 +61,8 @@ public enum DesktopModeFlags { ENABLE_DESKTOP_COMPAT_UI_VISIBILITY_STATUS(Flags::enableCompatUiVisibilityStatus, true), ENABLE_DESKTOP_INDICATOR_IN_SEPARATE_THREAD_BUGFIX( Flags::enableDesktopIndicatorInSeparateThreadBugfix, false), + ENABLE_DESKTOP_OPENING_DEEPLINK_MINIMIZE_ANIMATION_BUGFIX( + Flags::enableDesktopOpeningDeeplinkMinimizeAnimationBugfix, false), ENABLE_DESKTOP_RECENTS_TRANSITIONS_CORNERS_BUGFIX( Flags::enableDesktopRecentsTransitionsCornersBugfix, false), ENABLE_DESKTOP_SKIP_COMPAT_UI_EDUCATION_IN_DESKTOP_MODE_BUGFIX( @@ -112,6 +114,8 @@ public enum DesktopModeFlags { ENABLE_RESIZING_METRICS(Flags::enableResizingMetrics, true), ENABLE_RESTORE_TO_PREVIOUS_SIZE_FROM_DESKTOP_IMMERSIVE( Flags::enableRestoreToPreviousSizeFromDesktopImmersive, true), + ENABLE_SHELL_INITIAL_BOUNDS_REGRESSION_BUG_FIX( + Flags::enableShellInitialBoundsRegressionBugFix, false), ENABLE_START_LAUNCH_TRANSITION_FROM_TASKBAR_BUGFIX( Flags::enableStartLaunchTransitionFromTaskbarBugfix, true), ENABLE_TASKBAR_OVERFLOW(Flags::enableTaskbarOverflow, false), diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java index 63c55ad6a889..be4edc3b6ec5 100644 --- a/core/java/android/window/TransitionInfo.java +++ b/core/java/android/window/TransitionInfo.java @@ -29,6 +29,7 @@ import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; +import static android.view.WindowManager.TRANSIT_FLAG_AOD_APPEARING; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_NONE; @@ -375,7 +376,8 @@ public final class TransitionInfo implements Parcelable { */ public boolean hasChangesOrSideEffects() { return !mChanges.isEmpty() || isKeyguardGoingAway() - || (mFlags & TRANSIT_FLAG_KEYGUARD_APPEARING) != 0; + || (mFlags & TRANSIT_FLAG_KEYGUARD_APPEARING) != 0 + || (mFlags & TRANSIT_FLAG_AOD_APPEARING) != 0; } /** diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig index 355a87d72203..09f458be9bfa 100644 --- a/core/java/android/window/flags/lse_desktop_experience.aconfig +++ b/core/java/android/window/flags/lse_desktop_experience.aconfig @@ -38,6 +38,18 @@ flag { } flag { + name: "enable_shell_initial_bounds_regression_bug_fix" + namespace: "lse_desktop_experience" + description: "Enables fix for Shell initial bounds regression, forcing core to calculate /n" + "initial bounds in desktop launch params while respecting cascading position /n" + "passed by Shell." + bug: "396075922" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "enable_windowing_dynamic_initial_bounds" namespace: "lse_desktop_experience" description: "Enables new initial bounds for desktop windowing which adjust depending on app constraints" diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig index 9f768f065fe9..f2efa200918c 100644 --- a/core/java/android/window/flags/windowing_sdk.aconfig +++ b/core/java/android/window/flags/windowing_sdk.aconfig @@ -152,4 +152,15 @@ flag { metadata { purpose: PURPOSE_BUGFIX } -}
\ No newline at end of file +} + +flag { + namespace: "windowing_sdk" + name: "cleanup_dispatch_pending_transactions_remote_exception" + description: "Refactor to cleanup for RemoteException from dispatchPendingTransactions" + bug: "323801078" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/com/android/internal/config/appcloning/OWNERS b/core/java/com/android/internal/config/appcloning/OWNERS index 0645a8c54414..9369438deb07 100644 --- a/core/java/com/android/internal/config/appcloning/OWNERS +++ b/core/java/com/android/internal/config/appcloning/OWNERS @@ -1,3 +1,2 @@ # Bug component: 1207885 jigarthakkar@google.com -saumyap@google.com
\ No newline at end of file diff --git a/core/java/com/android/internal/infra/OWNERS b/core/java/com/android/internal/infra/OWNERS index 45503582b2c5..e69de29bb2d1 100644 --- a/core/java/com/android/internal/infra/OWNERS +++ b/core/java/com/android/internal/infra/OWNERS @@ -1,6 +0,0 @@ -per-file AndroidFuture.java = eugenesusla@google.com -per-file RemoteStream.java = eugenesusla@google.com -per-file PerUser.java = eugenesusla@google.com -per-file ServiceConnector.java = eugenesusla@google.com -per-file AndroidFuture.aidl = eugenesusla@google.com -per-file IAndroidFuture.aidl = eugenesusla@google.com
\ No newline at end of file diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java index 056a0e85ae97..81ca23173457 100644 --- a/core/java/com/android/internal/os/BatteryStatsHistory.java +++ b/core/java/com/android/internal/os/BatteryStatsHistory.java @@ -789,7 +789,7 @@ public class BatteryStatsHistory { */ public boolean readFragmentToParcel(Parcel out, BatteryHistoryFragment fragment) { byte[] data = mStore.readFragment(fragment); - if (data == null) { + if (data == null || data.length == 0) { return false; } out.unmarshall(data, 0, data.length); @@ -934,6 +934,10 @@ public class BatteryStatsHistory { continue; } + if (data.length == 0) { + continue; + } + out.writeBoolean(true); if (useBlobs) { out.writeBlob(data, 0, data.length); @@ -976,9 +980,11 @@ public class BatteryStatsHistory { return false; } - parcel.unmarshall(data, 0, data.length); - parcel.setDataPosition(0); - readHistoryBuffer(parcel); + if (data.length > 0) { + parcel.unmarshall(data, 0, data.length); + parcel.setDataPosition(0); + readHistoryBuffer(parcel); + } } catch (Exception e) { Slog.e(TAG, "Error reading battery history", e); reset(); diff --git a/core/java/com/android/internal/util/OWNERS b/core/java/com/android/internal/util/OWNERS index 9be8ea7aadc4..d174fe36e460 100644 --- a/core/java/com/android/internal/util/OWNERS +++ b/core/java/com/android/internal/util/OWNERS @@ -1,8 +1,8 @@ -per-file AsyncChannel* = lorenzo@google.com, satk@google.com, etancohen@google.com +per-file AsyncChannel* = lorenzo@google.com, satk@google.com per-file MessageUtils*, Protocol*, RingBuffer*, TokenBucket* = jchalard@google.com, lorenzo@google.com, satk@google.com per-file *Notification* = file:/services/core/java/com/android/server/notification/OWNERS per-file *ContrastColor* = file:/services/core/java/com/android/server/notification/OWNERS -per-file Protocol* = etancohen@google.com, lorenzo@google.com +per-file Protocol* =lorenzo@google.com per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com per-file *Dump* = file:/core/java/com/android/internal/util/dump/OWNERS per-file *Screenshot* = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS diff --git a/core/java/com/android/internal/util/function/pooled/OWNERS b/core/java/com/android/internal/util/function/pooled/OWNERS index da723b3b67da..e69de29bb2d1 100644 --- a/core/java/com/android/internal/util/function/pooled/OWNERS +++ b/core/java/com/android/internal/util/function/pooled/OWNERS @@ -1 +0,0 @@ -eugenesusla@google.com
\ No newline at end of file diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java index 453a0755ec5b..2cca3dbc4f2f 100644 --- a/core/java/com/android/internal/widget/ConversationLayout.java +++ b/core/java/com/android/internal/widget/ConversationLayout.java @@ -86,6 +86,7 @@ public class ConversationLayout extends FrameLayout public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f); public static final Interpolator OVERSHOOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f); + private static final int MAX_SUMMARIZATION_LINES = 3; public static final int IMPORTANCE_ANIM_GROW_DURATION = 250; public static final int IMPORTANCE_ANIM_SHRINK_DURATION = 200; public static final int IMPORTANCE_ANIM_SHRINK_DELAY = 25; @@ -401,7 +402,7 @@ public class ConversationLayout extends FrameLayout public void setIsCollapsed(boolean isCollapsed) { mIsCollapsed = isCollapsed; mMessagingLinearLayout.setMaxDisplayedLines(isCollapsed - ? TextUtils.isEmpty(mSummarizedContent) ? 1 : 2 + ? TextUtils.isEmpty(mSummarizedContent) ? 1 : MAX_SUMMARIZATION_LINES : Integer.MAX_VALUE); updateExpandButton(); updateContentEndPaddings(); diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java index f2099bc76109..9fe2de82adee 100644 --- a/core/java/com/android/internal/widget/MessagingLayout.java +++ b/core/java/com/android/internal/widget/MessagingLayout.java @@ -63,6 +63,7 @@ public class MessagingLayout extends FrameLayout public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f); public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f); + private static final int MAX_SUMMARIZATION_LINES = 3; public static final OnLayoutChangeListener MESSAGING_PROPERTY_ANIMATOR = new MessagingPropertyAnimator(); private final PeopleHelper mPeopleHelper = new PeopleHelper(); @@ -223,7 +224,7 @@ public class MessagingLayout extends FrameLayout List<MessagingMessage> newMessagingMessages; mSummarizedContent = extras.getCharSequence(Notification.EXTRA_SUMMARIZED_CONTENT); if (!TextUtils.isEmpty(mSummarizedContent) && mIsCollapsed) { - mMessagingLinearLayout.setMaxDisplayedLines(2); + mMessagingLinearLayout.setMaxDisplayedLines(MAX_SUMMARIZATION_LINES); Notification.MessagingStyle.Message summary = new Notification.MessagingStyle.Message(mSummarizedContent, 0, ""); newMessagingMessages = createMessages(List.of(summary), false, usePrecomputedText); diff --git a/core/java/com/android/internal/widget/remotecompose/OWNERS b/core/java/com/android/internal/widget/remotecompose/OWNERS index e163474bccb9..c606744df150 100644 --- a/core/java/com/android/internal/widget/remotecompose/OWNERS +++ b/core/java/com/android/internal/widget/remotecompose/OWNERS @@ -1,6 +1,5 @@ nicolasroard@google.com hoford@google.com -jnichol@google.com sihua@google.com sunnygoyal@google.com oscarad@google.com diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 92a841f9c290..748c5b48534f 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -21,7 +21,6 @@ soong_config_module_type { config_namespace: "ANDROID", bool_variables: [ "release_binder_death_recipient_weak_from_jni", - "release_package_libandroid_runtime_punch_holes", ], properties: [ "cflags", @@ -66,9 +65,6 @@ cc_library_shared_for_libandroid_runtime { release_binder_death_recipient_weak_from_jni: { cflags: ["-DBINDER_DEATH_RECIPIENT_WEAK_FROM_JNI"], }, - release_package_libandroid_runtime_punch_holes: { - cflags: ["-DENABLE_PUNCH_HOLES"], - }, }, cpp_std: "gnu++20", diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index 06fd80e37669..14132e61ff0e 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -236,7 +236,6 @@ static install_status_t extractNativeLibFromApk(ZipFileRO* zipFile, ZipEntryRO z return INSTALL_FAILED_CONTAINER_ERROR; } -#ifdef ENABLE_PUNCH_HOLES // punch extracted elf files as well. This will fail where compression is on (like f2fs) but it // will be useful for ext4 based systems struct statfs64 fsInfo; @@ -253,7 +252,6 @@ static install_status_t extractNativeLibFromApk(ZipFileRO* zipFile, ZipEntryRO z zipFile->getZipFileName()); } } -#endif // ENABLE_PUNCH_HOLES ALOGV("Successfully moved %s to %s\n", localTmpFileName, localFileName); @@ -332,7 +330,6 @@ static install_status_t copyFileIfChanged(JNIEnv* env, void* arg, ZipFileRO* zip return INSTALL_FAILED_INVALID_APK; } -#ifdef ENABLE_PUNCH_HOLES // if library is uncompressed, punch hole in it in place if (!punchHolesInElf64(zipFile->getZipFileName(), offset)) { ALOGW("Failed to punch uncompressed elf file :%s inside apk : %s at offset: " @@ -345,7 +342,6 @@ static install_status_t copyFileIfChanged(JNIEnv* env, void* arg, ZipFileRO* zip if (!punchHolesInZip(zipFile->getZipFileName(), offset, extraFieldLength)) { ALOGW("Failed to punch apk : %s at extra field", zipFile->getZipFileName()); } -#endif // ENABLE_PUNCH_HOLES return INSTALL_SUCCEEDED; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index ee6899cf866b..e16ce9849ff2 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -8995,13 +8995,13 @@ <!-- @SystemApi @FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled") - This permission is required to access the specific text classifier you need from the + This permission is required to access the specific text classifier from the TextClassificationManager. - <p>Protection level: signature|role + <p>Protection level: signature|role|privileged @hide --> <permission android:name="android.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE" - android:protectionLevel="signature|role" + android:protectionLevel="signature|role|privileged" android:featureFlag="android.permission.flags.text_classifier_choice_api_enabled"/> <!-- Attribution for Geofencing service. --> diff --git a/core/res/OWNERS b/core/res/OWNERS index faed4d80f39b..a208f7f1a3ad 100644 --- a/core/res/OWNERS +++ b/core/res/OWNERS @@ -9,7 +9,6 @@ hackbod@google.com ilyamaty@google.com jbolinger@google.com jsharkey@android.com -jsharkey@google.com juliacr@google.com kchyn@google.com michaelwr@google.com diff --git a/core/res/res/layout/accessibility_autoclick_type_panel.xml b/core/res/res/layout/accessibility_autoclick_type_panel.xml index cedbdc175488..902ef7fc38e8 100644 --- a/core/res/res/layout/accessibility_autoclick_type_panel.xml +++ b/core/res/res/layout/accessibility_autoclick_type_panel.xml @@ -17,7 +17,7 @@ */ --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +<com.android.server.accessibility.autoclick.AutoclickLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/accessibility_autoclick_type_panel" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -130,4 +130,4 @@ </LinearLayout> -</LinearLayout> +</com.android.server.accessibility.autoclick.AutoclickLinearLayout> diff --git a/core/res/res/values/locale_config.xml b/core/res/res/values/locale_config.xml index 77d2e873682f..0efa1bcbf975 100644 --- a/core/res/res/values/locale_config.xml +++ b/core/res/res/values/locale_config.xml @@ -163,15 +163,18 @@ <item>en-CM</item> <!-- English (Cameroon) --> <item>en-CX</item> <!-- English (Christmas Island) --> <item>en-CY</item> <!-- English (Cyprus) --> + <item>en-CZ</item> <!-- English (Czechia) --> <item>en-DE</item> <!-- English (Germany) --> <item>en-DG</item> <!-- English (Diego Garcia) --> <item>en-DK</item> <!-- English (Denmark) --> <item>en-DM</item> <!-- English (Dominica) --> <item>en-ER</item> <!-- English (Eritrea) --> + <item>en-ES</item> <!-- English (Spain) --> <item>en-FI</item> <!-- English (Finland) --> <item>en-FJ</item> <!-- English (Fiji) --> <item>en-FK</item> <!-- English (Falkland Islands (Islas Malvinas)) --> <item>en-FM</item> <!-- English (Micronesia) --> + <item>en-FR</item> <!-- English (France) --> <item>en-GB</item> <!-- English (United Kingdom) --> <item>en-GD</item> <!-- English (Grenada) --> <item>en-GG</item> <!-- English (Guernsey) --> @@ -181,12 +184,14 @@ <item>en-GU</item> <!-- English (Guam) --> <item>en-GY</item> <!-- English (Guyana) --> <item>en-HK</item> <!-- English (Hong Kong) --> + <item>en-HU</item> <!-- English (Hungary) --> <item>en-ID</item> <!-- English (Indonesia) --> <item>en-IE</item> <!-- English (Ireland) --> <item>en-IL</item> <!-- English (Israel) --> <item>en-IM</item> <!-- English (Isle of Man) --> <item>en-IN</item> <!-- English (India) --> <item>en-IO</item> <!-- English (British Indian Ocean Territory) --> + <item>en-IT</item> <!-- English (Italy) --> <item>en-JE</item> <!-- English (Jersey) --> <item>en-JM</item> <!-- English (Jamaica) --> <item>en-KE</item> <!-- English (Kenya) --> @@ -210,15 +215,19 @@ <item>en-NF</item> <!-- English (Norfolk Island) --> <item>en-NG</item> <!-- English (Nigeria) --> <item>en-NL</item> <!-- English (Netherlands) --> + <item>en-NO</item> <!-- English (Norway) --> <item>en-NR</item> <!-- English (Nauru) --> <item>en-NU</item> <!-- English (Niue) --> <item>en-NZ</item> <!-- English (New Zealand) --> <item>en-PG</item> <!-- English (Papua New Guinea) --> <item>en-PH</item> <!-- English (Philippines) --> <item>en-PK</item> <!-- English (Pakistan) --> + <item>en-PL</item> <!-- English (Poland) --> <item>en-PN</item> <!-- English (Pitcairn Islands) --> <item>en-PR</item> <!-- English (Puerto Rico) --> + <item>en-PT</item> <!-- English (Portugal) --> <item>en-PW</item> <!-- English (Palau) --> + <item>en-RO</item> <!-- English (Romania) --> <item>en-RW</item> <!-- English (Rwanda) --> <item>en-SB</item> <!-- English (Solomon Islands) --> <item>en-SC</item> <!-- English (Seychelles) --> @@ -227,6 +236,7 @@ <item>en-SG</item> <!-- English (Singapore) --> <item>en-SH</item> <!-- English (St. Helena) --> <item>en-SI</item> <!-- English (Slovenia) --> + <item>en-SK</item> <!-- English (Slovakia) --> <item>en-SL</item> <!-- English (Sierra Leone) --> <item>en-SS</item> <!-- English (South Sudan) --> <item>en-SX</item> <!-- English (Sint Maarten) --> diff --git a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java index ac78e87aa60d..f75a72d635dd 100644 --- a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java +++ b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java @@ -414,16 +414,23 @@ public class PropertyInvalidatedCacheTests { @Test @DisabledOnRavenwood(reason = "SystemProperties doesn't have permission check") public void testPermissionFailure() { - // Create a cache that will write a system nonce. - TestCache sysCache = new TestCache(MODULE_SYSTEM, "mode1"); try { - // Invalidate the cache, which writes the system property. There must be a permission - // failure. - sysCache.invalidateCache(); - fail("expected permission failure"); - } catch (RuntimeException e) { - // The expected exception is a bare RuntimeException. The test does not attempt to - // validate the text of the exception message. + // Disable the test mode for this test, but ensure that it will be enabled when the + // test exits. + PropertyInvalidatedCache.setTestMode(false); + // Create a cache that will write a system nonce. + TestCache sysCache = new TestCache(MODULE_SYSTEM, "mode1"); + try { + // Invalidate the cache, which writes the system property. There must be a + // permission failure. + sysCache.invalidateCache(); + fail("expected permission failure"); + } catch (RuntimeException e) { + // The expected exception is a bare RuntimeException. The test does not attempt + // to validate the text of the exception message. + } + } finally { + PropertyInvalidatedCache.setTestMode(true); } } diff --git a/core/tests/coretests/src/android/content/pm/OWNERS b/core/tests/coretests/src/android/content/pm/OWNERS index 867336515ce3..c4c40dcaa87a 100644 --- a/core/tests/coretests/src/android/content/pm/OWNERS +++ b/core/tests/coretests/src/android/content/pm/OWNERS @@ -1,5 +1,4 @@ include /core/java/android/content/pm/OWNERS per-file AppSearchPersonTest.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS -per-file SigningDetailsTest.java = cbrubaker@google.com per-file SigningDetailsTest.java = mpgroover@google.com diff --git a/core/tests/coretests/src/android/os/IpcDataCacheTest.java b/core/tests/coretests/src/android/os/IpcDataCacheTest.java index 74b32a17d964..791ec5d0cea3 100644 --- a/core/tests/coretests/src/android/os/IpcDataCacheTest.java +++ b/core/tests/coretests/src/android/os/IpcDataCacheTest.java @@ -452,22 +452,28 @@ public class IpcDataCacheTest { assertTrue(ec.isDisabled()); } - // Verify that invalidating the cache from an app process would fail due to lack of permissions. @Test @android.platform.test.annotations.DisabledOnRavenwood( reason = "SystemProperties doesn't have permission check") public void testPermissionFailure() { - // Create a cache that will write a system nonce. - TestCache sysCache = new TestCache(IpcDataCache.MODULE_SYSTEM, "mode1"); try { - // Invalidate the cache, which writes the system property. There must be a permission - // failure. - sysCache.invalidateCache(); - fail("expected permission failure"); - } catch (RuntimeException e) { - // The expected exception is a bare RuntimeException. The test does not attempt to - // validate the text of the exception message. + // Disable test mode for this test. Guarantee that the mode is enabled before the + // test exits. + IpcDataCache.setTestMode(false); + // Create a cache that will write a system nonce. + TestCache sysCache = new TestCache(IpcDataCache.MODULE_SYSTEM, "mode1"); + try { + // Invalidate the cache, which writes the system property. There must be a + // permission failure. + sysCache.invalidateCache(); + fail("expected permission failure"); + } catch (RuntimeException e) { + // The expected exception is a bare RuntimeException. The test does not attempt + // to validate the text of the exception message. + } + } finally { + IpcDataCache.setTestMode(true); } } diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java index f5d1e7a85e83..39f3d3319ad3 100644 --- a/core/tests/coretests/src/android/view/ViewRootImplTest.java +++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java @@ -16,6 +16,8 @@ package android.view; +import static android.app.UiModeManager.MODE_NIGHT_NO; +import static android.app.UiModeManager.MODE_NIGHT_YES; import static android.util.SequenceUtils.getInitSeq; import static android.view.HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING; import static android.view.InputDevice.SOURCE_ROTARY_ENCODER; @@ -67,8 +69,10 @@ import static org.junit.Assume.assumeTrue; import android.annotation.NonNull; import android.app.Instrumentation; import android.app.UiModeManager; +import android.app.UiModeManager.ForceInvertType; import android.content.Context; import android.graphics.ForceDarkType; +import android.graphics.ForceDarkType.ForceDarkTypeDef; import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; import android.os.Binder; @@ -93,9 +97,12 @@ import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; import com.android.compatibility.common.util.ShellIdentityUtils; +import com.android.compatibility.common.util.TestUtils; import com.android.cts.input.BlockingQueueEventVerifier; import com.android.window.flags.Flags; +import com.google.common.truth.Expect; + import org.hamcrest.Matcher; import org.junit.After; import org.junit.AfterClass; @@ -124,6 +131,8 @@ public class ViewRootImplTest { @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Rule + public final Expect mExpect = Expect.create(); private ViewRootImpl mViewRootImpl; private View mView; @@ -1507,49 +1516,34 @@ public class ViewRootImplTest { } @Test - public void forceInvertOffDarkThemeOff_forceDarkModeDisabled() { - mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR); - ShellIdentityUtils.invokeWithShellPermissions(() -> { - Settings.Secure.putInt( - sContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED, - /* value= */ 0 - ); - var uiModeManager = sContext.getSystemService(UiModeManager.class); - uiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO); - }); - - sInstrumentation.runOnMainSync(() -> - mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId()) - ); - - assertThat(mViewRootImpl.determineForceDarkType()).isEqualTo(ForceDarkType.NONE); - } - - @Test - public void forceInvertOnDarkThemeOff_forceDarkModeEnabled() { - mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR); - ShellIdentityUtils.invokeWithShellPermissions(() -> { - Settings.Secure.putInt( - sContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED, - /* value= */ 1 - ); - var uiModeManager = sContext.getSystemService(UiModeManager.class); - uiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO); - }); - - sInstrumentation.runOnMainSync(() -> - mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId()) - ); - - assertThat(mViewRootImpl.determineForceDarkType()) - .isEqualTo(ForceDarkType.FORCE_INVERT_COLOR_DARK); + @RequiresFlagsEnabled(FLAG_FORCE_INVERT_COLOR) + public void updateConfiguration_returnsExpectedForceDarkMode() { + waitForSystemNightModeActivated(true); + + verifyForceDarkType(/* isAppInNightMode= */ true, /* isForceInvertEnabled= */ true, + UiModeManager.FORCE_INVERT_TYPE_DARK, ForceDarkType.FORCE_INVERT_COLOR_DARK); + verifyForceDarkType(/* isAppInNightMode= */ true, /* isForceInvertEnabled= */ false, + UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE); + verifyForceDarkType(/* isAppInNightMode= */ false, /* isForceInvertEnabled= */ true, + UiModeManager.FORCE_INVERT_TYPE_DARK, ForceDarkType.FORCE_INVERT_COLOR_DARK); + verifyForceDarkType(/* isAppInNightMode= */ false, /* isForceInvertEnabled= */ false, + UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE); + + waitForSystemNightModeActivated(false); + + verifyForceDarkType(/* isAppInNightMode= */ true, /* isForceInvertEnabled= */ true, + UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE); + verifyForceDarkType(/* isAppInNightMode= */ true, /* isForceInvertEnabled= */ false, + UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE); + verifyForceDarkType(/* isAppInNightMode= */ false, /* isForceInvertEnabled= */ true, + UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE); + verifyForceDarkType(/* isAppInNightMode= */ false, /* isForceInvertEnabled= */ false, + UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE); } @Test + @EnableFlags(FLAG_FORCE_INVERT_COLOR) public void forceInvertOffForceDarkOff_forceDarkModeDisabled() { - mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR); ShellIdentityUtils.invokeWithShellPermissions(() -> { Settings.Secure.putInt( sContext.getContentResolver(), @@ -1562,15 +1556,14 @@ public class ViewRootImplTest { }); sInstrumentation.runOnMainSync(() -> - mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId()) - ); + mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())); assertThat(mViewRootImpl.determineForceDarkType()).isEqualTo(ForceDarkType.NONE); } @Test + @EnableFlags(FLAG_FORCE_INVERT_COLOR) public void forceInvertOffForceDarkOn_forceDarkModeEnabled() { - mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR); ShellIdentityUtils.invokeWithShellPermissions(() -> { Settings.Secure.putInt( sContext.getContentResolver(), @@ -1582,8 +1575,7 @@ public class ViewRootImplTest { }); sInstrumentation.runOnMainSync(() -> - mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId()) - ); + mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())); assertThat(mViewRootImpl.determineForceDarkType()).isEqualTo(ForceDarkType.FORCE_DARK); } @@ -1790,4 +1782,39 @@ public class ViewRootImplTest { () -> view.getViewTreeObserver().removeOnDrawListener(listener)); } } + + private void waitForSystemNightModeActivated(boolean active) { + ShellIdentityUtils.invokeWithShellPermissions(() -> + sInstrumentation.runOnMainSync(() -> { + var uiModeManager = sContext.getSystemService(UiModeManager.class); + uiModeManager.setNightModeActivated(active); + })); + sInstrumentation.waitForIdleSync(); + } + + private void verifyForceDarkType(boolean isAppInNightMode, boolean isForceInvertEnabled, + @ForceInvertType int expectedForceInvertType, + @ForceDarkTypeDef int expectedForceDarkType) { + var uiModeManager = sContext.getSystemService(UiModeManager.class); + ShellIdentityUtils.invokeWithShellPermissions(() -> { + uiModeManager.setApplicationNightMode( + isAppInNightMode ? MODE_NIGHT_YES : MODE_NIGHT_NO); + Settings.Secure.putInt( + sContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED, + isForceInvertEnabled ? 1 : 0); + }); + + sInstrumentation.runOnMainSync(() -> + mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())); + try { + TestUtils.waitUntil("Waiting for force invert state changed", + () -> (uiModeManager.getForceInvertState() == expectedForceInvertType)); + } catch (Exception e) { + Log.e(TAG, "Unexpected error trying to apply force invert state. " + e); + e.printStackTrace(); + } + + mExpect.that(mViewRootImpl.determineForceDarkType()).isEqualTo(expectedForceDarkType); + } } diff --git a/core/tests/featureflagtests/OWNERS b/core/tests/featureflagtests/OWNERS index 2ff4f5ab8807..6784f2891009 100644 --- a/core/tests/featureflagtests/OWNERS +++ b/core/tests/featureflagtests/OWNERS @@ -1,2 +1 @@ -sbasi@google.com -tmfang@google.com
\ No newline at end of file +tmfang@google.com diff --git a/data/etc/OWNERS b/data/etc/OWNERS index 712042f6ff6b..1251fce1ce19 100644 --- a/data/etc/OWNERS +++ b/data/etc/OWNERS @@ -1,6 +1,5 @@ include /PACKAGE_MANAGER_OWNERS -cbrubaker@google.com hackbod@android.com hackbod@google.com jeffv@google.com diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 15f70298198f..9234902335c1 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -619,6 +619,8 @@ applications that come with the platform <permission name="android.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE"/> <permission name="android.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE"/> <permission name="android.permission.READ_COLOR_ZONES"/> + <!-- Permission required for CTS test - CtsTextClassifierTestCases --> + <permission name="android.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE"/> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> diff --git a/drm/java/android/drm/OWNERS b/drm/java/android/drm/OWNERS index 43871001c9ad..b65cce70225e 100644 --- a/drm/java/android/drm/OWNERS +++ b/drm/java/android/drm/OWNERS @@ -1,4 +1,3 @@ # Bug component: 49079 -jtinker@google.com robertshih@google.com diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index a0ca0988e03c..05e23a08481f 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -2206,26 +2206,21 @@ public class Paint { * @param fontVariationOverride font variation override. You can pass null or empty string for * clearing font variation override. * - * @return true if the provided font variation settings is valid. Otherwise returns false. - * + * @throws IllegalArgumentException If given string is not a valid font variation settings + * format * @see #getFontVariationSettings() * @see #setFontVariationSettings(String) * @see #getFontVariationOverride() * @see FontVariationAxis */ @FlaggedApi(FLAG_TYPEFACE_REDESIGN_READONLY) - public boolean setFontVariationOverride(@Nullable String fontVariationOverride) { + public void setFontVariationOverride(@Nullable String fontVariationOverride) { if (Objects.equals(fontVariationOverride, mFontVariationOverride)) { - return true; + return; } - List<FontVariationAxis> axes; - try { - axes = FontVariationAxis.fromFontVariationSettingsForList(fontVariationOverride); - } catch (IllegalArgumentException e) { - Log.i(TAG, "failed to parse font variation settings.", e); - return false; - } + List<FontVariationAxis> axes = + FontVariationAxis.fromFontVariationSettingsForList(fontVariationOverride); long builderPtr = nCreateFontVariationBuilder(axes.size()); for (int i = 0; i < axes.size(); ++i) { FontVariationAxis axis = axes.get(i); @@ -2234,7 +2229,6 @@ public class Paint { } nSetFontVariationOverride(mNativePaint, builderPtr); mFontVariationOverride = fontVariationOverride; - return true; } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/OWNERS index 6207e5b020f7..7e557860365e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/OWNERS +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/OWNERS @@ -4,5 +4,4 @@ madym@google.com mattsziklay@google.com mdehaini@google.com pbdr@google.com -tkachenkoi@google.com vaniadesmonda@google.com diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index 305fcdd5fb7d..be2240286ab1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -117,6 +117,7 @@ import com.android.wm.shell.shared.annotations.ShellBackgroundThread; import com.android.wm.shell.shared.annotations.ShellMainThread; import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper; import com.android.wm.shell.shared.bubbles.BubbleBarLocation; +import com.android.wm.shell.shared.bubbles.BubbleBarLocation.UpdateSource; import com.android.wm.shell.shared.bubbles.BubbleBarUpdate; import com.android.wm.shell.shared.bubbles.BubbleDropTargetBoundsProvider; import com.android.wm.shell.shared.bubbles.DeviceConfig; @@ -795,7 +796,7 @@ public class BubbleController implements ConfigurationChangeListener, * Update bubble bar location and trigger and update to listeners */ public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation, - @BubbleBarLocation.UpdateSource int source) { + @UpdateSource int source) { if (isShowingAsBubbleBar()) { updateExpandedViewForBubbleBarLocation(bubbleBarLocation, source); BubbleBarUpdate bubbleBarUpdate = new BubbleBarUpdate(); @@ -805,7 +806,7 @@ public class BubbleController implements ConfigurationChangeListener, } private void updateExpandedViewForBubbleBarLocation(BubbleBarLocation bubbleBarLocation, - @BubbleBarLocation.UpdateSource int source) { + @UpdateSource int source) { if (isShowingAsBubbleBar()) { BubbleBarLocation previousLocation = mBubblePositioner.getBubbleBarLocation(); mBubblePositioner.setBubbleBarLocation(bubbleBarLocation); @@ -818,7 +819,7 @@ public class BubbleController implements ConfigurationChangeListener, private void logBubbleBarLocationIfChanged(BubbleBarLocation location, BubbleBarLocation previous, - @BubbleBarLocation.UpdateSource int source) { + @UpdateSource int source) { if (mLayerView == null) { return; } @@ -830,25 +831,25 @@ public class BubbleController implements ConfigurationChangeListener, return; } switch (source) { - case BubbleBarLocation.UpdateSource.DRAG_BAR: - case BubbleBarLocation.UpdateSource.A11Y_ACTION_BAR: + case UpdateSource.DRAG_BAR: + case UpdateSource.A11Y_ACTION_BAR: mLogger.log(onLeft ? BubbleLogger.Event.BUBBLE_BAR_MOVED_LEFT_DRAG_BAR : BubbleLogger.Event.BUBBLE_BAR_MOVED_RIGHT_DRAG_BAR); break; - case BubbleBarLocation.UpdateSource.DRAG_BUBBLE: - case BubbleBarLocation.UpdateSource.A11Y_ACTION_BUBBLE: + case UpdateSource.DRAG_BUBBLE: + case UpdateSource.A11Y_ACTION_BUBBLE: mLogger.log(onLeft ? BubbleLogger.Event.BUBBLE_BAR_MOVED_LEFT_DRAG_BUBBLE : BubbleLogger.Event.BUBBLE_BAR_MOVED_RIGHT_DRAG_BUBBLE); break; - case BubbleBarLocation.UpdateSource.DRAG_EXP_VIEW: - case BubbleBarLocation.UpdateSource.A11Y_ACTION_EXP_VIEW: + case UpdateSource.DRAG_EXP_VIEW: + case UpdateSource.A11Y_ACTION_EXP_VIEW: // TODO(b/349845968): move logging from BubbleBarLayerView to here break; - case BubbleBarLocation.UpdateSource.APP_ICON_DRAG: + case UpdateSource.APP_ICON_DRAG: mLogger.log(onLeft ? BubbleLogger.Event.BUBBLE_BAR_MOVED_LEFT_APP_ICON_DROP : BubbleLogger.Event.BUBBLE_BAR_MOVED_RIGHT_APP_ICON_DROP); break; - case BubbleBarLocation.UpdateSource.DRAG_TASK: + case UpdateSource.DRAG_TASK: mLogger.log(onLeft ? BubbleLogger.Event.BUBBLE_BAR_MOVED_LEFT_DRAG_TASK : BubbleLogger.Event.BUBBLE_BAR_MOVED_RIGHT_DRAG_TASK); break; @@ -872,10 +873,7 @@ public class BubbleController implements ConfigurationChangeListener, if (bubbleBarLocation == null) return; if (isShowingAsBubbleBar() && BubbleAnythingFlagHelper.enableCreateAnyBubble()) { mBubbleStateListener.onDragItemOverBubbleBarDragZone(bubbleBarLocation); - ensureBubbleViewsAndWindowCreated(); - if (mLayerView != null) { - mLayerView.showBubbleBarExtendedViewDropTarget(bubbleBarLocation); - } + showBubbleBarExpandedViewDropTarget(bubbleBarLocation); } } @@ -921,6 +919,13 @@ public class BubbleController implements ConfigurationChangeListener, return result; } + private void showBubbleBarExpandedViewDropTarget(BubbleBarLocation bubbleBarLocation) { + ensureBubbleViewsAndWindowCreated(); + if (mLayerView != null) { + mLayerView.showBubbleBarExtendedViewDropTarget(bubbleBarLocation); + } + } + private void hideBubbleBarExpandedViewDropTarget() { if (mLayerView != null) { mLayerView.hideBubbleBarExpandedViewDropTarget(); @@ -1541,20 +1546,9 @@ public class BubbleController implements ConfigurationChangeListener, public void expandStackAndSelectBubble(ShortcutInfo info, @Nullable BubbleBarLocation bubbleBarLocation) { if (!BubbleAnythingFlagHelper.enableCreateAnyBubble()) return; - BubbleBarLocation updateLocation = isShowingAsBubbleBar() ? bubbleBarLocation : null; - if (updateLocation != null) { - updateExpandedViewForBubbleBarLocation(updateLocation, - BubbleBarLocation.UpdateSource.APP_ICON_DRAG); - } Bubble b = mBubbleData.getOrCreateBubble(info); // Removes from overflow ProtoLog.v(WM_SHELL_BUBBLES, "expandStackAndSelectBubble - shortcut=%s", info); - if (b.isInflated()) { - mBubbleData.setSelectedBubbleAndExpandStack(b, updateLocation); - } else { - b.enable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE); - inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false, - updateLocation); - } + expandStackAndSelectAppBubble(b, bubbleBarLocation, UpdateSource.APP_ICON_DRAG); } /** @@ -1562,16 +1556,12 @@ public class BubbleController implements ConfigurationChangeListener, * * @param intent the intent for the bubble. */ - public void expandStackAndSelectBubble(Intent intent, UserHandle user) { + public void expandStackAndSelectBubble(Intent intent, UserHandle user, + @Nullable BubbleBarLocation bubbleBarLocation) { if (!BubbleAnythingFlagHelper.enableCreateAnyBubble()) return; Bubble b = mBubbleData.getOrCreateBubble(intent, user); // Removes from overflow ProtoLog.v(WM_SHELL_BUBBLES, "expandStackAndSelectBubble - intent=%s", intent); - if (b.isInflated()) { - mBubbleData.setSelectedBubbleAndExpandStack(b); - } else { - b.enable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE); - inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false); - } + expandStackAndSelectAppBubble(b, bubbleBarLocation, UpdateSource.APP_ICON_DRAG); } /** @@ -1583,14 +1573,19 @@ public class BubbleController implements ConfigurationChangeListener, public void expandStackAndSelectBubble(PendingIntent pendingIntent, UserHandle user, @Nullable BubbleBarLocation bubbleBarLocation) { if (!BubbleAnythingFlagHelper.enableCreateAnyBubble()) return; + Bubble b = mBubbleData.getOrCreateBubble(pendingIntent, user); // Removes from overflow + ProtoLog.v(WM_SHELL_BUBBLES, "expandStackAndSelectBubble - pendingIntent=%s", + pendingIntent); + expandStackAndSelectAppBubble(b, bubbleBarLocation, UpdateSource.APP_ICON_DRAG); + } + + private void expandStackAndSelectAppBubble(Bubble b, + @Nullable BubbleBarLocation bubbleBarLocation, @UpdateSource int source) { + if (!BubbleAnythingFlagHelper.enableCreateAnyBubble()) return; BubbleBarLocation updateLocation = isShowingAsBubbleBar() ? bubbleBarLocation : null; if (updateLocation != null) { - updateExpandedViewForBubbleBarLocation(updateLocation, - BubbleBarLocation.UpdateSource.APP_ICON_DRAG); + updateExpandedViewForBubbleBarLocation(updateLocation, source); } - Bubble b = mBubbleData.getOrCreateBubble(pendingIntent, user); - ProtoLog.v(WM_SHELL_BUBBLES, "expandStackAndSelectBubble - pendingIntent=%s", - pendingIntent); if (b.isInflated()) { mBubbleData.setSelectedBubbleAndExpandStack(b, updateLocation); } else { @@ -1623,7 +1618,7 @@ public class BubbleController implements ConfigurationChangeListener, } } else { if (location != null) { - setBubbleBarLocation(location, BubbleBarLocation.UpdateSource.DRAG_TASK); + setBubbleBarLocation(location, UpdateSource.DRAG_TASK); } b.enable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE); // Lazy init stack view when a bubble is created @@ -2840,14 +2835,16 @@ public class BubbleController implements ConfigurationChangeListener, } @Override - public void showShortcutBubble(ShortcutInfo info) { + public void showShortcutBubble(ShortcutInfo info, @Nullable BubbleBarLocation location) { mMainExecutor.execute(() -> mController - .expandStackAndSelectBubble(info, /* bubbleBarLocation = */ null)); + .expandStackAndSelectBubble(info, location)); } @Override - public void showAppBubble(Intent intent, UserHandle user) { - mMainExecutor.execute(() -> mController.expandStackAndSelectBubble(intent, user)); + public void showAppBubble(Intent intent, UserHandle user, + @Nullable BubbleBarLocation location) { + mMainExecutor.execute( + () -> mController.expandStackAndSelectBubble(intent, user, location)); } @Override @@ -2900,7 +2897,7 @@ public class BubbleController implements ConfigurationChangeListener, @Override public void setBubbleBarLocation(BubbleBarLocation location, - @BubbleBarLocation.UpdateSource int source) { + @UpdateSource int source) { mMainExecutor.execute(() -> mController.setBubbleBarLocation(location, source)); } @@ -2921,6 +2918,17 @@ public class BubbleController implements ConfigurationChangeListener, } }); } + + @Override + public void showDropTarget(boolean show, BubbleBarLocation location) { + mMainExecutor.execute(() -> { + if (show) { + showBubbleBarExpandedViewDropTarget(location); + } else { + hideBubbleBarExpandedViewDropTarget(); + } + }); + } } private class BubblesImpl implements Bubbles { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl index 0a4d79a6c297..ae1b4077098d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl @@ -51,9 +51,11 @@ interface IBubbles { oneway void stopBubbleDrag(in BubbleBarLocation location, in int topOnScreen) = 11; - oneway void showShortcutBubble(in ShortcutInfo info) = 12; + oneway void showShortcutBubble(in ShortcutInfo info, in @nullable BubbleBarLocation location) = 12; - oneway void showAppBubble(in Intent intent, in UserHandle user) = 13; + oneway void showAppBubble(in Intent intent, in UserHandle user, in @nullable BubbleBarLocation location) = 13; oneway void showExpandedView() = 14; + + oneway void showDropTarget(in boolean show, in @nullable BubbleBarLocation location) = 15; }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java index b507ca2019a9..3f21e74a7d03 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java @@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import android.app.ActivityManager; +import android.window.DesktopExperienceFlags; import android.window.DisplayAreaInfo; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; @@ -67,7 +68,7 @@ public class PipDesktopState { /** Returns whether PiP in Connected Displays is enabled by checking the flag. */ public boolean isConnectedDisplaysPipEnabled() { - return Flags.enableConnectedDisplaysPip(); + return DesktopExperienceFlags.ENABLE_CONNECTED_DISPLAYS_PIP.isTrue(); } /** Returns whether the display with the PiP task is in freeform windowing mode. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMinimizationTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMinimizationTransitionHandler.kt index 7074e8bc9cce..6c6d830e915e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMinimizationTransitionHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMinimizationTransitionHandler.kt @@ -21,6 +21,7 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.os.Handler import android.os.IBinder import android.view.SurfaceControl.Transaction +import android.view.WindowManager.TRANSIT_TO_BACK import android.window.TransitionInfo import android.window.TransitionRequestInfo import android.window.WindowContainerTransaction @@ -61,7 +62,9 @@ class DesktopMinimizationTransitionHandler( finishTransaction: Transaction, finishCallback: Transitions.TransitionFinishCallback, ): Boolean { - if (!TransitionUtil.isClosingType(info.type)) return false + val shouldAnimate = + TransitionUtil.isClosingType(info.type) || info.type == Transitions.TRANSIT_MINIMIZE + if (!shouldAnimate) return false val animations = mutableListOf<Animator>() val onAnimFinish: (Animator) -> Unit = { animator -> @@ -75,10 +78,14 @@ class DesktopMinimizationTransitionHandler( } } + val checkChangeMode = { change: TransitionInfo.Change -> + change.mode == info.type || + (info.type == Transitions.TRANSIT_MINIMIZE && change.mode == TRANSIT_TO_BACK) + } animations += info.changes .filter { - it.mode == info.type && it.taskInfo?.windowingMode == WINDOWING_MODE_FREEFORM + checkChangeMode(it) && it.taskInfo?.windowingMode == WINDOWING_MODE_FREEFORM } .mapNotNull { createMinimizeAnimation(it, finishTransaction, onAnimFinish) } if (animations.isEmpty()) return false diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt index aa507728739e..e3a71a1ad9a5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt @@ -18,6 +18,7 @@ package com.android.wm.shell.desktopmode import android.app.ActivityTaskManager.INVALID_TASK_ID import android.window.DesktopExperienceFlags +import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource.UNKNOWN import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.transition.FocusTransitionObserver @@ -188,8 +189,12 @@ class DesktopModeShellCommandHandler( pw.println("Error: task id should be an integer") return false } - pw.println("Not implemented.") - return false + controller.moveTaskToFront( + /* taskId= */ taskId, + /* remoteTransition= */ null, + /* unminimizeReason= */ UnminimizeReason.UNKNOWN, + ) + return true } private fun runMoveTaskOutOfDesk(args: Array<String>, pw: PrintWriter): Boolean { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt index 6034299453fb..70a648f57125 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt @@ -35,7 +35,7 @@ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUser desktopRepository.removeTask(taskInfo.displayId, taskInfo.taskId) return } - if (isFreeformTask(taskInfo)) { + if (isFreeformTask(taskInfo) && !desktopRepository.isActiveTask(taskInfo.taskId)) { desktopRepository.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible) } } @@ -44,23 +44,33 @@ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUser logD("onTaskChanging for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) val desktopRepository: DesktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) - if (!desktopRepository.isActiveTask(taskInfo.taskId)) return - // TODO: b/394281403 - with multiple desks, it's possible to have a non-freeform task // inside a desk, so this should be decoupled from windowing mode. // Also, changes in/out of desks are handled by the [DesksTransitionObserver], which has // more specific information about the desk involved in the transition, which might be // more accurate than assuming it's always the default/active desk in the display, as this // method does. - // Case 1: Freeform task is changed in Desktop Mode. - if (isFreeformTask(taskInfo)) { - if (taskInfo.isVisible) { + // Case 1: When the task change is from a task in the desktop repository which is now + // fullscreen, + // remove the task from the desktop repository since it is no longer a freeform task. + if (!isFreeformTask(taskInfo)) { + if (desktopRepository.isActiveTask(taskInfo.taskId)) { + desktopRepository.removeTask(taskInfo.displayId, taskInfo.taskId) + } + } else { // Task change is a freeform task + if (!desktopRepository.isActiveTask(taskInfo.taskId)) { + // Case 2: When the task change is a freeform visible task, but the task is not + // yet active in the desktop repository, adds task to desktop repository. desktopRepository.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible) + } else { + // Case 3: When the task change is a freeform task which already exists as an active + // task in the desktop repository, updates the task state. + desktopRepository.updateTask( + taskInfo.displayId, + taskInfo.taskId, + taskInfo.isVisible, + ) } - desktopRepository.updateTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible) - } else { - // Case 2: Freeform task is changed outside Desktop Mode. - desktopRepository.removeTask(taskInfo.displayId, taskInfo.taskId) } } @@ -82,14 +92,22 @@ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUser logD("onTaskMovingToFront for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) val desktopRepository: DesktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) - if (!desktopRepository.isActiveTask(taskInfo.taskId)) return - if (!isFreeformTask(taskInfo)) { + // When the task change is from a task in the desktop repository which is now fullscreen, + // remove the task from the desktop repository since it is no longer a freeform task. + if (!isFreeformTask(taskInfo) && desktopRepository.isActiveTask(taskInfo.taskId)) { desktopRepository.removeTask(taskInfo.displayId, taskInfo.taskId) } - desktopRepository.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible) + if (isFreeformTask(taskInfo)) { + // If the task is already active in the repository, then it only moves the task to the + // front. + desktopRepository.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible) + } } override fun onTaskMovingToBack(taskInfo: RunningTaskInfo) { + val desktopRepository: DesktopRepository = + desktopUserRepositories.getProfile(taskInfo.userId) + if (!desktopRepository.isActiveTask(taskInfo.taskId)) return logD("onTaskMovingToBack for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) // TODO: b/367268953 - Connect this with DesktopRepository. } @@ -101,7 +119,7 @@ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUser if (!desktopRepository.isActiveTask(taskInfo.taskId)) return // TODO: b/370038902 - Handle Activity#finishAndRemoveTask. if ( - !DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue() || + !DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue || desktopRepository.isClosingTask(taskInfo.taskId) ) { // A task that's vanishing should be removed: diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index b47dfe2064cd..8f7e52ea2108 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -677,11 +677,7 @@ class DesktopTasksController( // Bring other apps to front first. bringDesktopAppsToFrontBeforeShowingNewTask(displayId, wct, task.taskId) } - if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { - prepareMoveTaskToDesk(wct, task, deskId) - } else { - addMoveToDesktopChanges(wct, task) - } + addMoveToDeskTaskChanges(wct = wct, task = task, deskId = deskId) return taskIdToMinimize } @@ -1121,12 +1117,13 @@ class DesktopTasksController( excludeTaskId = launchingTaskId, reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH, ) - var deskIdToActivate: Int? = null - if ( - DesktopExperienceFlags.ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING.isTrue && + var activationRunOnTransitStart: RunOnTransitStart? = null + val shouldActivateDesk = + (DesktopExperienceFlags.ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING.isTrue || + DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) && !isDesktopModeShowing(displayId) - ) { - deskIdToActivate = + if (shouldActivateDesk) { + val deskIdToActivate = checkNotNull( launchingTaskId?.let { taskRepository.getDeskIdForTask(it) } ?: getDefaultDeskId(displayId) @@ -1136,6 +1133,18 @@ class DesktopTasksController( // Desk activation must be handled before app launch-related transactions. activateDeskWct.merge(launchTransaction, /* transfer= */ true) launchTransaction = activateDeskWct + activationRunOnTransitStart = { transition -> + desksTransitionObserver.addPendingTransition( + DeskTransition.ActivateDesk( + token = transition, + displayId = displayId, + deskId = deskIdToActivate, + ) + ) + } + desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted( + FREEFORM_ANIMATION_DURATION + ) } val t = if (remoteTransition == null) { @@ -1169,24 +1178,7 @@ class DesktopTasksController( if (launchingTaskId != null && taskRepository.isMinimizedTask(launchingTaskId)) { addPendingUnminimizeTransition(t, displayId, launchingTaskId, unminimizeReason) } - if ( - DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue && - deskIdToActivate != null - ) { - if (DesktopExperienceFlags.ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING.isTrue) { - desksTransitionObserver.addPendingTransition( - DeskTransition.ActivateDesk( - token = t, - displayId = displayId, - deskId = deskIdToActivate, - ) - ) - } - - desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted( - FREEFORM_ANIMATION_DURATION - ) - } + activationRunOnTransitStart?.invoke(t) exitImmersiveResult.asExit()?.runOnTransitionStart?.invoke(t) return t } @@ -1250,6 +1242,10 @@ class DesktopTasksController( pendingIntentBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS launchBounds = bounds + if (DesktopModeFlags.ENABLE_SHELL_INITIAL_BOUNDS_REGRESSION_BUG_FIX.isTrue) { + // Sets launch bounds size as flexible so core can recalculate. + flexibleLaunchSize = true + } } wct.sendPendingIntent(pendingIntent, intent, ops.toBundle()) @@ -1260,6 +1256,8 @@ class DesktopTasksController( * Move [task] to display with [displayId]. * * No-op if task is already on that display per [RunningTaskInfo.displayId]. + * + * TODO: b/399411604 - split this up into smaller functions. */ private fun moveToDisplay(task: RunningTaskInfo, displayId: Int) { logV("moveToDisplay: taskId=%d displayId=%d", task.taskId, displayId) @@ -1315,16 +1313,20 @@ class DesktopTasksController( // TODO: b/393977830 and b/397437641 - do not assume that freeform==desktop. if (!task.isFreeform) { - addMoveToDesktopChanges(wct, task, displayId) - } else if (Flags.enableMoveToNextDisplayShortcut()) { - applyFreeformDisplayChange(wct, task, displayId) + addMoveToDeskTaskChanges(wct = wct, task = task, deskId = destinationDeskId) + } else { + if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { + desksOrganizer.moveTaskToDesk(wct, destinationDeskId, task) + } + if (Flags.enableMoveToNextDisplayShortcut()) { + applyFreeformDisplayChange(wct, task, displayId) + } } - if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { - desksOrganizer.moveTaskToDesk(wct, destinationDeskId, task) - } else { + if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { wct.reparent(task.token, displayAreaInfo.token, /* onTop= */ true) } + addDeskActivationChanges(destinationDeskId, wct) val activationRunnable: RunOnTransitStart = { transition -> desksTransitionObserver.addPendingTransition( @@ -2062,12 +2064,13 @@ class DesktopTasksController( triggerTask?.let { task -> when { // Check if freeform task launch during recents should be handled - shouldHandleMidRecentsFreeformLaunch -> handleMidRecentsFreeformTaskLaunch(task) + shouldHandleMidRecentsFreeformLaunch -> + handleMidRecentsFreeformTaskLaunch(task, transition) // Check if the closing task needs to be handled TransitionUtil.isClosingType(request.type) -> handleTaskClosing(task, transition, request.type) // Check if the top task shouldn't be allowed to enter desktop mode - isIncompatibleTask(task) -> handleIncompatibleTaskLaunch(task) + isIncompatibleTask(task) -> handleIncompatibleTaskLaunch(task, transition) // Check if fullscreen task should be updated task.isFullscreen -> handleFullscreenTaskLaunch(task, transition) // Check if freeform task should be updated @@ -2306,20 +2309,23 @@ class DesktopTasksController( * This is a special case where we want to launch the task in fullscreen instead of freeform. */ private fun handleMidRecentsFreeformTaskLaunch( - task: RunningTaskInfo + task: RunningTaskInfo, + transition: IBinder, ): WindowContainerTransaction? { logV("DesktopTasksController: handleMidRecentsFreeformTaskLaunch") val wct = WindowContainerTransaction() - addMoveToFullscreenChanges( - wct = wct, - taskInfo = task, - willExitDesktop = - willExitDesktop( - triggerTaskId = task.taskId, - displayId = task.displayId, - forceExitDesktop = true, - ), - ) + val runOnTransitStart = + addMoveToFullscreenChanges( + wct = wct, + taskInfo = task, + willExitDesktop = + willExitDesktop( + triggerTaskId = task.taskId, + displayId = task.displayId, + forceExitDesktop = true, + ), + ) + runOnTransitStart?.invoke(transition) wct.reorder(task.token, true) return wct } @@ -2343,16 +2349,18 @@ class DesktopTasksController( // launched. We should make this task go to fullscreen instead of freeform. Note // that this means any re-launch of a freeform window outside of desktop will be in // fullscreen as long as default-desktop flag is disabled. - addMoveToFullscreenChanges( - wct = wct, - taskInfo = task, - willExitDesktop = - willExitDesktop( - triggerTaskId = task.taskId, - displayId = task.displayId, - forceExitDesktop = true, - ), - ) + val runOnTransitStart = + addMoveToFullscreenChanges( + wct = wct, + taskInfo = task, + willExitDesktop = + willExitDesktop( + triggerTaskId = task.taskId, + displayId = task.displayId, + forceExitDesktop = true, + ), + ) + runOnTransitStart?.invoke(transition) return wct } bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, task.taskId) @@ -2416,7 +2424,8 @@ class DesktopTasksController( if (shouldFullscreenTaskLaunchSwitchToDesktop(task)) { logD("Switch fullscreen task to freeform on transition: taskId=%d", task.taskId) return WindowContainerTransaction().also { wct -> - addMoveToDesktopChanges(wct, task) + val deskId = getDefaultDeskId(task.displayId) + addMoveToDeskTaskChanges(wct = wct, task = task, deskId = deskId) // In some launches home task is moved behind new task being launched. Make sure // that's not the case for launches in desktop. Also, if this launch is the first // one to trigger the desktop mode (e.g., when [forceEnterDesktop()]), activate the @@ -2447,7 +2456,8 @@ class DesktopTasksController( // If a freeform task receives a request for a fullscreen launch, apply the same // changes we do for similar transitions. The task not having WINDOWING_MODE_UNDEFINED // set when needed can interfere with future split / multi-instance transitions. - return WindowContainerTransaction().also { wct -> + val wct = WindowContainerTransaction() + val runOnTransitStart = addMoveToFullscreenChanges( wct = wct, taskInfo = task, @@ -2458,7 +2468,8 @@ class DesktopTasksController( forceExitDesktop = true, ), ) - } + runOnTransitStart?.invoke(transition) + return wct } return null } @@ -2473,7 +2484,10 @@ class DesktopTasksController( * If a task is not compatible with desktop mode freeform, it should always be launched in * fullscreen. */ - private fun handleIncompatibleTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? { + private fun handleIncompatibleTaskLaunch( + task: RunningTaskInfo, + transition: IBinder, + ): WindowContainerTransaction? { logV("handleIncompatibleTaskLaunch") if (!isDesktopModeShowing(task.displayId) && !forceEnterDesktop(task.displayId)) return null // Only update task repository for transparent task. @@ -2485,7 +2499,8 @@ class DesktopTasksController( } // Already fullscreen, no-op. if (task.isFullscreen) return null - return WindowContainerTransaction().also { wct -> + val wct = WindowContainerTransaction() + val runOnTransitStart = addMoveToFullscreenChanges( wct = wct, taskInfo = task, @@ -2496,7 +2511,8 @@ class DesktopTasksController( forceExitDesktop = true, ), ) - } + runOnTransitStart?.invoke(transition) + return wct } /** @@ -2543,55 +2559,44 @@ class DesktopTasksController( } /** - * Apply all changes required when task is first added to desktop. Uses the task's current - * display by default to apply initial bounds and placement relative to the display. Use a - * different [displayId] if the task should be moved to a different display. + * Applies the [wct] changes needed when a task is first moving to a desk. + * + * Note that this recalculates the initial bounds of the task, so it should not be used when + * transferring a task between desks. + * + * TODO: b/362720497 - this should be improved to be reusable by desk-to-desk CUJs where + * [DesksOrganizer.moveTaskToDesk] needs to be called and even cross-display CUJs where + * [applyFreeformDisplayChange] needs to be called. Potentially by comparing source vs + * destination desk ids and display ids, or adding extra arguments to the function. */ - @VisibleForTesting - @Deprecated("Deprecated with multiple desks", ReplaceWith("prepareMoveTaskToDesk()")) - fun addMoveToDesktopChanges( + fun addMoveToDeskTaskChanges( wct: WindowContainerTransaction, - taskInfo: RunningTaskInfo, - displayId: Int = taskInfo.displayId, - ) { - val displayLayout = displayController.getDisplayLayout(displayId) ?: return - val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId)!! - val tdaWindowingMode = tdaInfo.configuration.windowConfiguration.windowingMode - // TODO: b/397437641 - reconsider the windowing mode choice when multiple desks is enabled. - val targetWindowingMode = - if (tdaWindowingMode == WINDOWING_MODE_FREEFORM) { - // Display windowing is freeform, set to undefined and inherit it - WINDOWING_MODE_UNDEFINED - } else { - WINDOWING_MODE_FREEFORM - } - val initialBounds = getInitialBounds(displayLayout, taskInfo, displayId) - - if (canChangeTaskPosition(taskInfo)) { - wct.setBounds(taskInfo.token, initialBounds) - } - wct.setWindowingMode(taskInfo.token, targetWindowingMode) - wct.reorder(taskInfo.token, /* onTop= */ true) - if (useDesktopOverrideDensity()) { - wct.setDensityDpi(taskInfo.token, DESKTOP_DENSITY_OVERRIDE) - } - } - - private fun prepareMoveTaskToDesk( - wct: WindowContainerTransaction, - taskInfo: RunningTaskInfo, + task: RunningTaskInfo, deskId: Int, ) { - if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return - val displayId = taskRepository.getDisplayForDesk(deskId) - val displayLayout = displayController.getDisplayLayout(displayId) ?: return - val initialBounds = getInitialBounds(displayLayout, taskInfo, displayId) - if (canChangeTaskPosition(taskInfo)) { - wct.setBounds(taskInfo.token, initialBounds) + val targetDisplayId = taskRepository.getDisplayForDesk(deskId) + val displayLayout = displayController.getDisplayLayout(targetDisplayId) ?: return + val initialBounds = getInitialBounds(displayLayout, task, targetDisplayId) + if (canChangeTaskPosition(task)) { + wct.setBounds(task.token, initialBounds) + } + if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { + desksOrganizer.moveTaskToDesk(wct = wct, deskId = deskId, task = task) + } else { + val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(targetDisplayId)!! + val tdaWindowingMode = tdaInfo.configuration.windowConfiguration.windowingMode + val targetWindowingMode = + if (tdaWindowingMode == WINDOWING_MODE_FREEFORM) { + // Display windowing is freeform, set to undefined and inherit it + WINDOWING_MODE_UNDEFINED + } else { + WINDOWING_MODE_FREEFORM + } + wct.setWindowingMode(task.token, targetWindowingMode) + wct.reorder(task.token, /* onTop= */ true) } - desksOrganizer.moveTaskToDesk(wct, deskId = deskId, task = taskInfo) if (useDesktopOverrideDensity()) { - wct.setDensityDpi(taskInfo.token, DESKTOP_DENSITY_OVERRIDE) + wct.setDensityDpi(task.token, DESKTOP_DENSITY_OVERRIDE) } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS index 44d46eea9c55..7a63ec5eeda3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/OWNERS @@ -2,7 +2,6 @@ atsjenk@google.com jorgegil@google.com madym@google.com -nmusgrave@google.com pbdr@google.com vaniadesmonda@google.com pragyabajoria@google.com diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java index d666126b91ba..c0a0f469add4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java @@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.service.dreams.Flags.dismissDreamOnKeyguardDismiss; import static android.view.WindowManager.KEYGUARD_VISIBILITY_TRANSIT_FLAGS; +import static android.view.WindowManager.TRANSIT_FLAG_AOD_APPEARING; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED; @@ -200,7 +201,8 @@ public class KeyguardTransitionHandler transition, info, startTransaction, finishTransaction, finishCallback); } - if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_APPEARING) != 0) { + if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_APPEARING) != 0 + || (info.getFlags() & TRANSIT_FLAG_AOD_APPEARING) != 0) { return startAnimation(mAppearTransition, "appearing", transition, info, startTransaction, finishTransaction, finishCallback); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/OWNERS index 5aa3c4e2abef..245669b644db 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/OWNERS +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/OWNERS @@ -1,3 +1,2 @@ # WM shell sub-module TV pip owner -galinap@google.com bronger@google.com diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java index 1ce24f76ada5..6012fe66188d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java @@ -32,6 +32,7 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.os.Bundle; import android.view.SurfaceControl; +import android.window.DesktopExperienceFlags; import android.window.DisplayAreaInfo; import android.window.WindowContainerTransaction; @@ -41,7 +42,6 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.ProtoLog; import com.android.internal.util.Preconditions; -import com.android.window.flags.Flags; import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayChangeController; @@ -303,7 +303,8 @@ public class PipController implements ConfigurationChangeListener, public void onDisplayRemoved(int displayId) { // If PiP was active on an external display that is removed, clean up states and set // {@link PipDisplayLayoutState} to DEFAULT_DISPLAY. - if (Flags.enableConnectedDisplaysPip() && mPipTransitionState.isInPip() + if (DesktopExperienceFlags.ENABLE_CONNECTED_DISPLAYS_PIP.isTrue() + && mPipTransitionState.isInPip() && displayId == mPipDisplayLayoutState.getDisplayId() && displayId != DEFAULT_DISPLAY) { mPipTransitionState.setState(PipTransitionState.EXITING_PIP); @@ -345,7 +346,6 @@ public class PipController implements ConfigurationChangeListener, return; } - mPipTouchHandler.updateMinMaxSize(mPipBoundsState.getAspectRatio()); mPipMenuController.hideMenu(); if (mPipTransitionState.isInFixedRotation()) { @@ -366,6 +366,8 @@ public class PipController implements ConfigurationChangeListener, mPipBoundsState.setBounds(toBounds); } t.setBounds(mPipTransitionState.getPipTaskToken(), mPipBoundsState.getBounds()); + // Update the size spec in PipBoundsState afterwards. + mPipBoundsState.updateMinMaxSize(mPipBoundsState.getAspectRatio()); } private void setDisplayLayout(DisplayLayout layout) { @@ -384,7 +386,7 @@ public class PipController implements ConfigurationChangeListener, // If PiP is enabled on Connected Displays, update PipDisplayLayoutState to have the correct // display info that PiP is entering in. - if (Flags.enableConnectedDisplaysPip()) { + if (DesktopExperienceFlags.ENABLE_CONNECTED_DISPLAYS_PIP.isTrue()) { final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(displayId); if (displayLayout != null) { mPipDisplayLayoutState.setDisplayId(displayId); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java index af1e98a3a8d2..d53365abd143 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java @@ -81,8 +81,6 @@ public class PipResizeGestureHandler implements private final PointF mDownSecondPoint = new PointF(); private final PointF mLastPoint = new PointF(); private final PointF mLastSecondPoint = new PointF(); - private final Point mMaxSize = new Point(); - private final Point mMinSize = new Point(); private final Rect mLastResizeBounds = new Rect(); private final Rect mUserResizeBounds = new Rect(); private final Rect mDownBounds = new Rect(); @@ -95,7 +93,6 @@ public class PipResizeGestureHandler implements private boolean mIsEnabled; private boolean mEnablePinchResize; private boolean mEnableDragCornerResize; - private boolean mIsSysUiStateValid; private boolean mThresholdCrossed; private boolean mOngoingPinchToResize = false; private boolean mWaitingForBoundsChangeTransition = false; @@ -152,7 +149,6 @@ public class PipResizeGestureHandler implements } void init() { - mContext.getDisplay().getRealSize(mMaxSize); reloadResources(); final Resources res = mContext.getResources(); @@ -163,15 +159,6 @@ public class PipResizeGestureHandler implements reloadResources(); } - /** - * Called when SysUI state changed. - * - * @param isSysUiStateValid Is SysUI valid or not. - */ - public void onSystemUiStateChanged(boolean isSysUiStateValid) { - mIsSysUiStateValid = isSysUiStateValid; - } - private void reloadResources() { mPipDragToResizeHandler.reloadResources(); mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop(); @@ -287,13 +274,15 @@ public class PipResizeGestureHandler implements } } + final Point minSize = mPipBoundsState.getMinSize(); + final Point maxSize = mPipBoundsState.getMaxSize(); if (mOngoingPinchToResize) { mPipPinchToResizeHandler.onPinchResize(mv, mDownPoint, mDownSecondPoint, mDownBounds, mLastPoint, mLastSecondPoint, mLastResizeBounds, mTouchSlop, - mMinSize, mMaxSize); + minSize, maxSize); } else if (mEnableDragCornerResize) { mPipDragToResizeHandler.onDragCornerResize(mv, mLastResizeBounds, mDownPoint, - mDownBounds, mMinSize, mMaxSize, mTouchSlop); + mDownBounds, minSize, maxSize, mTouchSlop); } } } @@ -327,7 +316,7 @@ public class PipResizeGestureHandler implements if (mEnablePinchResize && ev.getPointerCount() == 2) { mPipPinchToResizeHandler.onPinchResize(ev, mDownPoint, mDownSecondPoint, mDownBounds, mLastPoint, mLastSecondPoint, mLastResizeBounds, - mTouchSlop, mMinSize, mMaxSize); + mTouchSlop, mPipBoundsState.getMinSize(), mPipBoundsState.getMaxSize()); mOngoingPinchToResize = mAllowGesture; return mAllowGesture; } @@ -407,16 +396,19 @@ public class PipResizeGestureHandler implements return; } + final Point minSize = mPipBoundsState.getMinSize(); + final Point maxSize = mPipBoundsState.getMaxSize(); + // If user resize is pretty close to max size, just auto resize to max. - if (mLastResizeBounds.width() >= PINCH_RESIZE_AUTO_MAX_RATIO * mMaxSize.x - || mLastResizeBounds.height() >= PINCH_RESIZE_AUTO_MAX_RATIO * mMaxSize.y) { - resizeRectAboutCenter(mLastResizeBounds, mMaxSize.x, mMaxSize.y); + if (mLastResizeBounds.width() >= PINCH_RESIZE_AUTO_MAX_RATIO * maxSize.x + || mLastResizeBounds.height() >= PINCH_RESIZE_AUTO_MAX_RATIO * maxSize.y) { + resizeRectAboutCenter(mLastResizeBounds, maxSize.x, maxSize.y); } // If user resize is smaller than min size, auto resize to min - if (mLastResizeBounds.width() < mMinSize.x - || mLastResizeBounds.height() < mMinSize.y) { - resizeRectAboutCenter(mLastResizeBounds, mMinSize.x, mMinSize.y); + if (mLastResizeBounds.width() < minSize.x + || mLastResizeBounds.height() < minSize.y) { + resizeRectAboutCenter(mLastResizeBounds, minSize.x, minSize.y); } // get the current movement bounds @@ -472,15 +464,6 @@ public class PipResizeGestureHandler implements mInputMonitor.pilferPointers(); } - - void updateMaxSize(int maxX, int maxY) { - mMaxSize.set(maxX, maxY); - } - - void updateMinSize(int minX, int minY) { - mMinSize.set(minX, minY); - } - void setOhmOffset(int offset) { mOhmOffset = offset; } @@ -568,8 +551,6 @@ public class PipResizeGestureHandler implements pw.println(innerPrefix + "mEnableDragCornerResize=" + mEnableDragCornerResize); pw.println(innerPrefix + "mThresholdCrossed=" + mThresholdCrossed); pw.println(innerPrefix + "mOhmOffset=" + mOhmOffset); - pw.println(innerPrefix + "mMinSize=" + mMinSize); - pw.println(innerPrefix + "mMaxSize=" + mMaxSize); } class PipResizeInputEventReceiver extends BatchedInputEventReceiver { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java index 72346b335a8e..6fdfecaf15d5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java @@ -230,10 +230,7 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha pipBoundsState, mTouchState, mPipScheduler, mPipTransitionState, pipUiEventLogger, menuController, this::getMovementBounds, mPipDisplayLayoutState, pipDesktopState, mainExecutor, mPipPerfHintController); - mPipBoundsState.addOnAspectRatioChangedCallback(aspectRatio -> { - updateMinMaxSize(aspectRatio); - onAspectRatioChanged(); - }); + mPipBoundsState.addOnAspectRatioChangedCallback(aspectRatio -> onAspectRatioChanged()); mMoveOnShelVisibilityChanged = () -> { if (mIsImeShowing && mImeHeight > mShelfHeight) { @@ -418,15 +415,6 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha mMainExecutor.executeDelayed(mMoveOnShelVisibilityChanged, PIP_KEEP_CLEAR_AREAS_DELAY); } - /** - * Called when SysUI state changed. - * - * @param isSysUiStateValid Is SysUI valid or not. - */ - public void onSystemUiStateChanged(boolean isSysUiStateValid) { - mPipResizeGestureHandler.onSystemUiStateChanged(isSysUiStateValid); - } - void adjustBoundsForRotation(Rect outBounds, Rect curBounds, Rect insetBounds) { final Rect toMovementBounds = new Rect(); mPipBoundsAlgorithm.getMovementBounds(outBounds, insetBounds, toMovementBounds, 0); @@ -480,8 +468,6 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha mPipBoundsState.getExpandedBounds(), insetBounds, expandedMovementBounds, bottomOffset); - updatePipSizeConstraints(normalBounds, aspectRatio); - // The extra offset does not really affect the movement bounds, but are applied based on the // current state (ime showing, or shelf offset) when we need to actually shift int extraOffset = Math.max( @@ -507,35 +493,6 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha } /** - * Update the values for min/max allowed size of picture in picture window based on the aspect - * ratio. - * @param aspectRatio aspect ratio to use for the calculation of min/max size - */ - public void updateMinMaxSize(float aspectRatio) { - updatePipSizeConstraints(mPipBoundsState.getNormalBounds(), - aspectRatio); - } - - private void updatePipSizeConstraints(Rect normalBounds, - float aspectRatio) { - if (mPipResizeGestureHandler.isUsingPinchToZoom()) { - updatePinchResizeSizeConstraints(aspectRatio); - } else { - mPipResizeGestureHandler.updateMinSize(normalBounds.width(), normalBounds.height()); - mPipResizeGestureHandler.updateMaxSize(mPipBoundsState.getExpandedBounds().width(), - mPipBoundsState.getExpandedBounds().height()); - } - } - - private void updatePinchResizeSizeConstraints(float aspectRatio) { - mPipBoundsState.updateMinMaxSize(aspectRatio); - mPipResizeGestureHandler.updateMinSize(mPipBoundsState.getMinSize().x, - mPipBoundsState.getMinSize().y); - mPipResizeGestureHandler.updateMaxSize(mPipBoundsState.getMaxSize().x, - mPipBoundsState.getMaxSize().y); - } - - /** * TODO Add appropriate description */ public void onRegistrationChanged(boolean isRegistered) { 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 93023471fdfb..a3a808de6ff1 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 @@ -2080,8 +2080,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, Math.max(topLeftBounds.top, 0); bottomRightBounds.right = Math.min(bottomRightBounds.right, mSplitLayout.getDisplayWidth()); - bottomRightBounds.top = - Math.min(bottomRightBounds.top, mSplitLayout.getDisplayHeight()); + bottomRightBounds.bottom = + Math.min(bottomRightBounds.bottom, mSplitLayout.getDisplayHeight()); // TODO (b/349828130): Can change to getState() fully after brief soak time. if (mSplitState.get() != currentSnapPosition) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/OWNERS index 28be0efc38f6..9dc0ebbb8e56 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/OWNERS +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/OWNERS @@ -1,3 +1,2 @@ # WM shell sub-module TV splitscreen owner -galinap@google.com bronger@google.com diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java index 3652a1661f28..bf5800330979 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java @@ -95,7 +95,6 @@ import android.os.UserHandle; import android.util.ArrayMap; import android.view.SurfaceControl; import android.view.WindowManager; -import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.window.TransitionInfo; import android.window.TransitionMetrics; @@ -835,9 +834,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { a = mTransitionAnimation.loadVoiceActivityExitAnimation(enter, userId); } } else if (changeMode == TRANSIT_CHANGE) { - // In the absence of a specific adapter, we just want to keep everything stationary. - a = new AlphaAnimation(1.f, 1.f); - a.setDuration(TransitionAnimation.DEFAULT_APP_TRANSITION_DURATION); + // Apply end state directly by default. + return null; } else if (type == TRANSIT_RELAUNCH) { a = mTransitionAnimation.createRelaunchAnimation(endBounds, mInsets, endBounds); } else if (overrideType == ANIM_CUSTOM diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt index 4c443d7501f7..d73d08c032f9 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt @@ -498,9 +498,9 @@ class DesktopModeFlickerScenarios { it.remove(VisibleLayersShownMoreThanOneConsecutiveEntry()) } + listOf( - AppWindowOnTopAtStart(DESKTOP_MODE_APP), AppWindowBecomesInvisible(DESKTOP_MODE_APP), AppWindowOnTopAtEnd(LAUNCHER), + AppWindowIsInvisibleAtEnd(DESKTOP_WALLPAPER), ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }) ) val OPEN_UNLIMITED_APPS = diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayModeControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayModeControllerTest.kt index d054de4d6fc1..cc37c440f650 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayModeControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayModeControllerTest.kt @@ -26,7 +26,6 @@ import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.provider.Settings import android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS -import android.testing.AndroidTestingRunner import android.view.Display.DEFAULT_DISPLAY import android.view.IWindowManager import android.view.WindowManager.TRANSIT_CHANGE @@ -43,6 +42,8 @@ import com.android.wm.shell.TestRunningTaskInfoBuilder import com.android.wm.shell.desktopmode.desktopwallpaperactivity.DesktopWallpaperActivityTokenProvider import com.android.wm.shell.transition.Transitions import com.google.common.truth.Truth.assertThat +import com.google.testing.junit.testparameterinjector.TestParameter +import com.google.testing.junit.testparameterinjector.TestParameterInjector import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -62,7 +63,7 @@ import org.mockito.kotlin.whenever * Usage: atest WMShellUnitTests:DesktopDisplayModeControllerTest */ @SmallTest -@RunWith(AndroidTestingRunner::class) +@RunWith(TestParameterInjector::class) class DesktopDisplayModeControllerTest : ShellTestCase() { private val transitions = mock<Transitions>() private val rootTaskDisplayAreaOrganizer = mock<RootTaskDisplayAreaOrganizer>() @@ -143,41 +144,24 @@ class DesktopDisplayModeControllerTest : ShellTestCase() { @Test @DisableFlags(Flags.FLAG_ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING) - fun displayWindowingModeSwitchOnDisplayConnected_fullscreenDisplay_flagDisabled() { - testDisplayWindowingModeSwitch( - defaultWindowingMode = WINDOWING_MODE_FULLSCREEN, - extendedDisplayEnabled = true, - expectToSwitch = false, - ) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING) - fun displayWindowingModeSwitchOnDisplayConnected_extendedDisplayDisabled() { + fun displayWindowingModeSwitchOnDisplayConnected_flagDisabled( + @TestParameter param: ModeSwitchTestCase + ) { testDisplayWindowingModeSwitch( - defaultWindowingMode = WINDOWING_MODE_FULLSCREEN, - extendedDisplayEnabled = false, + param.defaultWindowingMode, + param.extendedDisplayEnabled, + // When the flag is disabled, never switch. expectToSwitch = false, ) } @Test @EnableFlags(Flags.FLAG_ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING) - fun displayWindowingModeSwitchOnDisplayConnected_fullscreenDisplay() { + fun displayWindowingModeSwitchOnDisplayConnected(@TestParameter param: ModeSwitchTestCase) { testDisplayWindowingModeSwitch( - defaultWindowingMode = WINDOWING_MODE_FULLSCREEN, - extendedDisplayEnabled = true, - expectToSwitch = true, - ) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING) - fun displayWindowingModeSwitchOnDisplayConnected_freeformDisplay() { - testDisplayWindowingModeSwitch( - defaultWindowingMode = WINDOWING_MODE_FREEFORM, - extendedDisplayEnabled = true, - expectToSwitch = false, + param.defaultWindowingMode, + param.extendedDisplayEnabled, + param.expectToSwitchByDefault, ) } @@ -249,7 +233,34 @@ class DesktopDisplayModeControllerTest : ShellTestCase() { } } - private companion object { + companion object { const val EXTERNAL_DISPLAY_ID = 100 + + enum class ModeSwitchTestCase( + val defaultWindowingMode: Int, + val extendedDisplayEnabled: Boolean, + val expectToSwitchByDefault: Boolean, + ) { + FULLSCREEN_DISPLAY( + defaultWindowingMode = WINDOWING_MODE_FULLSCREEN, + extendedDisplayEnabled = true, + expectToSwitchByDefault = true, + ), + FULLSCREEN_DISPLAY_MIRRORING( + defaultWindowingMode = WINDOWING_MODE_FULLSCREEN, + extendedDisplayEnabled = false, + expectToSwitchByDefault = false, + ), + FREEFORM_DISPLAY( + defaultWindowingMode = WINDOWING_MODE_FREEFORM, + extendedDisplayEnabled = true, + expectToSwitchByDefault = false, + ), + FREEFORM_DISPLAY_MIRRORING( + defaultWindowingMode = WINDOWING_MODE_FREEFORM, + extendedDisplayEnabled = false, + expectToSwitchByDefault = false, + ), + } } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMinimizationTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMinimizationTransitionHandlerTest.kt index 0d1c57221fb9..3e6f688e6acc 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMinimizationTransitionHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMinimizationTransitionHandlerTest.kt @@ -33,6 +33,7 @@ import com.android.wm.shell.ShellTestCase import com.android.wm.shell.TestRunningTaskInfoBuilder import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.ShellExecutor +import com.android.wm.shell.transition.Transitions import org.junit.Assert.assertFalse import org.junit.Assert.assertNull import org.junit.Assert.assertTrue @@ -154,6 +155,24 @@ class DesktopMinimizationTransitionHandlerTest : ShellTestCase() { assertTrue("Should animate going to back freeform task close transition", animates) } + @Test + fun startAnimation_minimizeTransitionToBackFreeformTask_returnsTrue() { + val animates = + handler.startAnimation( + transition = mock(), + info = + createTransitionInfo( + type = Transitions.TRANSIT_MINIMIZE, + task = createTask(WINDOWING_MODE_FREEFORM), + ), + startTransaction = mock(), + finishTransaction = mock(), + finishCallback = {}, + ) + + assertTrue("Should animate going to back freeform task minimize transition", animates) + } + private fun createTransitionInfo( type: Int = WindowManager.TRANSIT_TO_BACK, changeMode: Int = WindowManager.TRANSIT_TO_BACK, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt index 50590f021a2a..6b0ee5b7ffd4 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt @@ -56,7 +56,7 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { } @Test - fun onTaskOpening_fullscreenTask_notActiveDesktopTask_noop() { + fun onTaskOpening_fullscreenTask_nonActiveDesktopTask_noop() { val task = createFullscreenTask().apply { isVisible = true } whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(false) @@ -68,7 +68,7 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { } @Test - fun onTaskOpening_freeformTask_activeDesktopTask_removesTaskFromRepo() { + fun onTaskOpening_fullscreenTask_taskIsActiveInDesktopRepo_removesTaskFromDesktopRepo() { val task = createFullscreenTask().apply { isVisible = true } whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true) @@ -78,19 +78,20 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { } @Test - fun onTaskOpening_freeformTask_visibleDesktopTask_addsTaskToRepository() { + fun onTaskOpening_freeformTask_activeInDesktopRepository_noop() { val task = createFreeformTask().apply { isVisible = true } - whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(false) + whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true) desktopTaskChangeListener.onTaskOpening(task) - verify(desktopUserRepositories.current).addTask(task.displayId, task.taskId, task.isVisible) + verify(desktopUserRepositories.current, never()) + .addTask(task.displayId, task.taskId, task.isVisible) } @Test - fun onTaskOpening_freeformTask_nonVisibleDesktopTask_addsTaskToRepository() { + fun onTaskOpening_freeformTask_notActiveInDesktopRepo_addsTaskToRepository() { val task = createFreeformTask().apply { isVisible = false } - whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true) + whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(false) desktopTaskChangeListener.onTaskOpening(task) @@ -98,7 +99,7 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { } @Test - fun onTaskChanging_freeformTaskOutsideDesktop_removesTaskFromRepo() { + fun onTaskChanging_fullscreenTask_activeInDesktopRepository_removesTaskFromRepo() { val task = createFullscreenTask().apply { isVisible = true } whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true) @@ -108,7 +109,27 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { } @Test - fun onTaskChanging_visibleTaskInDesktop_updatesTaskVisibility() { + fun onTaskChanging_fullscreenTask_nonActiveInDesktopRepo_noop() { + val task = createFullscreenTask().apply { isVisible = true } + whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(false) + + desktopTaskChangeListener.onTaskChanging(task) + + verify(desktopUserRepositories.current, never()).removeTask(task.displayId, task.taskId) + } + + @Test + fun onTaskChanging_freeformTask_nonActiveTaskInDesktopRepo_addsTaskToDesktopRepo() { + val task = createFreeformTask().apply { isVisible = true } + whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(false) + + desktopTaskChangeListener.onTaskChanging(task) + + verify(desktopUserRepositories.current).addTask(task.displayId, task.taskId, task.isVisible) + } + + @Test + fun onTaskChanging_freeformTask_activeVisibleTaskInDesktopRepo_updatesTaskVisibility() { val task = createFreeformTask().apply { isVisible = true } whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true) @@ -119,7 +140,7 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { } @Test - fun onTaskChanging_nonVisibleTask_updatesTaskVisibility() { + fun onTaskChanging_freeformTask_activeNonVisibleTask_updatesTaskVisibility() { val task = createFreeformTask().apply { isVisible = false } whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true) @@ -130,7 +151,7 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { } @Test - fun onTaskMovingToFront_freeformTaskOutsideDesktop_removesTaskFromRepo() { + fun onTaskMovingToFront_fullscreenTask_activeTaskInDesktopRepo_removesTaskFromRepo() { val task = createFullscreenTask().apply { isVisible = true } whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true) @@ -140,9 +161,18 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { } @Test - fun onTaskMovingToFront_freeformTaskOutsideDesktop_addsTaskToRepo() { + fun onTaskMovingToFront_fullscreenTask_nonActiveTaskInDesktopRepo_noop() { val task = createFullscreenTask().apply { isVisible = true } - whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true) + whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(false) + + desktopTaskChangeListener.onTaskMovingToFront(task) + + verify(desktopUserRepositories.current, never()).removeTask(task.displayId, task.taskId) + } + + @Test + fun onTaskMovingToFront_freeformTask_addsTaskToRepo() { + val task = createFreeformTask().apply { isVisible = true } desktopTaskChangeListener.onTaskMovingToFront(task) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index d5c84bafbd81..63bf6841dba4 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -334,6 +334,16 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() whenever(enterDesktopTransitionHandler.moveToDesktop(any(), any())).thenAnswer { Binder() } whenever(exitDesktopTransitionHandler.startTransition(any(), any(), any(), any())) .thenReturn(Binder()) + whenever( + desktopMixedTransitionHandler.startLaunchTransition( + any(), + any(), + anyOrNull(), + anyOrNull(), + anyOrNull(), + ) + ) + .thenReturn(Binder()) whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout) whenever(displayController.getDisplayContext(anyInt())).thenReturn(mockDisplayContext) whenever(displayController.getDisplay(anyInt())).thenReturn(display) @@ -1104,44 +1114,44 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() } @Test - fun addMoveToDesktopChanges_gravityLeft_noBoundsApplied() { + fun addMoveToDeskTaskChanges_gravityLeft_noBoundsApplied() { setUpLandscapeDisplay() val task = setUpFullscreenTask(gravity = Gravity.LEFT) val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) val finalBounds = findBoundsChange(wct, task) assertThat(finalBounds).isEqualTo(Rect()) } @Test - fun addMoveToDesktopChanges_gravityRight_noBoundsApplied() { + fun addMoveToDeskTaskChanges_gravityRight_noBoundsApplied() { setUpLandscapeDisplay() val task = setUpFullscreenTask(gravity = Gravity.RIGHT) val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) val finalBounds = findBoundsChange(wct, task) assertThat(finalBounds).isEqualTo(Rect()) } @Test - fun addMoveToDesktopChanges_gravityTop_noBoundsApplied() { + fun addMoveToDeskTaskChanges_gravityTop_noBoundsApplied() { setUpLandscapeDisplay() val task = setUpFullscreenTask(gravity = Gravity.TOP) val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) val finalBounds = findBoundsChange(wct, task) assertThat(finalBounds).isEqualTo(Rect()) } @Test - fun addMoveToDesktopChanges_gravityBottom_noBoundsApplied() { + fun addMoveToDeskTaskChanges_gravityBottom_noBoundsApplied() { setUpLandscapeDisplay() val task = setUpFullscreenTask(gravity = Gravity.BOTTOM) val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) val finalBounds = findBoundsChange(wct, task) assertThat(finalBounds).isEqualTo(Rect()) @@ -1182,7 +1192,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS) - fun addMoveToDesktopChanges_positionBottomRight() { + fun addMoveToDeskTaskChanges_positionBottomRight() { setUpLandscapeDisplay() val stableBounds = Rect() displayLayout.getStableBoundsForDesktopMode(stableBounds) @@ -1191,7 +1201,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val task = setUpFullscreenTask() val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) val finalBounds = findBoundsChange(wct, task) assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!)) @@ -1200,7 +1210,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS) - fun addMoveToDesktopChanges_positionTopLeft() { + fun addMoveToDeskTaskChanges_positionTopLeft() { setUpLandscapeDisplay() val stableBounds = Rect() displayLayout.getStableBoundsForDesktopMode(stableBounds) @@ -1209,7 +1219,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val task = setUpFullscreenTask() val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) val finalBounds = findBoundsChange(wct, task) assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!)) @@ -1218,7 +1228,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS) - fun addMoveToDesktopChanges_positionBottomLeft() { + fun addMoveToDeskTaskChanges_positionBottomLeft() { setUpLandscapeDisplay() val stableBounds = Rect() displayLayout.getStableBoundsForDesktopMode(stableBounds) @@ -1227,7 +1237,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val task = setUpFullscreenTask() val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) val finalBounds = findBoundsChange(wct, task) assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!)) @@ -1236,7 +1246,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS) - fun addMoveToDesktopChanges_positionTopRight() { + fun addMoveToDeskTaskChanges_positionTopRight() { setUpLandscapeDisplay() val stableBounds = Rect() displayLayout.getStableBoundsForDesktopMode(stableBounds) @@ -1245,7 +1255,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val task = setUpFullscreenTask() val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) val finalBounds = findBoundsChange(wct, task) assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!)) @@ -1254,7 +1264,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS) - fun addMoveToDesktopChanges_positionResetsToCenter() { + fun addMoveToDeskTaskChanges_positionResetsToCenter() { setUpLandscapeDisplay() val stableBounds = Rect() displayLayout.getStableBoundsForDesktopMode(stableBounds) @@ -1263,7 +1273,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val task = setUpFullscreenTask() val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) val finalBounds = findBoundsChange(wct, task) assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!)) @@ -1272,7 +1282,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS) - fun addMoveToDesktopChanges_lastWindowSnapLeft_positionResetsToCenter() { + fun addMoveToDeskTaskChanges_lastWindowSnapLeft_positionResetsToCenter() { setUpLandscapeDisplay() val stableBounds = Rect() displayLayout.getStableBoundsForDesktopMode(stableBounds) @@ -1284,7 +1294,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val task = setUpFullscreenTask() val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) val finalBounds = findBoundsChange(wct, task) assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!)) @@ -1293,7 +1303,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS) - fun addMoveToDesktopChanges_lastWindowSnapRight_positionResetsToCenter() { + fun addMoveToDeskTaskChanges_lastWindowSnapRight_positionResetsToCenter() { setUpLandscapeDisplay() val stableBounds = Rect() displayLayout.getStableBoundsForDesktopMode(stableBounds) @@ -1311,7 +1321,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val task = setUpFullscreenTask() val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) val finalBounds = findBoundsChange(wct, task) assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!)) @@ -1320,7 +1330,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS) - fun addMoveToDesktopChanges_lastWindowMaximised_positionResetsToCenter() { + fun addMoveToDeskTaskChanges_lastWindowMaximised_positionResetsToCenter() { setUpLandscapeDisplay() val stableBounds = Rect() displayLayout.getStableBoundsForDesktopMode(stableBounds) @@ -1330,7 +1340,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val task = setUpFullscreenTask() val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) val finalBounds = findBoundsChange(wct, task) assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!)) @@ -1339,7 +1349,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS) - fun addMoveToDesktopChanges_defaultToCenterIfFree() { + fun addMoveToDeskTaskChanges_defaultToCenterIfFree() { setUpLandscapeDisplay() val stableBounds = Rect() displayLayout.getStableBoundsForDesktopMode(stableBounds) @@ -1357,7 +1367,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val task = setUpFullscreenTask() val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) val finalBounds = findBoundsChange(wct, task) assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!)) @@ -1365,7 +1375,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() } @Test - fun addMoveToDesktopChanges_excludeCaptionFromAppBounds_nonResizableLandscape() { + fun addMoveToDeskTaskChanges_excludeCaptionFromAppBounds_nonResizableLandscape() { setUpLandscapeDisplay() val task = setUpFullscreenTask( @@ -1375,7 +1385,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() whenever(desktopModeCompatPolicy.shouldExcludeCaptionFromAppBounds(task)).thenReturn(true) val initialAspectRatio = calculateAspectRatio(task) val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) val finalBounds = findBoundsChange(wct, task) val captionInsets = getAppHeaderHeight(context) @@ -1387,7 +1397,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() } @Test - fun addMoveToDesktopChanges_excludeCaptionFromAppBounds_nonResizablePortrait() { + fun addMoveToDeskTaskChanges_excludeCaptionFromAppBounds_nonResizablePortrait() { setUpLandscapeDisplay() val task = setUpFullscreenTask( @@ -1397,7 +1407,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() whenever(desktopModeCompatPolicy.shouldExcludeCaptionFromAppBounds(task)).thenReturn(true) val initialAspectRatio = calculateAspectRatio(task) val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) val finalBounds = findBoundsChange(wct, task) val captionInsets = getAppHeaderHeight(context) @@ -1435,29 +1445,29 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) - fun addMoveToDesktopChanges_landscapeDevice_userFullscreenOverride_defaultPortraitBounds() { + fun addMoveToDeskTaskChanges_landscapeDevice_userFullscreenOverride_defaultPortraitBounds() { setUpLandscapeDisplay() val task = setUpFullscreenTask(enableUserFullscreenOverride = true) val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_LANDSCAPE_BOUNDS) } @Test @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) - fun addMoveToDesktopChanges_landscapeDevice_systemFullscreenOverride_defaultPortraitBounds() { + fun addMoveToDeskTaskChanges_landscapeDevice_systemFullscreenOverride_defaultPortraitBounds() { setUpLandscapeDisplay() val task = setUpFullscreenTask(enableSystemFullscreenOverride = true) val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_LANDSCAPE_BOUNDS) } @Test @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) - fun addMoveToDesktopChanges_landscapeDevice_portraitResizableApp_aspectRatioOverridden() { + fun addMoveToDeskTaskChanges_landscapeDevice_portraitResizableApp_aspectRatioOverridden() { setUpLandscapeDisplay() val task = setUpFullscreenTask( @@ -1466,36 +1476,36 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() aspectRatioOverrideApplied = true, ) val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) assertThat(findBoundsChange(wct, task)).isEqualTo(UNRESIZABLE_PORTRAIT_BOUNDS) } @Test @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) - fun addMoveToDesktopChanges_portraitDevice_userFullscreenOverride_defaultPortraitBounds() { + fun addMoveToDeskTaskChanges_portraitDevice_userFullscreenOverride_defaultPortraitBounds() { setUpPortraitDisplay() val task = setUpFullscreenTask(enableUserFullscreenOverride = true) val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_PORTRAIT_BOUNDS) } @Test @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) - fun addMoveToDesktopChanges_portraitDevice_systemFullscreenOverride_defaultPortraitBounds() { + fun addMoveToDeskTaskChanges_portraitDevice_systemFullscreenOverride_defaultPortraitBounds() { setUpPortraitDisplay() val task = setUpFullscreenTask(enableSystemFullscreenOverride = true) val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_PORTRAIT_BOUNDS) } @Test @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS) - fun addMoveToDesktopChanges_portraitDevice_landscapeResizableApp_aspectRatioOverridden() { + fun addMoveToDeskTaskChanges_portraitDevice_landscapeResizableApp_aspectRatioOverridden() { setUpPortraitDisplay() val task = setUpFullscreenTask( @@ -1505,7 +1515,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() aspectRatioOverrideApplied = true, ) val wct = WindowContainerTransaction() - controller.addMoveToDesktopChanges(wct, task) + controller.addMoveToDeskTaskChanges(wct, task, deskId = 0) assertThat(findBoundsChange(wct, task)).isEqualTo(UNRESIZABLE_LANDSCAPE_BOUNDS) } @@ -2814,7 +2824,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() } @Test - @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun moveToNextDisplay_toDesktopInOtherDisplay_bringsExistingTasksToFront() { val transition = Binder() val sourceDeskId = 0 @@ -2846,7 +2855,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() Flags.FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY, Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER, ) - @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun moveToNextDisplay_toDesktopInOtherDisplay_movesHomeAndWallpaperToFront() { val homeTask = setUpHomeTask(displayId = SECOND_DISPLAY) whenever(desktopWallpaperActivityTokenProvider.getToken(SECOND_DISPLAY)) @@ -3496,6 +3504,39 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() } @Test + @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + fun handleRequest_fullscreenTask_switchToDesktop_movesTaskToDesk() { + taskRepository.addDesk(displayId = DEFAULT_DISPLAY, deskId = 5) + setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = 5) + taskRepository.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 5) + + val fullscreenTask = createFullscreenTask() + val wct = controller.handleRequest(Binder(), createTransition(fullscreenTask)) + + assertNotNull(wct, "should handle request") + verify(desksOrganizer).moveTaskToDesk(wct = wct, deskId = 5, task = fullscreenTask) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + fun handleRequest_fullscreenTaskThatWasInactiveInDesk_tracksDeskDeactivation() { + // Set up and existing desktop task in an active desk. + val inactiveInDeskTask = setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = 0) + taskRepository.setDeskInactive(deskId = 0) + + // Now the task is launching as fullscreen. + inactiveInDeskTask.configuration.windowConfiguration.windowingMode = + WINDOWING_MODE_FULLSCREEN + val transition = Binder() + val wct = controller.handleRequest(transition, createTransition(inactiveInDeskTask)) + + // Desk is deactivated. + assertNotNull(wct, "should handle request") + verify(desksTransitionsObserver) + .addPendingTransition(DeskTransition.DeactivateDesk(transition, deskId = 0)) + } + + @Test fun handleRequest_fullscreenTask_freeformVisible_returnSwitchToFreeformWCT() { val homeTask = setUpHomeTask() val freeformTask = setUpFreeformTask() @@ -3671,6 +3712,20 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() } @Test + @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + fun handleRequest_freeformTaskFromInactiveDesk_tracksDeskDeactivation() { + val deskId = 0 + val freeformTask = setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = deskId) + taskRepository.setDeskInactive(deskId = deskId) + + val transition = Binder() + controller.handleRequest(transition, createTransition(freeformTask)) + + verify(desksTransitionsObserver) + .addPendingTransition(DeskTransition.DeactivateDesk(transition, deskId)) + } + + @Test fun handleRequest_freeformTask_relaunchActiveTask_taskBecomesUndefined() { val freeformTask = setUpFreeformTask() markTaskHidden(freeformTask) @@ -3918,6 +3973,24 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() } @Test + @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + fun handleRequest_recentsAnimationRunning_relaunchActiveTask_tracksDeskDeactivation() { + // Set up a visible freeform task + val freeformTask = setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = 0) + markTaskVisible(freeformTask) + + // Mark recents animation running + recentsTransitionStateListener.onTransitionStateChanged(TRANSITION_STATE_ANIMATING) + + val transition = Binder() + controller.handleRequest(transition, createTransition(freeformTask)) + + desksTransitionsObserver.addPendingTransition( + DeskTransition.DeactivateDesk(transition, deskId = 0) + ) + } + + @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) fun handleRequest_topActivityTransparentWithoutDisplay_returnSwitchToFreeformWCT() { val freeformTask = setUpFreeformTask() @@ -4035,6 +4108,31 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() } @Test + @EnableFlags( + Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND, + Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY, + ) + fun handleRequest_systemUIActivityWithDisplayInFreeformTask_inDesktop_tracksDeskDeactivation() { + val deskId = 5 + taskRepository.addDesk(displayId = DEFAULT_DISPLAY, deskId = deskId) + taskRepository.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = deskId) + val systemUIPackageName = + context.resources.getString(com.android.internal.R.string.config_systemUi) + val baseComponent = ComponentName(systemUIPackageName, /* cls= */ "") + val task = + setUpFreeformTask(displayId = DEFAULT_DISPLAY).apply { + baseActivity = baseComponent + isTopActivityNoDisplay = false + } + + val transition = Binder() + controller.handleRequest(transition, createTransition(task)) + + verify(desksTransitionsObserver) + .addPendingTransition(DeskTransition.DeactivateDesk(transition, deskId)) + } + + @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) fun handleRequest_systemUIActivityWithoutDisplay_returnSwitchToFreeformWCT() { val freeformTask = setUpFreeformTask() @@ -6576,6 +6674,25 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @EnableFlags( Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY, Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER, + Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND, + ) + fun startLaunchTransition_desktopNotShowing_updatesDesktopEnterExitListener() { + setUpFreeformTask(displayId = DEFAULT_DISPLAY, deskId = 0) + taskRepository.setDeskInactive(deskId = 0) + + controller.startLaunchTransition( + transitionType = TRANSIT_OPEN, + wct = WindowContainerTransaction(), + launchingTaskId = null, + ) + + verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(any()) + } + + @Test + @EnableFlags( + Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY, + Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER, ) fun startLaunchTransition_desktopShowing_doesNotReorderWallpaper() { val wct = WindowContainerTransaction() diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/OWNERS index 736d4cff6ce8..a7d1890a0286 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/OWNERS +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/OWNERS @@ -1,3 +1,2 @@ # WM shell sub-module TV pip owners -galinap@google.com -bronger@google.com
\ No newline at end of file +bronger@google.com diff --git a/libs/hwui/OWNERS b/libs/hwui/OWNERS index 70d13ab8b3e5..9c06fd5f0225 100644 --- a/libs/hwui/OWNERS +++ b/libs/hwui/OWNERS @@ -3,7 +3,7 @@ alecmouri@google.com djsollen@google.com jreck@google.com -njawad@google.com +nscobie@google.com sumir@google.com # For text, e.g. Typeface, Font, Minikin, etc. diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index fb89973bcc11..66de8c791fdd 100644 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -27,8 +27,6 @@ import android.telephony.TelephonyManager; import android.telephony.emergency.EmergencyNumber; import android.util.Log; -import com.android.internal.annotations.KeepForWeakReference; - import java.util.concurrent.TimeUnit; /** @@ -94,7 +92,6 @@ public class GpsNetInitiatedHandler { // The internal implementation of TelephonyManager uses WeakReference so we have to keep a // reference here. - @KeepForWeakReference private final EmergencyCallListener mEmergencyCallListener = new EmergencyCallListener(); private final EmergencyCallCallback mEmergencyCallCallback; diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index 9bb31d0076c9..4e86eacea404 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -1223,8 +1223,14 @@ public final class MediaCodecInfo { private static final String TAG = "CodecCapabilities"; // NEW-STYLE CAPABILITIES + // Capabilities for an audio codec. + @Nullable private AudioCapabilities mAudioCaps; + // Capabilities for a video codec. + @Nullable private VideoCapabilities mVideoCaps; + // Capabilities specific to an encoder (vs. a decoder). + @Nullable private EncoderCapabilities mEncoderCaps; private MediaFormat mDefaultFormat; @@ -1262,6 +1268,7 @@ public final class MediaCodecInfo { /** * Returns the audio capabilities or {@code null} if this is not an audio codec. */ + @Nullable public AudioCapabilities getAudioCapabilities() { return mAudioCaps; } @@ -1273,6 +1280,7 @@ public final class MediaCodecInfo { /** * Returns the encoding capabilities or {@code null} if this is not an encoder. */ + @Nullable public EncoderCapabilities getEncoderCapabilities() { return mEncoderCaps; } @@ -1284,6 +1292,7 @@ public final class MediaCodecInfo { /** * Returns the video capabilities or {@code null} if this is not a video codec. */ + @Nullable public VideoCapabilities getVideoCapabilities() { return mVideoCaps; } diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java index b11a81047bf8..4e1d472688ea 100644 --- a/media/java/android/media/MediaExtractor.java +++ b/media/java/android/media/MediaExtractor.java @@ -375,6 +375,9 @@ public final class MediaExtractor { /** * Extract DRM initialization data if it exists * + * <p>If the media contains a PSSH box, only PSSH version 0 is supported. The result for media + * with other PSSH versions is undefined. + * * @return DRM initialization data in the content, or {@code null} * if no recognizable DRM format is found; * @see DrmInitData @@ -460,6 +463,10 @@ public final class MediaExtractor { /** * Get the PSSH info if present. + * + * <p>This method only supports version 0 PSSH boxes. The result for other versions is + * undefined. + * * @return a map of uuid-to-bytes, with the uuid specifying * the crypto scheme, and the bytes being the data specific to that scheme. * This can be {@code null} if the source does not contain PSSH info. diff --git a/media/java/android/media/Utils.java b/media/java/android/media/Utils.java index d6e27b0ffa75..9db527bfaa2d 100644 --- a/media/java/android/media/Utils.java +++ b/media/java/android/media/Utils.java @@ -18,6 +18,8 @@ package android.media; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.annotation.TestApi; import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; @@ -61,16 +63,30 @@ import java.util.concurrent.Executor; * * @hide */ +@TestApi +@SuppressLint({"UnflaggedApi", "StaticUtils"}) // Test API public class Utils { private static final String TAG = "Utils"; + /** @hide + * The vibration uri key parameter + */ + @TestApi + @SuppressLint("UnflaggedApi") // Test API public static final String VIBRATION_URI_PARAM = "vibration_uri"; + /** @hide + * Indicates the synchronized vibration + */ + @TestApi + @SuppressLint("UnflaggedApi") // Test API public static final String SYNCHRONIZED_VIBRATION = "synchronized"; /** * Sorts distinct (non-intersecting) range array in ascending order. * @throws java.lang.IllegalArgumentException if ranges are not distinct + * + * @hide */ public static <T extends Comparable<? super T>> void sortDistinctRanges(Range<T>[] ranges) { Arrays.sort(ranges, new Comparator<Range<T>>() { @@ -92,6 +108,8 @@ public class Utils { * @param one a sorted set of non-intersecting ranges in ascending order * @param another another sorted set of non-intersecting ranges in ascending order * @return the intersection of the two sets, sorted in ascending order + * + * @hide */ public static <T extends Comparable<? super T>> Range<T>[] intersectSortedDistinctRanges(Range<T>[] one, Range<T>[] another) { @@ -124,6 +142,8 @@ public class Utils { * @return if the value is in one of the ranges, it returns the index of that range. Otherwise, * the return value is {@code (-1-index)} for the {@code index} of the range that is * immediately following {@code value}. + * + * @hide */ public static <T extends Comparable<? super T>> int binarySearchDistinctRanges(Range<T>[] ranges, T value) { @@ -358,6 +378,8 @@ public class Utils { * @param fileName desired name for the file. * @param mimeType MIME type of the file to create. * @return the File object in the storage, or null if an error occurs. + * + * @hide */ public static File getUniqueExternalFile(Context context, String subdirectory, String fileName, String mimeType) { @@ -676,6 +698,8 @@ public class Utils { * Must match the implementation of BluetoothUtils.toAnonymizedAddress() * @param address MAC address to be anonymized * @return anonymized MAC address + * + * @hide */ public static @Nullable String anonymizeBluetoothAddress(@Nullable String address) { if (address == null) { @@ -693,6 +717,8 @@ public class Utils { * @param deviceType the internal type of the audio device * @param address MAC address to be anonymized * @return anonymized MAC address + * + * @hide */ public static @Nullable String anonymizeBluetoothAddress( int deviceType, @Nullable String address) { @@ -707,6 +733,8 @@ public class Utils { * * @param context the {@link Context} * @return {@code true} if the device supports ringtone vibration + * + * @hide */ public static boolean isRingtoneVibrationSettingsSupported(Context context) { final Resources res = context.getResources(); @@ -719,6 +747,8 @@ public class Utils { * * @param ringtoneUri the ringtone Uri * @return {@code true} if the Uri has vibration parameter + * + * @hide */ public static boolean hasVibration(Uri ringtoneUri) { if (ringtoneUri == null) { @@ -734,6 +764,8 @@ public class Utils { * @param ringtoneUri the ringtone Uri * @return parsed {@link Uri} of vibration parameter, {@code null} if the vibration parameter * is not found. + * + * @hide */ public static @Nullable Uri getVibrationUri(Uri ringtoneUri) { if (ringtoneUri == null) { @@ -751,6 +783,8 @@ public class Utils { * * @param vibrator the vibrator to resolve the vibration file * @param vibrationUri the vibration file Uri to represent a vibration + * + * @hide */ @SuppressWarnings("FlaggedApi") // VibrationXmlParser is available internally as hidden APIs. public static VibrationEffect parseVibrationEffect(Vibrator vibrator, Uri vibrationUri) { diff --git a/media/jni/OWNERS b/media/jni/OWNERS index fdddf13a0a23..84618a35cd4f 100644 --- a/media/jni/OWNERS +++ b/media/jni/OWNERS @@ -1,5 +1,5 @@ # extra for MTP related files -per-file android_mtp_*.cpp=aprasath@google.com,anothermark@google.com,kumarashishg@google.com,sarup@google.com,jsharkey@android.com,jameswei@google.com,rmojumder@google.com +per-file android_mtp_*.cpp=aprasath@google.com,anothermark@google.com,sarup@google.com,jsharkey@android.com,jameswei@google.com,rmojumder@google.com # extra for TV related files per-file android_media_tv_*=hgchen@google.com,quxiangfang@google.com diff --git a/native/webview/TEST_MAPPING b/native/webview/TEST_MAPPING index 38580595dc2d..c9b54760491a 100644 --- a/native/webview/TEST_MAPPING +++ b/native/webview/TEST_MAPPING @@ -17,15 +17,6 @@ "exclude-annotation": "android.test.FlakyTest" } ] - }, - { - "name": "GtsWebViewHostTestCases", - "keywords": ["internal"], - "options": [ - { - "exclude-annotation": "android.test.FlakyTest" - } - ] } ] } diff --git a/opengl/java/android/opengl/OWNERS b/opengl/java/android/opengl/OWNERS index e340bc62567a..4ec9e29c48b0 100644 --- a/opengl/java/android/opengl/OWNERS +++ b/opengl/java/android/opengl/OWNERS @@ -3,4 +3,3 @@ sumir@google.com prahladk@google.com ianelliott@google.com -lpy@google.com diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v36/settingslib_expressive_collapsing_toolbar_content_layout.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v36/settingslib_expressive_collapsing_toolbar_content_layout.xml index 6221659388d1..3db0ac653848 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v36/settingslib_expressive_collapsing_toolbar_content_layout.xml +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v36/settingslib_expressive_collapsing_toolbar_content_layout.xml @@ -41,6 +41,7 @@ android:id="@+id/action_bar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" + android:layout_marginStart="@dimen/settingslib_expressive_space_extrasmall4" android:theme="?android:attr/actionBarTheme" android:transitionName="shared_element_view" app:layout_collapseMode="pin"/> diff --git a/packages/SettingsLib/OWNERS b/packages/SettingsLib/OWNERS index 04df308e72a0..7348920dfd3d 100644 --- a/packages/SettingsLib/OWNERS +++ b/packages/SettingsLib/OWNERS @@ -8,6 +8,7 @@ edgarwang@google.com evanlaird@google.com jiannan@google.com juliacr@google.com +millchen@google.com ykhung@google.com # Exempt resource files (because they are in a flat directory and too hard to manage via OWNERS) diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background.xml index 9aa0bc39c5d8..0446873126b7 100644 --- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background.xml +++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background.xml @@ -19,16 +19,12 @@ android:color="?android:colorControlHighlight"> <item android:start="?android:attr/listPreferredItemPaddingStart" - android:end="?android:attr/listPreferredItemPaddingEnd" - android:top="2dp" - android:bottom="16dp"> + android:end="?android:attr/listPreferredItemPaddingEnd"> <shape android:shape="rectangle"> <solid android:color="@color/settingslib_materialColorSurfaceBright" /> <corners android:radius="@dimen/settingslib_preference_corner_radius" /> - <padding - android:bottom="16dp"/> </shape> </item> -</ripple>
\ No newline at end of file +</ripple> diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom.xml index 554cba565383..25a936deade5 100644 --- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom.xml +++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom.xml @@ -19,9 +19,7 @@ android:color="?android:colorControlHighlight"> <item android:start="?android:attr/listPreferredItemPaddingStart" - android:end="?android:attr/listPreferredItemPaddingEnd" - android:top="2dp" - android:bottom="16dp"> + android:end="?android:attr/listPreferredItemPaddingEnd"> <shape android:shape="rectangle"> <solid android:color="@color/settingslib_materialColorSurfaceBright" /> @@ -30,8 +28,6 @@ android:bottomLeftRadius="@dimen/settingslib_preference_corner_radius" android:topRightRadius="4dp" android:bottomRightRadius="@dimen/settingslib_preference_corner_radius" /> - <padding - android:bottom="16dp"/> </shape> </item> -</ripple>
\ No newline at end of file +</ripple> diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_highlighted.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_highlighted.xml index c0c08699cc2a..db2800e0ec41 100644 --- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_highlighted.xml +++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_highlighted.xml @@ -19,8 +19,7 @@ <item android:bottom="16dp" android:end="?android:attr/listPreferredItemPaddingEnd" - android:start="?android:attr/listPreferredItemPaddingStart" - android:top="2dp"> + android:start="?android:attr/listPreferredItemPaddingStart"> <shape android:shape="rectangle" android:tint="?android:attr/colorAccent"> @@ -29,8 +28,7 @@ android:bottomRightRadius="@dimen/settingslib_preference_corner_radius" android:topLeftRadius="4dp" android:topRightRadius="4dp" /> - <padding android:bottom="16dp" /> <solid android:color="#42000000" /> </shape> </item> -</ripple>
\ No newline at end of file +</ripple> diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_selected.xml index 543b237373fb..98f95d927fa6 100644 --- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_selected.xml +++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_selected.xml @@ -19,9 +19,7 @@ android:color="?android:colorControlHighlight"> <item android:start="?android:attr/listPreferredItemPaddingStart" - android:end="?android:attr/listPreferredItemPaddingEnd" - android:top="2dp" - android:bottom="16dp"> + android:end="?android:attr/listPreferredItemPaddingEnd"> <shape android:shape="rectangle"> <solid android:color="@color/settingslib_materialColorSurfaceContainer" /> @@ -30,8 +28,6 @@ android:bottomLeftRadius="@dimen/settingslib_preference_corner_radius" android:topRightRadius="4dp" android:bottomRightRadius="@dimen/settingslib_preference_corner_radius" /> - <padding - android:bottom="16dp"/> </shape> </item> -</ripple>
\ No newline at end of file +</ripple> diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center.xml index b89a0ddcdec5..c4286fdf020c 100644 --- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center.xml +++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center.xml @@ -19,8 +19,7 @@ android:color="?android:colorControlHighlight"> <item android:start="?android:attr/listPreferredItemPaddingStart" - android:end="?android:attr/listPreferredItemPaddingEnd" - android:top="2dp"> + android:end="?android:attr/listPreferredItemPaddingEnd"> <shape android:shape="rectangle"> <solid android:color="@color/settingslib_materialColorSurfaceBright" /> @@ -28,4 +27,4 @@ android:radius="4dp" /> </shape> </item> -</ripple>
\ No newline at end of file +</ripple> diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_highlighted.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_highlighted.xml index 8099d9b3d7f7..194cdb00a337 100644 --- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_highlighted.xml +++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_highlighted.xml @@ -18,8 +18,7 @@ android:color="?android:colorControlHighlight"> <item android:end="?android:attr/listPreferredItemPaddingEnd" - android:start="?android:attr/listPreferredItemPaddingStart" - android:top="2dp"> + android:start="?android:attr/listPreferredItemPaddingStart"> <shape android:shape="rectangle" android:tint="?android:attr/colorAccent"> @@ -27,4 +26,4 @@ <solid android:color="#42000000" /> </shape> </item> -</ripple>
\ No newline at end of file +</ripple> diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_selected.xml index 6d2cd1a51620..8bc2f2f9ccd1 100644 --- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_selected.xml +++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_selected.xml @@ -19,8 +19,7 @@ android:color="?android:colorControlHighlight"> <item android:start="?android:attr/listPreferredItemPaddingStart" - android:end="?android:attr/listPreferredItemPaddingEnd" - android:top="2dp"> + android:end="?android:attr/listPreferredItemPaddingEnd"> <shape android:shape="rectangle"> <solid android:color="@color/settingslib_materialColorSurfaceContainer" /> @@ -28,4 +27,4 @@ android:radius="4dp" /> </shape> </item> -</ripple>
\ No newline at end of file +</ripple> diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_highlighted.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_highlighted.xml index a119a4ae083f..2341661528d9 100644 --- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_highlighted.xml +++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_highlighted.xml @@ -19,14 +19,12 @@ <item android:bottom="16dp" android:end="?android:attr/listPreferredItemPaddingEnd" - android:start="?android:attr/listPreferredItemPaddingStart" - android:top="2dp"> + android:start="?android:attr/listPreferredItemPaddingStart"> <shape android:shape="rectangle" android:tint="?android:attr/colorAccent"> <corners android:radius="@dimen/settingslib_preference_corner_radius" /> - <padding android:bottom="16dp" /> <solid android:color="#42000000" /> </shape> </item> -</ripple>
\ No newline at end of file +</ripple> diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_selected.xml index bcdbf1d19545..99704f2df190 100644 --- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_selected.xml +++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_selected.xml @@ -19,16 +19,12 @@ android:color="?android:colorControlHighlight"> <item android:start="?android:attr/listPreferredItemPaddingStart" - android:end="?android:attr/listPreferredItemPaddingEnd" - android:top="2dp" - android:bottom="16dp"> + android:end="?android:attr/listPreferredItemPaddingEnd"> <shape android:shape="rectangle"> <solid android:color="@color/settingslib_materialColorSurfaceContainer" /> <corners android:radius="@dimen/settingslib_preference_corner_radius" /> - <padding - android:bottom="16dp"/> </shape> </item> -</ripple>
\ No newline at end of file +</ripple> diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top.xml index 7955e4418ae9..3a5938688f34 100644 --- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top.xml +++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top.xml @@ -19,8 +19,7 @@ android:color="?android:colorControlHighlight"> <item android:start="?android:attr/listPreferredItemPaddingStart" - android:end="?android:attr/listPreferredItemPaddingEnd" - android:top="2dp"> + android:end="?android:attr/listPreferredItemPaddingEnd"> <shape android:shape="rectangle"> <solid android:color="@color/settingslib_materialColorSurfaceBright" /> @@ -31,4 +30,4 @@ android:bottomRightRadius="4dp" /> </shape> </item> -</ripple>
\ No newline at end of file +</ripple> diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_highlighted.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_highlighted.xml index 052eb01cab8d..edace29df37a 100644 --- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_highlighted.xml +++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_highlighted.xml @@ -19,8 +19,7 @@ <item android:color="?android:attr/colorAccent" android:end="?android:attr/listPreferredItemPaddingEnd" - android:start="?android:attr/listPreferredItemPaddingStart" - android:top="2dp"> + android:start="?android:attr/listPreferredItemPaddingStart"> <shape android:shape="rectangle" android:tint="?android:attr/colorAccent"> @@ -32,4 +31,4 @@ <solid android:color="#42000000" /> </shape> </item> -</ripple>
\ No newline at end of file +</ripple> diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_selected.xml index d4b658c384e6..b2d6d9da6af8 100644 --- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_selected.xml +++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_selected.xml @@ -19,8 +19,7 @@ android:color="?android:colorControlHighlight"> <item android:start="?android:attr/listPreferredItemPaddingStart" - android:end="?android:attr/listPreferredItemPaddingEnd" - android:top="2dp"> + android:end="?android:attr/listPreferredItemPaddingEnd"> <shape android:shape="rectangle"> <solid android:color="@color/settingslib_materialColorSurfaceContainer" /> @@ -31,4 +30,4 @@ android:bottomRightRadius="4dp" /> </shape> </item> -</ripple>
\ No newline at end of file +</ripple> diff --git a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/NormalPaddingMixin.kt b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/NormalPaddingMixin.kt new file mode 100644 index 000000000000..5035542b9783 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/NormalPaddingMixin.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2024 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.settingslib.widget + +/** + * A base interface to indicate that a Preference should have normal paddings. + * + * Preferences implementing this interface will be treated as has normal paddings both inside and + * outside. + */ +interface NormalPaddingMixin
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsBasePreferenceFragment.kt b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsBasePreferenceFragment.kt index 8d12f01e24ed..22cd87307a42 100644 --- a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsBasePreferenceFragment.kt +++ b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsBasePreferenceFragment.kt @@ -16,6 +16,7 @@ package com.android.settingslib.widget +import android.graphics.Rect import android.os.Bundle import android.view.LayoutInflater; import android.view.View @@ -24,6 +25,7 @@ import androidx.annotation.CallSuper import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceScreen import androidx.recyclerview.widget.RecyclerView +import com.android.settingslib.widget.theme.R /** Base class for Settings to use PreferenceFragmentCompat */ abstract class SettingsBasePreferenceFragment : PreferenceFragmentCompat() { @@ -43,6 +45,7 @@ abstract class SettingsBasePreferenceFragment : PreferenceFragmentCompat() { if (SettingsThemeHelper.isExpressiveTheme(requireContext())) { // Don't allow any divider in between the preferences in expressive design. setDivider(null) + this.listView.addItemDecoration(MarginItemDecoration()) } } @@ -51,4 +54,18 @@ abstract class SettingsBasePreferenceFragment : PreferenceFragmentCompat() { return SettingsPreferenceGroupAdapter(preferenceScreen) return super.onCreateAdapter(preferenceScreen) } + + internal class MarginItemDecoration() : RecyclerView.ItemDecoration() { + override fun getItemOffsets( + outRect: Rect, + view: View, + parent: RecyclerView, + state: RecyclerView.State, + ) { + with(outRect) { + bottom = + view.resources.getDimensionPixelSize(R.dimen.settingslib_expressive_radius_extrasmall1) + } + } + } } diff --git a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsPreferenceGroupAdapter.kt b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsPreferenceGroupAdapter.kt index a04fce7eeb86..2672787a0519 100644 --- a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsPreferenceGroupAdapter.kt +++ b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsPreferenceGroupAdapter.kt @@ -177,14 +177,32 @@ open class SettingsPreferenceGroupAdapter(preferenceGroup: PreferenceGroup) : val v = holder.itemView // Update padding if (SettingsThemeHelper.isExpressiveTheme(context)) { - val paddingStart = if (backgroundRes == 0) mNormalPaddingStart else mGroupPaddingStart - val paddingEnd = if (backgroundRes == 0) mNormalPaddingEnd else mGroupPaddingEnd + val (paddingStart, paddingEnd) = getStartEndPadding(position, backgroundRes) v.setPaddingRelative(paddingStart, v.paddingTop, paddingEnd, v.paddingBottom) + v.clipToOutline = backgroundRes != 0 } // Update background v.setBackgroundResource(backgroundRes) } + private fun getStartEndPadding(position: Int, backgroundRes: Int): Pair<Int, Int> { + val item = getItem(position) + return when { + // This item handles edge to edge itself + item is NormalPaddingMixin && item is GroupSectionDividerMixin -> 0 to 0 + + // According to mappingPreferenceGroup(), backgroundRes == 0 means this item is + // GroupSectionDividerMixin or PreferenceCategory, which is design to have normal + // padding. + // NormalPaddingMixin items are also designed to have normal padding. + backgroundRes == 0 || item is NormalPaddingMixin -> + mNormalPaddingStart to mNormalPaddingEnd + + // Other items are suppose to have group padding. + else -> mGroupPaddingStart to mGroupPaddingEnd + } + } + @DrawableRes protected fun getRoundCornerDrawableRes(position: Int, isSelected: Boolean): Int { return getRoundCornerDrawableRes(position, isSelected, false) diff --git a/packages/SettingsLib/SliderPreference/src/com/android/settingslib/widget/SliderPreference.java b/packages/SettingsLib/SliderPreference/src/com/android/settingslib/widget/SliderPreference.java index 4315238ad7c1..fe8e8b6f1d46 100644 --- a/packages/SettingsLib/SliderPreference/src/com/android/settingslib/widget/SliderPreference.java +++ b/packages/SettingsLib/SliderPreference/src/com/android/settingslib/widget/SliderPreference.java @@ -22,6 +22,7 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.os.Parcel; import android.os.Parcelable; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; @@ -72,6 +73,7 @@ public class SliderPreference extends Preference { private int mSliderIncrement; private boolean mAdjustable; private boolean mTrackingTouch; + private CharSequence mSliderContentDescription; /** * Listener reacting to the user pressing DPAD left/right keys if {@code @@ -143,6 +145,7 @@ public class SliderPreference extends Preference { @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setLayoutResource(R.layout.settingslib_expressive_preference_slider); + setSelectable(false); TypedArray a = context.obtainStyledAttributes( attrs, androidx.preference.R.styleable.SeekBarPreference, defStyleAttr, @@ -265,6 +268,14 @@ public class SliderPreference extends Preference { } else { mSliderIncrement = (int) (mSlider.getStepSize()); } + final CharSequence title = getTitle(); + if (!TextUtils.isEmpty(mSliderContentDescription)) { + mSlider.setContentDescription(mSliderContentDescription); + } else if (!TextUtils.isEmpty(title)) { + mSlider.setContentDescription(title); + } else { + mSlider.setContentDescription(null); + } mSlider.setValueFrom(mMin); mSlider.setValueTo(mMax); mSlider.setValue(mSliderValue); @@ -273,6 +284,8 @@ public class SliderPreference extends Preference { mSlider.clearOnChangeListeners(); mSlider.addOnChangeListener(mChangeListener); mSlider.setEnabled(isEnabled()); + mSlider.setFocusable(isSelectable()); + mSlider.setClickable(isSelectable()); // Set up slider color mSlider.setTrackActiveTintList(mTrackActiveColor); @@ -471,6 +484,19 @@ public class SliderPreference extends Preference { setValueInternal(sliderValue, true); } + + /** + * Sets the content description of the {@link Slider}. + * + * @param contentDescription The content description of the {@link Slider} + */ + public void setSliderContentDescription(@Nullable CharSequence contentDescription) { + mSliderContentDescription = contentDescription; + if (mSlider != null) { + mSlider.setContentDescription(contentDescription); + } + } + @Override protected void onSetInitialValue(@Nullable Object defaultValue) { if (defaultValue == null) { diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS b/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS index b9449acc6f7d..50bfe8c7cd78 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS @@ -1,6 +1,5 @@ # Default reviewers for this and subdirectories. andychou@google.com -arcwang@google.com asapperstein@google.com changbetty@google.com qal@google.com diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java index c98a741f8254..99c4e21c6053 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -456,11 +456,16 @@ public class SettingsState { @GuardedBy("mLock") private void loadAconfigDefaultValuesLocked(List<String> filePaths) { for (String fileName : filePaths) { - try (FileInputStream inputStream = new FileInputStream(fileName)) { - loadAconfigDefaultValues( - inputStream.readAllBytes(), mNamespaceDefaults, mAconfigDefaultFlags); - } catch (IOException e) { - Slog.e(LOG_TAG, "failed to read protobuf", e); + File f = new File(fileName); + if (f.isFile() && f.canRead()) { + try (FileInputStream inputStream = new FileInputStream(fileName)) { + loadAconfigDefaultValues( + inputStream.readAllBytes(), mNamespaceDefaults, mAconfigDefaultFlags); + } catch (IOException e) { + Slog.e(LOG_TAG, "failed to read protobuf", e); + } + } else { + Slog.d(LOG_TAG, "No protobuf file at " + fileName); } } } diff --git a/packages/Shell/OWNERS b/packages/Shell/OWNERS index 576afdc824f2..897c1fe7639e 100644 --- a/packages/Shell/OWNERS +++ b/packages/Shell/OWNERS @@ -4,12 +4,9 @@ ronish@google.com jsharkey@android.com felipeal@google.com nandana@google.com -svetoslavganov@google.com hackbod@google.com yamasani@google.com -toddke@google.com patb@google.com -cbrubaker@google.com omakoto@google.com michaelwr@google.com ronish@google.com diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt index 2c6d09a4593a..2d03e2bcdd19 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt @@ -23,7 +23,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.layout.Layout -import androidx.compose.ui.layout.Measurable import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntRect @@ -35,7 +34,6 @@ import com.android.systemui.communal.smartspace.SmartspaceInteractionHandler import com.android.systemui.communal.ui.compose.section.AmbientStatusBarSection import com.android.systemui.communal.ui.compose.section.CommunalLockSection import com.android.systemui.communal.ui.compose.section.CommunalPopupSection -import com.android.systemui.communal.ui.compose.section.CommunalToDreamButtonSection import com.android.systemui.communal.ui.compose.section.HubOnboardingSection import com.android.systemui.communal.ui.view.layout.sections.CommunalAppWidgetSection import com.android.systemui.communal.ui.viewmodel.CommunalViewModel @@ -61,7 +59,6 @@ constructor( private val ambientStatusBarSection: AmbientStatusBarSection, private val communalPopupSection: CommunalPopupSection, private val widgetSection: CommunalAppWidgetSection, - private val communalToDreamButtonSection: CommunalToDreamButtonSection, private val hubOnboardingSection: HubOnboardingSection, ) { @@ -103,13 +100,11 @@ constructor( Modifier.element(Communal.Elements.IndicationArea).fillMaxWidth() ) } - with(communalToDreamButtonSection) { Button() } }, ) { measurables, constraints -> val communalGridMeasurable = measurables[0] val lockIconMeasurable = measurables[1] val bottomAreaMeasurable = measurables[2] - val screensaverButtonMeasurable: Measurable? = measurables.getOrNull(3) val noMinConstraints = constraints.copy(minWidth = 0, minHeight = 0) @@ -152,9 +147,6 @@ constructor( val bottomAreaPlaceable = bottomAreaMeasurable.measure(noMinConstraints) - val screensaverButtonPlaceable = - screensaverButtonMeasurable?.measure(noMinConstraints) - val communalGridPlaceable = communalGridMeasurable.measure( noMinConstraints.copy(maxHeight = lockIconBounds.top) @@ -166,26 +158,12 @@ constructor( val bottomAreaTop = constraints.maxHeight - bottomAreaPlaceable.height bottomAreaPlaceable.place(x = 0, y = bottomAreaTop) - - val screensaverButtonPaddingInt = screensaverButtonPadding.roundToPx() - screensaverButtonPlaceable?.place( - x = - constraints.maxWidth - - screensaverButtonPaddingInt - - screensaverButtonPlaceable.width, - y = - constraints.maxHeight - - screensaverButtonPaddingInt - - screensaverButtonPlaceable.height, - ) } } } } companion object { - private val screensaverButtonPadding: Dp = 24.dp - // TODO(b/382739998): Remove these hardcoded values once lock icon size and bottom area // position are sorted. private val lockIconSize: Dp = 54.dp diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/CommunalToDreamButtonSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/CommunalToDreamButtonSection.kt deleted file mode 100644 index acaf43a62f43..000000000000 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/CommunalToDreamButtonSection.kt +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (C) 2024 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.communal.ui.compose.section - -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.core.MutableTransitionState -import androidx.compose.animation.expandVertically -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.shrinkVertically -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.widthIn -import androidx.compose.foundation.shape.CornerSize -import androidx.compose.material3.IconButtonDefaults -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.geometry.CornerRadius -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.geometry.RoundRect -import androidx.compose.ui.geometry.Size -import androidx.compose.ui.geometry.toRect -import androidx.compose.ui.graphics.Outline -import androidx.compose.ui.graphics.Path -import androidx.compose.ui.graphics.Shape -import androidx.compose.ui.input.pointer.pointerInput -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.Density -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.LayoutDirection -import androidx.compose.ui.unit.dp -import com.android.compose.PlatformIconButton -import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor -import com.android.systemui.communal.ui.compose.extensions.observeTaps -import com.android.systemui.communal.ui.viewmodel.CommunalToDreamButtonViewModel -import com.android.systemui.lifecycle.rememberViewModel -import com.android.systemui.res.R -import javax.inject.Inject -import kotlin.time.Duration.Companion.seconds -import kotlinx.coroutines.delay - -class CommunalToDreamButtonSection -@Inject -constructor( - private val communalSettingsInteractor: CommunalSettingsInteractor, - private val viewModelFactory: CommunalToDreamButtonViewModel.Factory, -) { - @Composable - fun Button() { - if (!communalSettingsInteractor.isV2FlagEnabled()) { - return - } - - val viewModel = - rememberViewModel("CommunalToDreamButtonSection") { viewModelFactory.create() } - - if (!viewModel.shouldShowDreamButtonOnHub) { - return - } - - val buttonSize = dimensionResource(R.dimen.communal_to_dream_button_size) - - if (viewModel.shouldShowTooltip) { - val tooltipVisibleState = remember { MutableTransitionState(false) } - - Column( - modifier = - Modifier.widthIn(max = tooltipMaxWidth).pointerInput(Unit) { - observeTaps { - if (tooltipVisibleState.isCurrentlyVisible()) { - tooltipVisibleState.targetState = false - } - } - } - ) { - var waitingToShowTooltip by remember { mutableStateOf(true) } - - LaunchedEffect(tooltipVisibleState.targetState) { - delay(3.seconds) - tooltipVisibleState.targetState = true - waitingToShowTooltip = false - } - - // This LaunchedEffect is used to wait for the tooltip dismiss animation to - // complete before setting the tooltip dismissed. Otherwise, the composable would - // be removed before the animation can start. - LaunchedEffect( - tooltipVisibleState.currentState, - tooltipVisibleState.isIdle, - waitingToShowTooltip, - ) { - if ( - !waitingToShowTooltip && - !tooltipVisibleState.currentState && - tooltipVisibleState.isIdle - ) { - viewModel.setDreamButtonTooltipDismissed() - } - } - - AnimatedVisibility( - visibleState = tooltipVisibleState, - enter = fadeIn() + expandVertically(expandFrom = Alignment.Bottom), - exit = fadeOut() + shrinkVertically(shrinkTowards = Alignment.Bottom), - ) { - Tooltip( - pointerOffsetDp = buttonSize.div(2), - text = stringResource(R.string.glanceable_hub_to_dream_button_tooltip), - ) - } - - GoToDreamButton( - modifier = Modifier.width(buttonSize).height(buttonSize).align(Alignment.End) - ) { - viewModel.onShowDreamButtonTap() - } - } - } else { - GoToDreamButton(modifier = Modifier.width(buttonSize).height(buttonSize)) { - viewModel.onShowDreamButtonTap() - } - } - } - - private fun MutableTransitionState<Boolean>.isCurrentlyVisible() = currentState && isIdle - - companion object { - private val tooltipMaxWidth = 350.dp - } -} - -@Composable -private fun GoToDreamButton(modifier: Modifier, onClick: () -> Unit) { - PlatformIconButton( - modifier = modifier, - onClick = onClick, - iconResource = R.drawable.ic_screensaver_auto, - contentDescription = stringResource(R.string.accessibility_glanceable_hub_to_dream_button), - colors = - IconButtonDefaults.filledIconButtonColors( - contentColor = MaterialTheme.colorScheme.onPrimaryContainer, - containerColor = MaterialTheme.colorScheme.primaryContainer, - ), - ) -} - -@Composable -private fun Tooltip(pointerOffsetDp: Dp, text: String) { - Surface( - color = MaterialTheme.colorScheme.surface, - shape = TooltipShape(pointerSizeDp = 12.dp, pointerOffsetDp = pointerOffsetDp), - ) { - Text( - modifier = Modifier.padding(start = 32.dp, top = 16.dp, end = 32.dp, bottom = 32.dp), - color = MaterialTheme.colorScheme.onSurface, - text = text, - ) - } - - Spacer(modifier = Modifier.height(4.dp)) -} - -private class TooltipShape(private val pointerSizeDp: Dp, private val pointerOffsetDp: Dp) : Shape { - - override fun createOutline( - size: Size, - layoutDirection: LayoutDirection, - density: Density, - ): Outline { - - val pointerSizePx = with(density) { pointerSizeDp.toPx() } - val pointerOffsetPx = with(density) { pointerOffsetDp.toPx() } - val cornerRadius = CornerRadius(CornerSize(16.dp).toPx(size, density)) - val bubbleSize = size.copy(height = size.height - pointerSizePx) - - val path = - Path().apply { - addRoundRect( - RoundRect( - rect = bubbleSize.toRect(), - topLeft = cornerRadius, - topRight = cornerRadius, - bottomRight = cornerRadius, - bottomLeft = cornerRadius, - ) - ) - addPath( - Path().apply { - moveTo(0f, 0f) - lineTo(pointerSizePx / 2f, pointerSizePx) - lineTo(pointerSizePx, 0f) - close() - }, - offset = - Offset( - x = bubbleSize.width - pointerOffsetPx - pointerSizePx / 2f, - y = bubbleSize.height, - ), - ) - } - - return Outline.Generic(path) - } -} diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt index b59b4ab34c80..06484128ed6c 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt @@ -103,6 +103,7 @@ open class ClockRegistry( fun onAvailableClocksChanged() {} } + private val replacementMap = ConcurrentHashMap<ClockId, ClockId>() private val availableClocks = ConcurrentHashMap<ClockId, ClockInfo>() private val clockChangeListeners = mutableListOf<ClockChangeListener>() private val settingObserver = @@ -209,6 +210,7 @@ open class ClockRegistry( continue } + clock.replacementTarget?.let { replacementMap[id] = it } info.provider = plugin onLoaded(info) } @@ -393,10 +395,11 @@ open class ClockRegistry( // TODO: Merge w/ CurrentClockId when we convert to a flow. We shouldn't need both behaviors. val activeClockId: String get() { - if (!availableClocks.containsKey(currentClockId)) { + var id = currentClockId + if (!availableClocks.containsKey(id)) { return DEFAULT_CLOCK_ID } - return currentClockId + return replacementMap[id] ?: id } init { @@ -404,6 +407,7 @@ open class ClockRegistry( defaultClockProvider.initialize(clockBuffers) for (clock in defaultClockProvider.getClocks()) { availableClocks[clock.clockId] = ClockInfo(clock, defaultClockProvider, null) + clock.replacementTarget?.let { replacementMap[clock.clockId] = it } } // Something has gone terribly wrong if the default clock isn't present @@ -562,9 +566,12 @@ open class ClockRegistry( } } - fun getClocks(): List<ClockMetadata> { - if (!isEnabled) return listOf(availableClocks[DEFAULT_CLOCK_ID]!!.metadata) - return availableClocks.map { (_, clock) -> clock.metadata } + fun getClocks(includeDeprecated: Boolean = false): List<ClockMetadata> { + return when { + !isEnabled -> listOf(availableClocks[DEFAULT_CLOCK_ID]!!.metadata) + includeDeprecated -> availableClocks.map { (_, clock) -> clock.metadata } + else -> availableClocks.map { (_, clock) -> clock.metadata }.filter { !it.isDeprecated } + } } fun getClockPickerConfig(clockId: ClockId): ClockPickerConfig? { diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt index 654478af3fb0..c3935e68ca04 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt @@ -61,7 +61,14 @@ class DefaultClockProvider( override fun getClocks(): List<ClockMetadata> { var clocks = listOf(ClockMetadata(DEFAULT_CLOCK_ID)) - if (isClockReactiveVariantsEnabled) clocks += ClockMetadata(FLEX_CLOCK_ID) + if (isClockReactiveVariantsEnabled) { + clocks += + ClockMetadata( + FLEX_CLOCK_ID, + isDeprecated = true, + replacementTarget = DEFAULT_CLOCK_ID, + ) + } return clocks } diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt index 189d554415d0..f4d4b1efa3e2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt @@ -25,6 +25,8 @@ import android.view.Gravity import android.view.LayoutInflater import android.view.MotionEvent import android.view.View +import android.view.ViewTreeObserver +import android.view.ViewTreeObserver.OnPreDrawListener import android.view.WindowInsetsController import android.widget.FrameLayout import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -720,6 +722,37 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { } @Test + fun startAppearAnimation_ifDelayed() { + val argumentCaptor = ArgumentCaptor.forClass(OnPreDrawListener::class.java) + whenever(view.isAppearAnimationDelayed).thenReturn(true) + val viewTreeObserver: ViewTreeObserver = mock() + whenever(view.viewTreeObserver).thenReturn(viewTreeObserver) + + underTest.startAppearAnimationIfDelayed() + + verify(view).alpha = 1f + verify(viewTreeObserver).addOnPreDrawListener(argumentCaptor.capture()) + argumentCaptor.value.onPreDraw() + + verify(view).startAppearAnimation(any(SecurityMode::class.java)) + verify(view).setIsAppearAnimationDelayed(false) + } + + @Test + fun appearAnimation_willNotStart_ifNotDelayed() { + whenever(view.isAppearAnimationDelayed).thenReturn(false) + val viewTreeObserver: ViewTreeObserver = mock() + whenever(view.viewTreeObserver).thenReturn(viewTreeObserver) + + underTest.startAppearAnimationIfDelayed() + + verify(view, never()).alpha + verify(viewTreeObserver, never()).addOnPreDrawListener(any()) + + verify(view, never()).startAppearAnimation(any(SecurityMode::class.java)) + } + + @Test fun gravityReappliedOnConfigurationChange() { // Set initial gravity testableResources.addOverride(R.integer.keyguard_host_view_gravity, Gravity.CENTER) diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerTest.java index 176824fd4c5d..2845f6a2983a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerTest.java @@ -452,6 +452,14 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { verify(keyguardPasswordView).setDisappearAnimationListener(any()); } + @Test + public void setupForDelayedAppear() { + mKeyguardSecurityContainer.setupForDelayedAppear(); + assertThat(mKeyguardSecurityContainer.getTranslationY()).isEqualTo(0f); + assertThat(mKeyguardSecurityContainer.getAlpha()).isEqualTo(0f); + assertThat(mKeyguardSecurityContainer.isAppearAnimationDelayed()).isTrue(); + } + private BackEvent createBackEvent(float touchX, float progress) { return new BackEvent(0, 0, progress, BackEvent.EDGE_LEFT); } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java index f53f964cd3d9..191ecccd5f71 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java @@ -28,6 +28,8 @@ import static org.mockito.Mockito.when; import android.animation.ValueAnimator; import android.content.pm.UserInfo; +import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Rect; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; @@ -54,6 +56,7 @@ import com.android.systemui.scene.ui.view.WindowRootView; import com.android.systemui.shared.system.InputChannelCompat; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.CentralSurfaces; +import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.wm.shell.animation.FlingAnimationUtils; import org.junit.Before; @@ -127,10 +130,16 @@ public class BouncerFullscreenSwipeTouchHandlerTest extends SysuiTestCase { @Mock WindowRootView mWindowRootView; + @Mock + Resources mResources; + private SceneInteractor mSceneInteractor; + private KeyguardStateController mKeyguardStateController; + private static final float TOUCH_REGION = .3f; private static final float MIN_BOUNCER_HEIGHT = .05f; + private final Configuration mConfiguration = new Configuration(); private static final Rect SCREEN_BOUNDS = new Rect(0, 0, 1024, 100); private static final UserInfo CURRENT_USER_INFO = new UserInfo( @@ -153,6 +162,8 @@ public class BouncerFullscreenSwipeTouchHandlerTest extends SysuiTestCase { public void setup() { mKosmos = new KosmosJavaAdapter(this); mSceneInteractor = spy(mKosmos.getSceneInteractor()); + mKeyguardStateController = mKosmos.getKeyguardStateController(); + mConfiguration.orientation = Configuration.ORIENTATION_PORTRAIT; MockitoAnnotations.initMocks(this); mTouchHandler = new BouncerSwipeTouchHandler( @@ -172,7 +183,9 @@ public class BouncerFullscreenSwipeTouchHandlerTest extends SysuiTestCase { mKeyguardInteractor, mSceneInteractor, mKosmos.getShadeRepository(), - Optional.of(() -> mWindowRootView)); + Optional.of(() -> mWindowRootView), + mKeyguardStateController, + mKosmos.getCommunalSettingsInteractor()); when(mScrimManager.getCurrentController()).thenReturn(mScrimController); when(mValueAnimatorCreator.create(anyFloat(), anyFloat())).thenReturn(mValueAnimator); @@ -180,6 +193,9 @@ public class BouncerFullscreenSwipeTouchHandlerTest extends SysuiTestCase { when(mFlingAnimationUtils.getMinVelocityPxPerSecond()).thenReturn(Float.MAX_VALUE); when(mTouchSession.getBounds()).thenReturn(SCREEN_BOUNDS); when(mKeyguardInteractor.isKeyguardDismissible()).thenReturn(MutableStateFlow(false)); + when(mKeyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(true); + when(mWindowRootView.getResources()).thenReturn(mResources); + when(mResources.getConfiguration()).thenReturn(mConfiguration); } /** diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java index dd43d817cccc..e8dc6762cc92 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java @@ -16,6 +16,10 @@ package com.android.systemui.ambient.touch; +import static android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf; + +import static com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2; + import static com.google.common.truth.Truth.assertThat; import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow; @@ -34,6 +38,8 @@ import static org.mockito.Mockito.when; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.content.pm.UserInfo; +import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Rect; import android.graphics.Region; import android.platform.test.annotations.DisableFlags; @@ -63,6 +69,7 @@ import com.android.systemui.shade.ShadeExpansionChangeEvent; import com.android.systemui.shared.system.InputChannelCompat; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.CentralSurfaces; +import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.wm.shell.animation.FlingAnimationUtils; import org.junit.Before; @@ -132,12 +139,16 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { @Mock WindowRootView mWindowRootView; + Resources mResources; + @Mock CommunalViewModel mCommunalViewModel; @Mock KeyguardInteractor mKeyguardInteractor; + private KeyguardStateController mKeyguardStateController; + @Captor ArgumentCaptor<Rect> mRectCaptor; @@ -147,6 +158,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { private static final int SCREEN_WIDTH_PX = 1024; private static final int SCREEN_HEIGHT_PX = 100; private static final float MIN_BOUNCER_HEIGHT = .05f; + private final Configuration mConfiguration = new Configuration(); private static final Rect SCREEN_BOUNDS = new Rect(0, 0, 1024, 100); private static final UserInfo CURRENT_USER_INFO = new UserInfo( @@ -157,7 +169,8 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { @Parameters(name = "{0}") public static List<FlagsParameterization> getParams() { - return SceneContainerFlagParameterizationKt.parameterizeSceneContainerFlag(); + return SceneContainerFlagParameterizationKt + .andSceneContainer(allCombinationsOf(Flags.FLAG_GLANCEABLE_HUB_V2)); } public BouncerSwipeTouchHandlerTest(FlagsParameterization flags) { @@ -168,7 +181,13 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { @Before public void setup() { mKosmos = new KosmosJavaAdapter(this); + mContext.ensureTestableResources(); + mResources = mContext.getResources(); + overrideConfiguration(mConfiguration); + mConfiguration.orientation = Configuration.ORIENTATION_PORTRAIT; + mSceneInteractor = spy(mKosmos.getSceneInteractor()); + mKeyguardStateController = mKosmos.getKeyguardStateController(); MockitoAnnotations.initMocks(this); mTouchHandler = new BouncerSwipeTouchHandler( @@ -188,7 +207,9 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { mKeyguardInteractor, mSceneInteractor, mKosmos.getShadeRepository(), - Optional.of(() -> mWindowRootView) + Optional.of(() -> mWindowRootView), + mKeyguardStateController, + mKosmos.getCommunalSettingsInteractor() ); when(mScrimManager.getCurrentController()).thenReturn(mScrimController); @@ -197,6 +218,9 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { when(mFlingAnimationUtils.getMinVelocityPxPerSecond()).thenReturn(Float.MAX_VALUE); when(mTouchSession.getBounds()).thenReturn(SCREEN_BOUNDS); when(mKeyguardInteractor.isKeyguardDismissible()).thenReturn(MutableStateFlow(false)); + when(mKeyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(true); + when(mWindowRootView.getResources()).thenReturn(mResources); + setCommunalV2ConfigEnabled(true); } /** @@ -586,6 +610,43 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { verify(mUiEventLogger).log(BouncerSwipeTouchHandler.DreamEvent.DREAM_BOUNCER_FULLY_VISIBLE); } + @Test + @DisableFlags(Flags.FLAG_SCENE_CONTAINER) + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) + public void swipeUpAboveThresholdInLandscape_keyguardRotationNotAllowed_showsBouncer() { + when(mKeyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(false); + mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE; + + final float swipeUpPercentage = .1f; + // The upward velocity is ignored. + final float velocityY = -1; + swipeToPosition(swipeUpPercentage, velocityY); + + // Ensure show bouncer scrimmed + verify(mScrimController).show(true); + verify(mValueAnimatorCreator, never()).create(anyFloat(), anyFloat()); + verify(mValueAnimator, never()).start(); + } + + @Test + @DisableFlags(Flags.FLAG_SCENE_CONTAINER) + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) + public void swipeUpBelowThreshold_inLandscapeKeyguardRotationNotAllowed_noBouncer() { + mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE; + + final float swipeUpPercentage = .02f; + // The upward velocity is ignored. + final float velocityY = -1; + swipeToPosition(swipeUpPercentage, velocityY); + + // no bouncer shown scrimmed + verify(mScrimController, never()).show(true); + // on touch end, bouncer hidden + verify(mValueAnimatorCreator).create(eq(1 - swipeUpPercentage), + eq(KeyguardBouncerConstants.EXPANSION_HIDDEN)); + verify(mValueAnimator, never()).addListener(any()); + } + /** * Tests that swiping up with a speed above the set threshold will continue the expansion. */ @@ -672,4 +733,15 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { inputEventListenerCaptor.getValue().onInputEvent(upEvent); } + + private void setCommunalV2ConfigEnabled(boolean enabled) { + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.bool.config_glanceableHubEnabled, + enabled); + } + + private void overrideConfiguration(Configuration configuration) { + mContext.getOrCreateTestableResources().overrideConfiguration( + configuration); + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt index 7051f81cfc88..f58391496e65 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt @@ -22,6 +22,7 @@ import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization import android.provider.Settings import androidx.test.filters.SmallTest +import com.android.compose.animation.scene.ObservableTransitionState import com.android.internal.logging.uiEventLoggerFake import com.android.systemui.Flags.FLAG_COMMUNAL_HUB import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 @@ -38,8 +39,13 @@ import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED import com.android.systemui.flags.andSceneContainer import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.keyguardInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.collectLastValue @@ -56,11 +62,15 @@ import com.google.common.truth.Truth.assertThat import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.advanceTimeBy import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Mockito +import org.mockito.kotlin.verify import platform.test.runner.parameterized.ParameterizedAndroidJunit4 import platform.test.runner.parameterized.Parameters @@ -93,10 +103,12 @@ class CommunalSceneStartableTest(flags: FlagsParameterization) : SysuiTestCase() communalInteractor = communalInteractor, communalSettingsInteractor = communalSettingsInteractor, communalSceneInteractor = communalSceneInteractor, + keyguardTransitionInteractor = keyguardTransitionInteractor, keyguardInteractor = keyguardInteractor, systemSettings = fakeSettings, notificationShadeWindowController = notificationShadeWindowController, bgScope = applicationCoroutineScope, + applicationScope = applicationCoroutineScope, mainDispatcher = testDispatcher, uiEventLogger = uiEventLoggerFake, ) @@ -111,13 +123,13 @@ class CommunalSceneStartableTest(flags: FlagsParameterization) : SysuiTestCase() UserHandle.USER_CURRENT, ) fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true) + setCommunalV2ConfigEnabled(true) underTest.start() // Make communal available so that communalInteractor.desiredScene accurately reflects // scene changes instead of just returning Blank. runBlocking { setCommunalAvailable(true) } - setCommunalV2ConfigEnabled(true) } } @@ -414,6 +426,107 @@ class CommunalSceneStartableTest(flags: FlagsParameterization) : SysuiTestCase() assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1) } + @Test + @DisableFlags(FLAG_SCENE_CONTAINER) + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) + fun glanceableHubOrientationAware_idleOnCommunal() = + kosmos.runTest { + communalSceneInteractor.changeScene(CommunalScenes.Communal, "test") + + val scene by collectLastValue(communalSceneInteractor.currentScene) + assertThat(scene).isEqualTo(CommunalScenes.Communal) + + verify(notificationShadeWindowController).setGlanceableHubOrientationAware(true) + } + + @Test + @DisableFlags(FLAG_SCENE_CONTAINER) + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) + fun glanceableHubOrientationAware_transitioningToCommunal() = + kosmos.runTest { + val progress = MutableStateFlow(0f) + val targetScene = CommunalScenes.Communal + val currentScene = CommunalScenes.Blank + val transitionState = + MutableStateFlow( + ObservableTransitionState.Transition( + fromScene = currentScene, + toScene = targetScene, + currentScene = flowOf(targetScene), + progress = progress, + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + ) + ) + communalSceneInteractor.setTransitionState(transitionState) + + // Partially transition. + progress.value = .4f + + val scene by collectLastValue(communalSceneInteractor.currentScene) + assertThat(scene).isEqualTo(CommunalScenes.Blank) + + verify(notificationShadeWindowController).setGlanceableHubOrientationAware(true) + } + + @Test + @DisableFlags(FLAG_SCENE_CONTAINER) + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) + fun glanceableHubOrientationAware_communalToDreaming() = + kosmos.runTest { + communalSceneInteractor.changeScene(CommunalScenes.Communal, "test") + + verify(notificationShadeWindowController).setGlanceableHubOrientationAware(true) + Mockito.clearInvocations(notificationShadeWindowController) + + val progress = MutableStateFlow(0f) + val currentScene = CommunalScenes.Communal + val targetScene = CommunalScenes.Blank + val transitionState = + MutableStateFlow( + ObservableTransitionState.Transition( + fromScene = currentScene, + toScene = targetScene, + currentScene = flowOf(targetScene), + progress = progress, + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + ) + ) + communalSceneInteractor.setTransitionState(transitionState) + + // Partially transitioned out of Communal scene + progress.value = .4f + + // Started keyguard transitioning from hub -> dreaming. + fakeKeyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.GLANCEABLE_HUB, + to = KeyguardState.DREAMING, + transitionState = TransitionState.STARTED, + ) + ) + verify(notificationShadeWindowController).setGlanceableHubOrientationAware(true) + Mockito.clearInvocations(notificationShadeWindowController) + + fakeKeyguardTransitionRepository.sendTransitionStep( + from = KeyguardState.GLANCEABLE_HUB, + to = KeyguardState.DREAMING, + transitionState = TransitionState.RUNNING, + value = 0.5f, + ) + + // Transitioned to dreaming. + fakeKeyguardTransitionRepository.sendTransitionStep( + from = KeyguardState.GLANCEABLE_HUB, + to = KeyguardState.DREAMING, + transitionState = TransitionState.FINISHED, + value = 1f, + ) + // Not on hub anymore, let other states take control + verify(notificationShadeWindowController).setGlanceableHubOrientationAware(false) + } + /** * Advances time by duration + 1 millisecond, to ensure that tasks scheduled to run at * currentTime + duration are scheduled. diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt index 77d7091e463a..dc21f0692c9e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt @@ -134,7 +134,7 @@ class CommunalSceneInteractorTest(flags: FlagsParameterization) : SysuiTestCase( underTest.snapToScene( CommunalScenes.Communal, "test", - ActivityTransitionAnimator.TIMINGS.totalDuration + ActivityTransitionAnimator.TIMINGS.totalDuration, ) assertThat(currentScene).isEqualTo(CommunalScenes.Blank) advanceTimeBy(ActivityTransitionAnimator.TIMINGS.totalDuration) @@ -269,6 +269,48 @@ class CommunalSceneInteractorTest(flags: FlagsParameterization) : SysuiTestCase( @DisableFlags(FLAG_SCENE_CONTAINER) @Test + fun isTransitioningToOrIdleOnCommunal() = + testScope.runTest { + // isIdleOnCommunal is false when not on communal. + val isTransitioningToOrIdleOnCommunal by + collectLastValue(underTest.isTransitioningToOrIdleOnCommunal) + assertThat(isTransitioningToOrIdleOnCommunal).isEqualTo(false) + + val transitionState: MutableStateFlow<ObservableTransitionState> = + MutableStateFlow( + ObservableTransitionState.Transition( + fromScene = CommunalScenes.Blank, + toScene = CommunalScenes.Communal, + currentScene = flowOf(CommunalScenes.Communal), + progress = flowOf(0f), + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + ) + ) + + // Start transition to communal. + repository.setTransitionState(transitionState) + assertThat(isTransitioningToOrIdleOnCommunal).isEqualTo(true) + + // Finish transition to communal + transitionState.value = ObservableTransitionState.Idle(CommunalScenes.Communal) + assertThat(isTransitioningToOrIdleOnCommunal).isEqualTo(true) + + // Start transition away from communal. + transitionState.value = + ObservableTransitionState.Transition( + fromScene = CommunalScenes.Communal, + toScene = CommunalScenes.Blank, + currentScene = flowOf(CommunalScenes.Blank), + progress = flowOf(.1f), + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + ) + assertThat(isTransitioningToOrIdleOnCommunal).isEqualTo(false) + } + + @DisableFlags(FLAG_SCENE_CONTAINER) + @Test fun isCommunalVisible() = testScope.runTest { // isCommunalVisible is false when not on communal. diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelTest.kt deleted file mode 100644 index 2f3073e8eb23..000000000000 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelTest.kt +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2024 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.communal.ui.viewmodel - -import android.content.pm.UserInfo -import android.platform.test.annotations.EnableFlags -import android.provider.Settings -import android.service.dream.dreamManager -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.android.internal.logging.uiEventLoggerFake -import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 -import com.android.systemui.SysuiTestCase -import com.android.systemui.communal.data.repository.fakeCommunalPrefsRepository -import com.android.systemui.communal.domain.interactor.HubOnboardingInteractorTest.Companion.MAIN_USER -import com.android.systemui.communal.shared.log.CommunalUiEvent -import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED -import com.android.systemui.flags.fakeFeatureFlagsClassic -import com.android.systemui.kosmos.runCurrent -import com.android.systemui.kosmos.runTest -import com.android.systemui.kosmos.testScope -import com.android.systemui.lifecycle.activateIn -import com.android.systemui.plugins.activityStarter -import com.android.systemui.settings.fakeUserTracker -import com.android.systemui.statusbar.policy.batteryController -import com.android.systemui.statusbar.policy.fake -import com.android.systemui.testKosmos -import com.android.systemui.user.data.repository.fakeUserRepository -import com.android.systemui.util.settings.fakeSettings -import com.google.common.truth.Truth.assertThat -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers.anyInt -import org.mockito.Mockito.verify -import org.mockito.kotlin.any - -@SmallTest -@EnableFlags(FLAG_GLANCEABLE_HUB_V2) -@RunWith(AndroidJUnit4::class) -class CommunalToDreamButtonViewModelTest : SysuiTestCase() { - private val kosmos = testKosmos() - private val testScope = kosmos.testScope - private val underTest: CommunalToDreamButtonViewModel by lazy { - kosmos.communalToDreamButtonViewModel - } - - @Before - fun setUp() { - kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true) - underTest.activateIn(testScope) - } - - @Test - fun shouldShowDreamButtonOnHub_trueWhenPluggedIn() = - with(kosmos) { - runTest { - batteryController.fake._isPluggedIn = true - runCurrent() - - assertThat(underTest.shouldShowDreamButtonOnHub).isTrue() - } - } - - @Test - fun shouldShowDreamButtonOnHub_falseWhenNotPluggedIn() = - with(kosmos) { - runTest { - batteryController.fake._isPluggedIn = false - - assertThat(underTest.shouldShowDreamButtonOnHub).isFalse() - } - } - - @Test - fun onShowDreamButtonTap_dreamsEnabled_startsDream() = - with(kosmos) { - runTest { - val currentUser = fakeUserRepository.asMainUser() - kosmos.fakeSettings.putIntForUser( - Settings.Secure.SCREENSAVER_ENABLED, - 1, - currentUser.id, - ) - runCurrent() - - underTest.onShowDreamButtonTap() - runCurrent() - - verify(dreamManager).startDream() - } - } - - @Test - fun onShowDreamButtonTap_dreamsDisabled_startsActivity() = - with(kosmos) { - runTest { - val currentUser = fakeUserRepository.asMainUser() - kosmos.fakeSettings.putIntForUser( - Settings.Secure.SCREENSAVER_ENABLED, - 0, - currentUser.id, - ) - runCurrent() - - underTest.onShowDreamButtonTap() - runCurrent() - - verify(activityStarter).postStartActivityDismissingKeyguard(any(), anyInt()) - } - } - - @Test - fun shouldShowDreamButtonTooltip_trueWhenNotDismissedAndHubOnboardingDismissed() = - kosmos.runTest { - setSelectedUser(MAIN_USER) - fakeCommunalPrefsRepository.setHubOnboardingDismissed(MAIN_USER) - runCurrent() - - assertThat(underTest.shouldShowTooltip).isTrue() - } - - @Test - fun shouldShowDreamButtonTooltip_falseWhenNotDismissedAndHubOnboardingNotDismissed() = - kosmos.runTest { - runCurrent() - assertThat(underTest.shouldShowTooltip).isFalse() - } - - @Test - fun shouldShowDreamButtonTooltip_falseWhenDismissed() = - kosmos.runTest { - setSelectedUser(MAIN_USER) - fakeCommunalPrefsRepository.setDreamButtonTooltipDismissed(MAIN_USER) - runCurrent() - - assertThat(underTest.shouldShowTooltip).isFalse() - } - - @Test - fun onShowDreamButtonTap_eventLogged() = - with(kosmos) { - runTest { - underTest.onShowDreamButtonTap() - runCurrent() - - assertThat(uiEventLoggerFake[0].eventId) - .isEqualTo(CommunalUiEvent.COMMUNAL_HUB_SHOW_DREAM_BUTTON_TAP.id) - } - } - - private suspend fun setSelectedUser(user: UserInfo) { - with(kosmos.fakeUserRepository) { - setUserInfos(listOf(user)) - setSelectedUserInfo(user) - } - kosmos.fakeUserTracker.set(userInfos = listOf(user), selectedUserIndex = 0) - } -} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelTest.kt index 6b9e23abd9a4..135e9a55e8b5 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelTest.kt @@ -16,28 +16,46 @@ package com.android.systemui.keyguard.ui.viewmodel +import android.content.res.mainResources import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND +import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.domain.interactor.communalInteractor +import com.android.systemui.communal.domain.interactor.communalSceneInteractor +import com.android.systemui.communal.domain.interactor.setCommunalV2ConfigEnabled +import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.flags.DisableSceneContainer import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.keyguard.ui.transitions.blurConfig +import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.collectValues +import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.runTest +import com.android.systemui.statusbar.policy.keyguardStateController import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.whenever @SmallTest @RunWith(AndroidJUnit4::class) class GlanceableHubToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() { - private val kosmos = testKosmos() + private val kosmos = + testKosmos().apply { mainResources = mContext.orCreateTestableResources.resources } private val underTest by lazy { kosmos.glanceableHubToPrimaryBouncerTransitionViewModel } + @Before + fun setUp() { + with(kosmos) { setCommunalV2ConfigEnabled(true) } + } + @Test @DisableSceneContainer @DisableFlags(FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND) @@ -84,4 +102,81 @@ class GlanceableHubToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() { }, ) } + + @Test + @DisableSceneContainer + @DisableFlags(FLAG_GLANCEABLE_HUB_V2) + fun willDelayBouncerAppearAnimation_flagDisabled_isFalse() = + kosmos.runTest { + // keyguard rotation is not allowed on device. + whenever(keyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(false) + + val isIdleOnCommunal by collectLastValue(communalInteractor.isIdleOnCommunal) + communalSceneInteractor.changeScene(CommunalScenes.Communal, "test") + runCurrent() + // Device is idle on communal. + assertThat(isIdleOnCommunal).isTrue() + + // in landscape + assertThat(underTest.willDelayAppearAnimation(isLandscape = true)).isFalse() + // in portrait + assertThat(underTest.willDelayAppearAnimation(isLandscape = false)).isFalse() + } + + @Test + @DisableSceneContainer + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) + fun willDelayBouncerAppearAnimation_keyguardRotationAllowed_isFalse() = + kosmos.runTest { + // Keyguard rotation is allowed on device. + whenever(keyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(true) + + val isIdleOnCommunal by collectLastValue(communalInteractor.isIdleOnCommunal) + communalSceneInteractor.changeScene(CommunalScenes.Communal, "test") + runCurrent() + // Device is idle on communal. + assertThat(isIdleOnCommunal).isTrue() + + // in landscape + assertThat(underTest.willDelayAppearAnimation(isLandscape = true)).isFalse() + // in portrait + assertThat(underTest.willDelayAppearAnimation(isLandscape = false)).isFalse() + } + + @Test + @DisableSceneContainer + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) + fun willDelayBouncerAppearAnimation_isNotIdleOnCommunal_isFalse() = + kosmos.runTest { + whenever(keyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(false) + + val isIdleOnCommunal by collectLastValue(communalInteractor.isIdleOnCommunal) + communalSceneInteractor.changeScene(CommunalScenes.Blank, "test") + runCurrent() + // Device is not on communal. + assertThat(isIdleOnCommunal).isFalse() + + // in landscape + assertThat(underTest.willDelayAppearAnimation(isLandscape = true)).isFalse() + // in portrait + assertThat(underTest.willDelayAppearAnimation(isLandscape = false)).isFalse() + } + + @Test + @DisableSceneContainer + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) + fun willDelayBouncerAppearAnimation_isIdleOnCommunalAndKeyguardRotationIsNotAllowed() = + kosmos.runTest { + whenever(keyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(false) + val isIdleOnCommunal by collectLastValue(communalInteractor.isIdleOnCommunal) + communalSceneInteractor.changeScene(CommunalScenes.Communal, "test") + runCurrent() + // Device is idle on communal. + assertThat(isIdleOnCommunal).isTrue() + + // Will delay in landscape + assertThat(underTest.willDelayAppearAnimation(isLandscape = true)).isTrue() + // Won't delay in portrait + assertThat(underTest.willDelayAppearAnimation(isLandscape = false)).isFalse() + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java index 764068ec1bf5..3407cd50e76f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java @@ -84,12 +84,12 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; -import java.util.List; -import java.util.concurrent.Executor; - import platform.test.runner.parameterized.ParameterizedAndroidJunit4; import platform.test.runner.parameterized.Parameters; +import java.util.List; +import java.util.concurrent.Executor; + @RunWith(ParameterizedAndroidJunit4.class) @RunWithLooper(setAsMainLooper = true) @SmallTest @@ -410,6 +410,19 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { } @Test + public void hubOrientationAware_layoutParamsUpdated() { + mNotificationShadeWindowController.setKeyguardShowing(false); + mNotificationShadeWindowController.setBouncerShowing(false); + mNotificationShadeWindowController.setGlanceableHubOrientationAware(true); + when(mKeyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(false); + mNotificationShadeWindowController.onConfigChanged(new Configuration()); + + verify(mWindowManager, atLeastOnce()).updateViewLayout(any(), mLayoutParameters.capture()); + assertThat(mLayoutParameters.getValue().screenOrientation) + .isEqualTo(ActivityInfo.SCREEN_ORIENTATION_USER); + } + + @Test public void batchApplyWindowLayoutParams_doesNotDispatchEvents() { mNotificationShadeWindowController.setForceDozeBrightness(true); verify(mWindowManager).updateViewLayout(any(), any()); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt index f4a43a454a6f..ddad230f04e9 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt @@ -151,9 +151,17 @@ class ClockRegistryTest : SysuiTestCase() { create: (ClockId) -> ClockController = ::failFactory, getPickerConfig: (ClockSettings) -> ClockPickerConfig = ::failPickerConfig, ): FakeClockPlugin { - metadata.add(ClockMetadata(id)) - createCallbacks[id] = create - pickerConfigs[id] = getPickerConfig + return addClock(ClockMetadata(id), create, getPickerConfig) + } + + fun addClock( + metadata: ClockMetadata, + create: (ClockId) -> ClockController = ::failFactory, + getPickerConfig: (ClockSettings) -> ClockPickerConfig = ::failPickerConfig, + ): FakeClockPlugin { + this.metadata.add(metadata) + createCallbacks[metadata.clockId] = create + pickerConfigs[metadata.clockId] = getPickerConfig return this } } @@ -203,28 +211,40 @@ class ClockRegistryTest : SysuiTestCase() { val plugin1 = FakeClockPlugin().addClock("clock_1").addClock("clock_2") val lifecycle1 = FakeLifecycle("1", plugin1) - val plugin2 = FakeClockPlugin().addClock("clock_3").addClock("clock_4") + val plugin2 = + FakeClockPlugin() + .addClock(ClockMetadata("clock_3", isDeprecated = false)) + .addClock(ClockMetadata("clock_4", isDeprecated = true)) val lifecycle2 = FakeLifecycle("2", plugin2) pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1) pluginListener.onPluginLoaded(plugin2, mockContext, lifecycle2) - val list = registry.getClocks() assertEquals( - list.toSet(), setOf( ClockMetadata(DEFAULT_CLOCK_ID), ClockMetadata("clock_1"), ClockMetadata("clock_2"), ClockMetadata("clock_3"), - ClockMetadata("clock_4"), ), + registry.getClocks().toSet(), + ) + + assertEquals( + setOf( + ClockMetadata(DEFAULT_CLOCK_ID), + ClockMetadata("clock_1"), + ClockMetadata("clock_2"), + ClockMetadata("clock_3"), + ClockMetadata("clock_4", isDeprecated = true), + ), + registry.getClocks(includeDeprecated = true).toSet(), ) } @Test fun noPlugins_createDefaultClock() { val clock = registry.createCurrentClock() - assertEquals(clock, mockDefaultClock) + assertEquals(mockDefaultClock, clock) } @Test @@ -242,18 +262,18 @@ class ClockRegistryTest : SysuiTestCase() { pluginListener.onPluginLoaded(plugin2, mockContext, lifecycle2) val list = registry.getClocks() assertEquals( - list.toSet(), setOf( ClockMetadata(DEFAULT_CLOCK_ID), ClockMetadata("clock_1"), ClockMetadata("clock_2"), ), + list.toSet(), ) - assertEquals(registry.createExampleClock("clock_1"), mockClock) - assertEquals(registry.createExampleClock("clock_2"), mockClock) - assertEquals(registry.getClockPickerConfig("clock_1"), pickerConfig) - assertEquals(registry.getClockPickerConfig("clock_2"), pickerConfig) + assertEquals(mockClock, registry.createExampleClock("clock_1")) + assertEquals(mockClock, registry.createExampleClock("clock_2")) + assertEquals(pickerConfig, registry.getClockPickerConfig("clock_1")) + assertEquals(pickerConfig, registry.getClockPickerConfig("clock_2")) verify(lifecycle1, never()).unloadPlugin() verify(lifecycle2, times(2)).unloadPlugin() } @@ -305,7 +325,7 @@ class ClockRegistryTest : SysuiTestCase() { pluginListener.onPluginUnloaded(plugin2, lifecycle2) val clock = registry.createCurrentClock() - assertEquals(clock, mockDefaultClock) + assertEquals(mockDefaultClock, clock) } @Test @@ -482,13 +502,13 @@ class ClockRegistryTest : SysuiTestCase() { // Verify all plugins were correctly loaded into the registry assertEquals( - registry.getClocks().toSet(), setOf( ClockMetadata("DEFAULT"), ClockMetadata("clock_2"), ClockMetadata("clock_3"), ClockMetadata("clock_4"), ), + registry.getClocks().toSet(), ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/ConversationNotificationProcessorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/ConversationNotificationProcessorTest.kt index 67d0adedca6e..0caddf46cd3a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/ConversationNotificationProcessorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/ConversationNotificationProcessorTest.kt @@ -111,13 +111,13 @@ class ConversationNotificationProcessorTest : SysuiTestCase() { .isNotNull() val processedSummary = nb.build().extras.getCharSequence(EXTRA_SUMMARIZED_CONTENT) - assertThat(processedSummary.toString()).isEqualTo("x$summarization") + assertThat(processedSummary.toString()).isEqualTo("x $summarization") val checkSpans = SpannableStringBuilder(processedSummary) assertThat( checkSpans.getSpans( /* queryStart = */ 0, - /* queryEnd = */ 1, + /* queryEnd = */ 2, /* kind = */ ImageSpan::class.java, ) ) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimatorTest.kt index 56cd72e7725f..0bb473721446 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimatorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimatorTest.kt @@ -15,19 +15,22 @@ */ package com.android.systemui.statusbar.notification +import android.animation.AnimatorTestRule import android.util.FloatProperty import android.util.Property import android.view.View -import androidx.dynamicanimation.animation.DynamicAnimation + import androidx.test.annotation.UiThreadTest import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.internal.dynamicanimation.animation.DynamicAnimation import com.android.systemui.SysuiTestCase import com.android.systemui.res.R import com.android.systemui.statusbar.notification.stack.AnimationProperties import com.android.systemui.statusbar.notification.stack.ViewState import org.junit.Assert import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito @@ -50,6 +53,8 @@ class PhysicsPropertyAnimatorTest : SysuiTestCase() { return _value } } + @get:Rule + val animatorTestRule = AnimatorTestRule(this) private val property: PhysicsProperty = PhysicsProperty(R.id.scale_x_animator_tag, effectiveProperty) private var finishListener: DynamicAnimation.OnAnimationEndListener? = null diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt index 285326421a14..fa185bcabf83 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.collection.coordinator import android.app.Flags import android.app.NotificationChannel +import android.app.NotificationChannel.SYSTEM_RESERVED_IDS import android.app.NotificationManager.IMPORTANCE_DEFAULT import android.app.NotificationManager.IMPORTANCE_HIGH import android.app.NotificationManager.IMPORTANCE_LOW @@ -124,6 +125,14 @@ class ConversationCoordinatorTest : SysuiTestCase() { } @Test + fun testPrioritySectioner_doesNotClaim_classifiedConversation() { + val sectioner = coordinator.priorityPeopleSectioner + for (id in SYSTEM_RESERVED_IDS) { + assertFalse(sectioner.isInSection(makeClassifiedConversation(id))) + } + } + + @Test fun testPromotesImportantConversations() { assertTrue(promoter.shouldPromoteToTopLevel(makeEntryOfPeopleType(TYPE_IMPORTANT_PERSON))) assertFalse(promoter.shouldPromoteToTopLevel(makeEntryOfPeopleType(TYPE_FULL_PERSON))) @@ -166,6 +175,14 @@ class ConversationCoordinatorTest : SysuiTestCase() { } @Test + fun testAlertingSectioner_doesNotClaim_classifiedConversation() { + val sectioner = coordinator.peopleAlertingSectioner + for (id in SYSTEM_RESERVED_IDS) { + assertFalse(sectioner.isInSection(makeClassifiedConversation(id))) + } + } + + @Test fun testInAlertingPeopleSectionWhenTheImportanceIsAtLeastDefault() { // GIVEN val alertingEntry = makeEntryOfPeopleType(TYPE_PERSON) { setImportance(IMPORTANCE_DEFAULT) } @@ -186,6 +203,15 @@ class ConversationCoordinatorTest : SysuiTestCase() { @Test @DisableFlags(Flags.FLAG_SORT_SECTION_BY_TIME) + fun testSilentSectioner_doesNotClaim_classifiedConversation() { + val sectioner = coordinator.peopleSilentSectioner + for (id in SYSTEM_RESERVED_IDS) { + assertFalse(sectioner.isInSection(makeClassifiedConversation(id))) + } + } + + @Test + @DisableFlags(Flags.FLAG_SORT_SECTION_BY_TIME) fun testInSilentPeopleSectionWhenTheImportanceIsLowerThanDefault() { // GIVEN val silentEntry = makeEntryOfPeopleType(TYPE_PERSON) { setImportance(IMPORTANCE_LOW) } @@ -280,4 +306,17 @@ class ConversationCoordinatorTest : SysuiTestCase() { assertEquals(type, peopleNotificationIdentifier.getPeopleNotificationType(entry)) return entry } + + private fun makeClassifiedConversation(channelId: String): NotificationEntry { + val channel = NotificationChannel(channelId, channelId, IMPORTANCE_LOW) + val entry = + NotificationEntryBuilder() + .updateRanking { + it.setIsConversation(true) + it.setShortcutInfo(mock()) + it.setChannel(channel) + } + .build() + return entry + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinatorTest.kt index d5b2d3a68f1e..4e13dcd7576f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinatorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinatorTest.kt @@ -20,7 +20,6 @@ import android.app.Notification.MediaStyle import android.media.session.MediaSession import android.platform.test.flag.junit.FlagsParameterization import android.provider.Settings -import android.service.notification.StatusBarNotification import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.dump.dumpManager @@ -222,16 +221,19 @@ class OriginalUnseenKeyguardCoordinatorTest(flags: FlagsParameterization) : Sysu mock<ExpandableNotificationRow>().apply { whenever(isMediaRow).thenReturn(true) } - sbn = SbnBuilder().setNotification( - Notification.Builder(context, "channel").setStyle( - MediaStyle().setMediaSession( - MediaSession( - context, - "tag" - ).sessionToken + sbn = + SbnBuilder() + .setNotification( + Notification.Builder(context, "channel") + .setStyle( + MediaStyle() + .setMediaSession( + MediaSession(context, "tag").sessionToken + ) + ) + .build() ) - ).build() - ).build() + .build() } collectionListener.onEntryAdded(fakeEntry) @@ -631,6 +633,132 @@ class OriginalUnseenKeyguardCoordinatorTest(flags: FlagsParameterization) : Sysu } } + @Test + fun seenNotificationOnKeyguardMarkedAsSeenIfUpdatedBySystemServer() { + // GIVEN: Keyguard is showing, not dozing, unseen notification is present + keyguardRepository.setKeyguardShowing(true) + keyguardRepository.setIsDozing(false) + runKeyguardCoordinatorTest { + val fakeEntry = NotificationEntryBuilder().build() + collectionListener.onEntryAdded(fakeEntry) + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.AOD, + to = KeyguardState.LOCKSCREEN, + this.testScheduler, + ) + testScheduler.runCurrent() + + // WHEN: five seconds have passed + testScheduler.advanceTimeBy(5.seconds) + testScheduler.runCurrent() + + // WHEN: Keyguard is no longer showing + keyguardRepository.setKeyguardShowing(false) + kosmos.setTransition( + sceneTransition = Idle(Scenes.Gone), + stateTransition = TransitionStep(KeyguardState.LOCKSCREEN, KeyguardState.GONE), + ) + + // WHEN: the notification is updated by the Server + collectionListener.onEntryUpdated(fakeEntry, UpdateSource.SystemServer) + testScheduler.runCurrent() + + // WHEN: Keyguard is shown again + keyguardRepository.setKeyguardShowing(true) + kosmos.setTransition( + sceneTransition = Idle(Scenes.Lockscreen), + stateTransition = TransitionStep(KeyguardState.GONE, KeyguardState.AOD), + ) + + // THEN: The notification is still recognized as "seen" and is filtered out. + assertThat(unseenFilter.shouldFilterOut(fakeEntry, 0L)).isTrue() + } + } + + @Test + fun seenNotificationOnKeyguardMarkedAsSeenIfUpdatedBySystemUi() { + // GIVEN: Keyguard is showing, not dozing, unseen notification is present + keyguardRepository.setKeyguardShowing(true) + keyguardRepository.setIsDozing(false) + runKeyguardCoordinatorTest { + val fakeEntry = NotificationEntryBuilder().build() + collectionListener.onEntryAdded(fakeEntry) + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.AOD, + to = KeyguardState.LOCKSCREEN, + this.testScheduler, + ) + testScheduler.runCurrent() + + // WHEN: five seconds have passed + testScheduler.advanceTimeBy(5.seconds) + testScheduler.runCurrent() + + // WHEN: Keyguard is no longer showing + keyguardRepository.setKeyguardShowing(false) + kosmos.setTransition( + sceneTransition = Idle(Scenes.Gone), + stateTransition = TransitionStep(KeyguardState.LOCKSCREEN, KeyguardState.GONE), + ) + + // WHEN: the notification is updated by the SystemUi + collectionListener.onEntryUpdated(fakeEntry, UpdateSource.SystemUi) + testScheduler.runCurrent() + + // WHEN: Keyguard is shown again + keyguardRepository.setKeyguardShowing(true) + kosmos.setTransition( + sceneTransition = Idle(Scenes.Lockscreen), + stateTransition = TransitionStep(KeyguardState.GONE, KeyguardState.AOD), + ) + + // THEN: The notification is still recognized as "seen" and is filtered out. + assertThat(unseenFilter.shouldFilterOut(fakeEntry, 0L)).isTrue() + } + } + + @Test + fun seenNotificationOnKeyguardMarkedAsUnseenIfUpdatedByApp() { + // GIVEN: Keyguard is showing, not dozing, unseen notification is present + keyguardRepository.setKeyguardShowing(true) + keyguardRepository.setIsDozing(false) + runKeyguardCoordinatorTest { + val fakeEntry = NotificationEntryBuilder().build() + collectionListener.onEntryAdded(fakeEntry) + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.AOD, + to = KeyguardState.LOCKSCREEN, + this.testScheduler, + ) + testScheduler.runCurrent() + + // WHEN: five seconds have passed + testScheduler.advanceTimeBy(5.seconds) + testScheduler.runCurrent() + + // WHEN: Keyguard is no longer showing + keyguardRepository.setKeyguardShowing(false) + kosmos.setTransition( + sceneTransition = Idle(Scenes.Gone), + stateTransition = TransitionStep(KeyguardState.LOCKSCREEN, KeyguardState.GONE), + ) + + // WHEN: the notification is updated by the App + collectionListener.onEntryUpdated(fakeEntry, UpdateSource.App) + testScheduler.runCurrent() + + // WHEN: Keyguard is shown again + keyguardRepository.setKeyguardShowing(true) + kosmos.setTransition( + sceneTransition = Idle(Scenes.Lockscreen), + stateTransition = TransitionStep(KeyguardState.GONE, KeyguardState.AOD), + ) + + // THEN: The notification is now recognized as "unseen" and is not filtered out. + assertThat(unseenFilter.shouldFilterOut(fakeEntry, 0L)).isFalse() + } + } + private fun runKeyguardCoordinatorTest( testBlock: suspend KeyguardCoordinatorTestScope.() -> Unit ) { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt index 961616c99cb1..3d1fdee306f4 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt @@ -22,6 +22,8 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.accessibility.data.repository.FakeAccessibilityRepository import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.testKosmos +import com.android.systemui.window.domain.interactor.windowRootViewBlurInteractor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest @@ -32,12 +34,16 @@ import org.junit.runner.RunWith @SmallTest class ActivatableNotificationViewModelTest : SysuiTestCase() { + private val kosmos = testKosmos() + // fakes private val a11yRepo = FakeAccessibilityRepository() // real impls private val a11yInteractor = AccessibilityInteractor(a11yRepo) - private val underTest = ActivatableNotificationViewModel(a11yInteractor) + private val windowRootViewBlurInteractor = kosmos.windowRootViewBlurInteractor + private val underTest = ActivatableNotificationViewModel(a11yInteractor, + windowRootViewBlurInteractor) @Test fun isTouchable_whenA11yTouchExplorationDisabled() = runTest { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt index 4a761917b693..cb4642cc21be 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt @@ -18,9 +18,11 @@ package com.android.systemui.statusbar.notification.stack import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.SetFlagsRule import android.testing.TestableLooper.RunWithLooper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.animation.AnimatorTestRule import com.android.systemui.res.R @@ -44,6 +46,7 @@ import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.description import org.mockito.Mockito.eq import org.mockito.Mockito.verify +import org.mockito.kotlin.doNothing private const val VIEW_HEIGHT = 100 private const val FULL_SHADE_APPEAR_TRANSLATION = 300 @@ -53,18 +56,20 @@ private const val HEADS_UP_ABOVE_SCREEN = 80 @RunWith(AndroidJUnit4::class) @RunWithLooper class StackStateAnimatorTest : SysuiTestCase() { + + @get:Rule val setFlagsRule = SetFlagsRule() @get:Rule val animatorTestRule = AnimatorTestRule(this) private lateinit var stackStateAnimator: StackStateAnimator private lateinit var headsUpAnimator: HeadsUpAnimator private val stackScroller: NotificationStackScrollLayout = mock() private val view: ExpandableView = mock() - private val viewState: ExpandableViewState = - ExpandableViewState().apply { height = VIEW_HEIGHT } + private lateinit var viewState: ExpandableViewState private val runnableCaptor: ArgumentCaptor<Runnable> = argumentCaptor() @Before fun setUp() { + viewState = ExpandableViewState().apply { height = VIEW_HEIGHT } overrideResource( R.dimen.go_to_full_shade_appearing_translation, FULL_SHADE_APPEAR_TRANSLATION, @@ -153,6 +158,7 @@ class StackStateAnimatorTest : SysuiTestCase() { ) } + @DisableFlags(Flags.FLAG_PHYSICAL_NOTIFICATION_MOVEMENT) @Test @EnableFlags(NotificationsHunSharedAnimationValues.FLAG_NAME) fun startAnimationForEvents_headsUpFromBottom_startsHeadsUpAppearAnim_flagOn() { @@ -238,6 +244,32 @@ class StackStateAnimatorTest : SysuiTestCase() { .removeFromTransientContainer() } + @EnableFlags(Flags.FLAG_PHYSICAL_NOTIFICATION_MOVEMENT) + @Test + fun startAnimationForEvents_startsHeadsUpDisappearAnim_physical() { + val disappearDuration = ANIMATION_DURATION_HEADS_UP_DISAPPEAR.toLong() + val event = AnimationEvent(view, AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR) + clearInvocations(view) + stackStateAnimator.startAnimationForEvents(arrayListOf(event), 0) + + verify(view) + .performRemoveAnimation( + /* duration= */ eq(disappearDuration), + /* delay= */ eq(0L), + /* translationDirection= */ eq(0f), + /* isHeadsUpAnimation= */ eq(true), + /* isHeadsUpCycling= */ eq(false), + /* onStartedRunnable= */ any(), + /* onFinishedRunnable= */ runnableCaptor.capture(), + /* animationListener= */ any(), + /* clipSide= */ eq(ExpandableView.ClipSide.BOTTOM), + ) + + runnableCaptor.value.run() // execute the end runnable + verify(view, description("should be called at the end of the disappear animation")) + .removeFromTransientContainer() + } + @Test fun initView_updatesResources() { // Given: the resource values are initialized in the SSA diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt index ef415c918f91..6ee1c4ddf8e3 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.stack +import android.animation.AnimatorTestRule import android.animation.ValueAnimator import android.view.View import androidx.test.annotation.UiThreadTest @@ -28,6 +29,7 @@ import com.android.systemui.statusbar.notification.PhysicsPropertyAnimator import com.android.systemui.statusbar.notification.PhysicsPropertyAnimator.Companion.TAG_ANIMATOR_TRANSLATION_Y import com.android.systemui.statusbar.notification.PhysicsPropertyAnimator.Companion.Y_TRANSLATION import org.junit.Assert +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import kotlin.math.log2 @@ -38,6 +40,8 @@ import kotlin.math.sqrt @UiThreadTest class ViewStateTest : SysuiTestCase() { private val viewState = ViewState(true /* usePhysicsForMovement */) + @get:Rule + val animatorTestRule = AnimatorTestRule(this) @Suppress("DIVISION_BY_ZERO") @Test diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt index 7426f061b84c..0ef62a32a9c4 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt @@ -53,5 +53,21 @@ interface ClockProvider { /** Identifies a clock design */ typealias ClockId = String -/** Some data about a clock design */ -data class ClockMetadata(val clockId: ClockId) +/** Some metadata about a clock design */ +data class ClockMetadata( + /** Id for the clock design. */ + val clockId: ClockId, + + /** + * true if this clock is deprecated and should not be used. The ID may still show up in certain + * locations to help migrations, but it will not be selectable by new users. + */ + val isDeprecated: Boolean = false, + + /** + * Optional mapping of a legacy clock to a new id. This will map users that already are using + * `clockId` to the `replacementTarget` instead. The provider should still support the old id + * w/o crashing, but can consider it deprecated and the id reserved. + */ + val replacementTarget: ClockId? = null, +) diff --git a/packages/SystemUI/res/layout/volume_dialog_top_section.xml b/packages/SystemUI/res/layout/volume_dialog_top_section.xml index 4fc20e218c5e..29f52480bfe0 100644 --- a/packages/SystemUI/res/layout/volume_dialog_top_section.xml +++ b/packages/SystemUI/res/layout/volume_dialog_top_section.xml @@ -22,7 +22,6 @@ android:clipChildren="false" android:clipToPadding="false" android:gravity="center" - android:layoutDirection="ltr" android:paddingEnd="@dimen/volume_dialog_ringer_drawer_diff_end_margin" app:layoutDescription="@xml/volume_dialog_ringer_drawer_motion_scene"> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 6ff1240c5e60..43ea2c3f7633 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1024,6 +1024,12 @@ <string name="hearing_devices_ambient_control_left">Left</string> <!-- QuickSettings: The text to show the control is for right side device. [CHAR LIMIT=30] --> <string name="hearing_devices_ambient_control_right">Right</string> + <!-- QuickSettings: Content description for unified ambient control slider. [CHAR LIMIT=NONE] --> + <string name="hearing_devices_ambient_control_description">Surroundings</string> + <!-- QuickSettings: Content description for left ambient control slider. [CHAR LIMIT=NONE] --> + <string name="hearing_devices_ambient_control_left_description">Left surroundings</string> + <!-- QuickSettings: Content description for left ambient control slider. [CHAR LIMIT=NONE] --> + <string name="hearing_devices_ambient_control_right_description">Right surroundings</string> <!-- QuickSettings: Content description for a button, that expands ambient volume sliders [CHAR_LIMIT=NONE] --> <string name="hearing_devices_ambient_expand_controls">Expand to left and right separated controls</string> <!-- QuickSettings: Content description for a button, that collapses ambient volume sliders [CHAR LIMIT=NONE] --> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 5b96e5085fd2..4431ddadc8de 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -871,6 +871,7 @@ </style> <style name="MediaPlayer.SessionAction.Primary" parent="MediaPlayer.SessionAction"> + <item name="android:tint">@android:color/system_on_primary_dark</item> <item name="android:background">@drawable/qs_media_round_button_background</item> <item name="android:backgroundTint">@color/media_player_solid_button_bg</item> </style> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index 73dc28230e65..e2f3955263a1 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -172,6 +172,7 @@ public class KeyguardSecurityContainer extends ConstraintLayout { private boolean mIsDragging; private float mStartTouchY = -1; private boolean mDisappearAnimRunning; + private boolean mIsAppearAnimationDelayed; private SwipeListener mSwipeListener; private ViewMode mViewMode = new DefaultViewMode(); private boolean mIsInteractable; @@ -583,6 +584,10 @@ public class KeyguardSecurityContainer extends ConstraintLayout { return false; } + boolean isAppearAnimationDelayed() { + return mIsAppearAnimationDelayed; + } + void addMotionEventListener(Gefingerpoken listener) { mMotionEventListeners.add(listener); } @@ -624,6 +629,19 @@ public class KeyguardSecurityContainer extends ConstraintLayout { mViewMode.startAppearAnimation(securityMode); } + /** + * Set view translationY and alpha as we delay bouncer animation. + */ + public void setupForDelayedAppear() { + setTranslationY(0f); + setAlpha(0f); + setIsAppearAnimationDelayed(true); + } + + public void setIsAppearAnimationDelayed(boolean isDelayed) { + mIsAppearAnimationDelayed = isDelayed; + } + private void beginJankInstrument(int cuj) { KeyguardInputView securityView = mSecurityViewFlipper.getSecurityView(); if (securityView == null) return; @@ -812,6 +830,7 @@ public class KeyguardSecurityContainer extends ConstraintLayout { public void reset() { mViewMode.reset(); mDisappearAnimRunning = false; + mIsAppearAnimationDelayed = false; } /** diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index d10fce416150..198c1cb08647 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -18,6 +18,7 @@ package com.android.keyguard; import static android.app.StatusBarManager.SESSION_KEYGUARD; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; +import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISSIBLE_KEYGUARD; import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_BIOMETRIC; @@ -385,6 +386,10 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard boolean useSplitBouncer = orientation == ORIENTATION_LANDSCAPE; mSecurityViewFlipperController.updateConstraints(useSplitBouncer); } + if (orientation == ORIENTATION_PORTRAIT) { + // If there is any delayed bouncer appear animation it can start now + startAppearAnimationIfDelayed(); + } } @Override @@ -845,6 +850,16 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard } } + /** Start appear animation which was previously delayed from opening bouncer in landscape. */ + public void startAppearAnimationIfDelayed() { + if (!mView.isAppearAnimationDelayed()) { + return; + } + setAlpha(1f); + appear(); + mView.setIsAppearAnimationDelayed(false); + } + /** Called when the bouncer changes visibility. */ public void onBouncerVisibilityChanged(boolean isVisible) { if (!isVisible) { @@ -1301,4 +1316,13 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard setAlpha(MathUtils.constrain(1 - scaledFraction, 0f, 1f)); mView.setTranslationY(scaledFraction * mTranslationY); } + + /** Set up view for delayed appear animation. */ + public void setupForDelayedAppear() { + mView.setupForDelayedAppear(); + } + + public boolean isLandscapeOrientation() { + return mLastOrientation == Configuration.ORIENTATION_LANDSCAPE; + } } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeLayout.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeLayout.java index 5247acc94e03..33c9eb17cd44 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeLayout.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeLayout.java @@ -327,8 +327,19 @@ public class AmbientVolumeLayout extends LinearLayout implements AmbientVolumeUi slider.addOnChangeListener(mSliderOnChangeListener); if (side == SIDE_LEFT) { slider.setTitle(mContext.getString(R.string.hearing_devices_ambient_control_left)); + slider.setContentDescription( + mContext.getString(R.string.hearing_devices_ambient_control_left)); + slider.setSliderContentDescription( + mContext.getString(R.string.hearing_devices_ambient_control_left_description)); } else if (side == SIDE_RIGHT) { slider.setTitle(mContext.getString(R.string.hearing_devices_ambient_control_right)); + slider.setContentDescription( + mContext.getString(R.string.hearing_devices_ambient_control_right)); + slider.setSliderContentDescription( + mContext.getString(R.string.hearing_devices_ambient_control_right_description)); + } else { + slider.setSliderContentDescription( + mContext.getString(R.string.hearing_devices_ambient_control_description)); } mSideToSliderMap.put(side, slider); } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeSlider.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeSlider.java index 1a068c4229c9..5c0ad3dcf421 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeSlider.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeSlider.java @@ -92,6 +92,11 @@ public class AmbientVolumeSlider extends LinearLayout { mSlider = requireViewById(R.id.ambient_volume_slider); mSlider.addOnSliderTouchListener(mSliderTouchListener); mSlider.addOnChangeListener(mSliderChangeListener); + + setFocusable(false); + setClickable(false); + mSlider.setFocusable(false); + mSlider.setClickable(false); } /** @@ -178,6 +183,13 @@ public class AmbientVolumeSlider extends LinearLayout { return (int) Math.ceil((value - min) / levelGap); } + /** Sets the content description to the ambient volume slider. */ + public void setSliderContentDescription(CharSequence contentDescription) { + if (mSlider != null) { + mSlider.setContentDescription(contentDescription); + } + } + /** Interface definition for a callback invoked when a slider's value is changed. */ public interface OnChangeListener { /** Called when the finger is take off from the slider. */ diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt b/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt index d8e7a168ef3c..97de78c41af7 100644 --- a/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt @@ -18,6 +18,7 @@ package com.android.systemui.ambient.touch import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.animation.ValueAnimator +import android.content.res.Configuration import android.graphics.Rect import android.graphics.Region import android.util.Log @@ -36,6 +37,7 @@ import com.android.systemui.ambient.touch.dagger.BouncerSwipeModule import com.android.systemui.ambient.touch.scrim.ScrimController import com.android.systemui.ambient.touch.scrim.ScrimManager import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants +import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.communal.ui.viewmodel.CommunalViewModel import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.plugins.ActivityStarter @@ -46,6 +48,7 @@ import com.android.systemui.shade.ShadeExpansionChangeEvent import com.android.systemui.shade.data.repository.ShadeRepository import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.phone.CentralSurfaces +import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.wm.shell.animation.FlingAnimationUtils import java.util.Optional import javax.inject.Inject @@ -82,6 +85,8 @@ constructor( private val sceneInteractor: SceneInteractor, private val shadeRepository: ShadeRepository, private val windowRootViewProvider: Optional<Provider<WindowRootView>>, + private val keyguardStateController: KeyguardStateController, + communalSettingsInteractor: CommunalSettingsInteractor, ) : TouchHandler { /** An interface for creating ValueAnimators. */ interface ValueAnimatorCreator { @@ -101,6 +106,8 @@ constructor( private var capture: Boolean? = null private var expanded: Boolean = false private var touchSession: TouchSession? = null + private var isUserTrackingExpansionDisabled: Boolean = false + private var isKeyguardScreenRotationAllowed: Boolean = false private val scrimManagerCallback = ScrimManager.Callback { controller -> currentScrimController?.reset() @@ -121,6 +128,9 @@ constructor( distanceX: Float, distanceY: Float, ): Boolean { + val isLandscape = + windowRootView.resources.configuration.orientation == + Configuration.ORIENTATION_LANDSCAPE if (capture == null) { capture = if (Flags.dreamOverlayBouncerSwipeDirectionFiltering()) { @@ -137,7 +147,9 @@ constructor( // reset expanding expanded = false // Since the user is dragging the bouncer up, set scrimmed to false. - currentScrimController?.show() + if (isKeyguardScreenRotationAllowed || !isLandscape) { + currentScrimController?.show(false) + } if (SceneContainerFlag.isEnabled) { sceneInteractor.onRemoteUserInputStarted("bouncer touch handler") @@ -172,6 +184,37 @@ constructor( return true } + if (touchSession == null) { + return true + } + val screenTravelPercentage = + (abs((y - e2.y).toDouble()) / touchSession!!.bounds.height()).toFloat() + + if (communalSettingsInteractor.isV2FlagEnabled()) { + if (isUserTrackingExpansionDisabled) return true + // scrolling up in landscape orientation but device doesn't allow keyguard + // screen rotation + if (y > e2.y && !isKeyguardScreenRotationAllowed && isLandscape) { + velocityTracker!!.computeCurrentVelocity(1000) + currentExpansion = 1 - screenTravelPercentage + expanded = + shouldExpandBouncer( + velocityTracker!!.yVelocity, + velocityTracker!!.xVelocity, + EXPANSION_FROM_LANDSCAPE_THRESHOLD, + currentExpansion, + ) + if (expanded) { + // Once scroll past the percentage threshold, show bouncer scrimmed, + // so that user won't be required to drag up and then right to keep + // bouncer open after screen rotates to portrait. + currentScrimController?.show(true) + isUserTrackingExpansionDisabled = true + } + return true + } + } + if (SceneContainerFlag.isEnabled) { windowRootView.dispatchTouchEvent(e2) } else { @@ -182,12 +225,7 @@ constructor( // is fully hidden at full expansion (1) and fully visible when fully // collapsed // (0). - touchSession?.apply { - val screenTravelPercentage = - (abs((this@outer.y - e2.y).toDouble()) / getBounds().height()) - .toFloat() - setPanelExpansion(1 - screenTravelPercentage) - } + touchSession?.apply { setPanelExpansion(1 - screenTravelPercentage) } } } @@ -262,6 +300,7 @@ constructor( } scrimManager.addCallback(scrimManagerCallback) currentScrimController = scrimManager.currentController + isKeyguardScreenRotationAllowed = keyguardStateController.isKeyguardScreenRotationAllowed() shadeRepository.setLegacyShadeTracking(true) session.registerCallback { @@ -271,6 +310,7 @@ constructor( scrimManager.removeCallback(scrimManagerCallback) capture = null touchSession = null + isUserTrackingExpansionDisabled = false if (!Flags.communalBouncerDoNotModifyPluginOpen()) { notificationShadeWindowController.setForcePluginOpen(false, this) } @@ -299,14 +339,25 @@ constructor( return } + // We are already in progress of opening bouncer scrimmed + if (isUserTrackingExpansionDisabled) { + // User is done scrolling, reset + isUserTrackingExpansionDisabled = false + return + } + // We must capture the resulting velocities as resetMonitor() will clear these // values. velocityTracker!!.computeCurrentVelocity(1000) val verticalVelocity = velocityTracker!!.yVelocity - val horizontalVelocity = velocityTracker!!.xVelocity - val velocityVector = - hypot(horizontalVelocity.toDouble(), verticalVelocity.toDouble()).toFloat() - expanded = !flingRevealsOverlay(verticalVelocity, velocityVector) + expanded = + shouldExpandBouncer( + verticalVelocity, + velocityTracker!!.xVelocity, + FLING_PERCENTAGE_THRESHOLD, + currentExpansion, + ) + val expansion = if (expanded!!) KeyguardBouncerConstants.EXPANSION_VISIBLE else KeyguardBouncerConstants.EXPANSION_HIDDEN @@ -339,11 +390,27 @@ constructor( return animator } - protected fun flingRevealsOverlay(velocity: Float, velocityVector: Float): Boolean { + private fun shouldExpandBouncer( + verticalVelocity: Float, + horizontalVelocity: Float, + threshold: Float, + expansion: Float, + ): Boolean { + val velocityVector = + hypot(horizontalVelocity.toDouble(), verticalVelocity.toDouble()).toFloat() + return !flingRevealsOverlay(verticalVelocity, velocityVector, threshold, expansion) + } + + protected fun flingRevealsOverlay( + velocity: Float, + velocityVector: Float, + threshold: Float, + expansion: Float, + ): Boolean { // Fully expand the space above the bouncer, if the user has expanded the bouncer less // than halfway or final velocity was positive, indicating a downward direction. return if (abs(velocityVector.toDouble()) < flingAnimationUtils.minVelocityPxPerSecond) { - currentExpansion > FLING_PERCENTAGE_THRESHOLD + expansion > threshold } else { velocity > 0 } @@ -390,6 +457,7 @@ constructor( companion object { const val FLING_PERCENTAGE_THRESHOLD = 0.5f + const val EXPANSION_FROM_LANDSCAPE_THRESHOLD = 0.95f private const val TAG = "BouncerSwipeTouchHandler" } } diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/scrim/BouncerScrimController.java b/packages/SystemUI/src/com/android/systemui/ambient/touch/scrim/BouncerScrimController.java index 94c998267598..6f2dd799c409 100644 --- a/packages/SystemUI/src/com/android/systemui/ambient/touch/scrim/BouncerScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/scrim/BouncerScrimController.java @@ -33,8 +33,8 @@ public class BouncerScrimController implements ScrimController { } @Override - public void show() { - mStatusBarKeyguardViewManager.showPrimaryBouncer(false); + public void show(boolean scrimmed) { + mStatusBarKeyguardViewManager.showPrimaryBouncer(scrimmed); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/scrim/ScrimController.java b/packages/SystemUI/src/com/android/systemui/ambient/touch/scrim/ScrimController.java index 00543523ec2e..90cbd258f03e 100644 --- a/packages/SystemUI/src/com/android/systemui/ambient/touch/scrim/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/scrim/ScrimController.java @@ -25,8 +25,9 @@ import com.android.systemui.shade.ShadeExpansionChangeEvent; public interface ScrimController { /** * Called at the start of expansion before any expansion amount updates. + * @param scrimmed true when the bouncer should show scrimmed, false when user will be dragging. */ - default void show() { + default void show(boolean scrimmed) { } /** diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt index 7f268315e566..5d64219c7f90 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt @@ -15,6 +15,7 @@ import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToPrimaryBouncerTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel import com.android.systemui.log.BouncerLogger import com.android.systemui.user.domain.interactor.SelectedUserInteractor @@ -30,6 +31,8 @@ data class LegacyBouncerDependencies constructor( val viewModel: KeyguardBouncerViewModel, val primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel, + val glanceableHubToPrimaryBouncerTransitionViewModel: + GlanceableHubToPrimaryBouncerTransitionViewModel, val componentFactory: KeyguardBouncerComponent.Factory, val messageAreaControllerFactory: KeyguardMessageAreaController.Factory, val bouncerMessageInteractor: BouncerMessageInteractor, @@ -82,6 +85,7 @@ constructor( view, deps.viewModel, deps.primaryBouncerToGoneTransitionViewModel, + deps.glanceableHubToPrimaryBouncerTransitionViewModel, deps.componentFactory, deps.messageAreaControllerFactory, deps.bouncerMessageInteractor, diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt index 7d8945a5b4a7..45f0e13c185e 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt @@ -33,6 +33,7 @@ import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE import com.android.systemui.bouncer.ui.BouncerViewDelegate import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel +import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToPrimaryBouncerTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.log.BouncerLogger @@ -49,6 +50,8 @@ object KeyguardBouncerViewBinder { view: ViewGroup, viewModel: KeyguardBouncerViewModel, primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel, + glanceableHubToPrimaryBouncerTransitionViewModel: + GlanceableHubToPrimaryBouncerTransitionViewModel, componentFactory: KeyguardBouncerComponent.Factory, messageAreaControllerFactory: KeyguardMessageAreaController.Factory, bouncerMessageInteractor: BouncerMessageInteractor, @@ -133,7 +136,20 @@ object KeyguardBouncerViewBinder { /* turningOff= */ false ) securityContainerController.setInitialMessage() - securityContainerController.appear() + // Delay bouncer appearing animation when opening it from the + // glanceable hub in landscape, until after orientation changes + // to portrait. This prevents bouncer from showing in landscape + // layout, if bouncer rotation is not allowed. + if ( + glanceableHubToPrimaryBouncerTransitionViewModel + .willDelayAppearAnimation( + securityContainerController.isLandscapeOrientation + ) + ) { + securityContainerController.setupForDelayedAppear() + } else { + securityContainerController.appear() + } securityContainerController.onResume( KeyguardSecurityView.SCREEN_ON ) diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt index e36e85565293..49b0bb63545f 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt @@ -29,10 +29,17 @@ import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.communal.shared.model.CommunalScenes.isCommunal import com.android.systemui.communal.shared.model.CommunalTransitionKeys 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.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.Edge +import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING +import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB +import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.statusbar.NotificationShadeWindowController +import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf import com.android.systemui.util.kotlin.emitOnStart import com.android.systemui.util.kotlin.sample import com.android.systemui.util.settings.SettingsProxyExt.observerFlow @@ -45,6 +52,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.withContext @@ -60,10 +68,12 @@ constructor( private val communalInteractor: CommunalInteractor, private val communalSettingsInteractor: CommunalSettingsInteractor, private val communalSceneInteractor: CommunalSceneInteractor, + private val keyguardTransitionInteractor: KeyguardTransitionInteractor, private val keyguardInteractor: KeyguardInteractor, private val systemSettings: SystemSettings, private val notificationShadeWindowController: NotificationShadeWindowController, @Background private val bgScope: CoroutineScope, + @Application private val applicationScope: CoroutineScope, @Main private val mainDispatcher: CoroutineDispatcher, private val uiEventLogger: UiEventLogger, ) : CoreStartable { @@ -154,6 +164,25 @@ constructor( } } } + + if (communalSettingsInteractor.isV2FlagEnabled()) { + applicationScope.launch(context = mainDispatcher) { + anyOf( + communalSceneInteractor.isTransitioningToOrIdleOnCommunal, + // when transitioning from hub to dream, allow hub to stay at the current + // orientation, as keyguard doesn't allow rotation by default. + keyguardTransitionInteractor.isInTransition( + edge = Edge.create(from = Scenes.Communal, to = DREAMING), + edgeWithoutSceneContainer = + Edge.create(from = GLANCEABLE_HUB, to = DREAMING), + ), + ) + .distinctUntilChanged() + .collectLatest { + notificationShadeWindowController.setGlanceableHubOrientationAware(it) + } + } + } } private fun cancelHubTimeout() { diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt index 3d9e93036dbc..fed99d71fa3b 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt @@ -307,6 +307,21 @@ constructor( initialValue = false, ) + /** Flow that emits a boolean if transitioning to or idle on communal scene. */ + val isTransitioningToOrIdleOnCommunal: Flow<Boolean> = + transitionState + .map { + (it is ObservableTransitionState.Idle && + it.currentScene == CommunalScenes.Communal) || + (it is ObservableTransitionState.Transition && + it.toContent == CommunalScenes.Communal) + } + .stateIn( + scope = applicationScope, + started = SharingStarted.WhileSubscribed(), + initialValue = false, + ) + private companion object { const val TAG = "CommunalSceneInteractor" } diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModel.kt deleted file mode 100644 index b531d159acde..000000000000 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModel.kt +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2024 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.communal.ui.viewmodel - -import android.annotation.SuppressLint -import android.app.DreamManager -import android.content.Intent -import android.provider.Settings -import androidx.compose.runtime.getValue -import com.android.internal.logging.UiEventLogger -import com.android.systemui.communal.domain.interactor.CommunalPrefsInteractor -import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor -import com.android.systemui.communal.shared.log.CommunalUiEvent -import com.android.systemui.dagger.qualifiers.Background -import com.android.systemui.lifecycle.ExclusiveActivatable -import com.android.systemui.lifecycle.Hydrator -import com.android.systemui.plugins.ActivityStarter -import com.android.systemui.statusbar.policy.BatteryController -import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf -import com.android.systemui.util.kotlin.BooleanFlowOperators.not -import com.android.systemui.util.kotlin.isDevicePluggedIn -import com.android.systemui.util.kotlin.sample -import dagger.assisted.AssistedFactory -import dagger.assisted.AssistedInject -import kotlin.coroutines.CoroutineContext -import kotlinx.coroutines.awaitCancellation -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.receiveAsFlow -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext - -class CommunalToDreamButtonViewModel -@AssistedInject -constructor( - @Background private val backgroundContext: CoroutineContext, - batteryController: BatteryController, - private val prefsInteractor: CommunalPrefsInteractor, - private val settingsInteractor: CommunalSettingsInteractor, - private val activityStarter: ActivityStarter, - private val dreamManager: DreamManager, - private val uiEventLogger: UiEventLogger, -) : ExclusiveActivatable() { - - private val hydrator = Hydrator("CommunalToDreamButtonViewModel.hydrator") - private val _requests = Channel<Unit>(Channel.BUFFERED) - - /** Whether we should show a button on hub to switch to dream. */ - val shouldShowDreamButtonOnHub: Boolean by - hydrator.hydratedStateOf( - traceName = "shouldShowDreamButtonOnHub", - initialValue = false, - source = batteryController.isDevicePluggedIn().distinctUntilChanged(), - ) - - /** Return whether to show the dream button tooltip. */ - val shouldShowTooltip: Boolean by - hydrator.hydratedStateOf( - traceName = "shouldShowTooltip", - initialValue = false, - source = - allOf( - not(prefsInteractor.isDreamButtonTooltipDismissed), - prefsInteractor.isHubOnboardingDismissed, - ), - ) - - /** Set the dream button tooltip to be dismissed. */ - fun setDreamButtonTooltipDismissed() { - prefsInteractor.setDreamButtonTooltipDismissed() - } - - /** Handle a tap on the "show dream" button. */ - fun onShowDreamButtonTap() { - uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_SHOW_DREAM_BUTTON_TAP) - _requests.trySend(Unit) - } - - @SuppressLint("MissingPermission") - override suspend fun onActivated(): Nothing = coroutineScope { - launch { - _requests - .receiveAsFlow() - .sample(settingsInteractor.isScreensaverEnabled) - .collectLatest { enabled -> - withContext(backgroundContext) { - if (enabled) { - dreamManager.startDream() - } else { - activityStarter.postStartActivityDismissingKeyguard( - Intent(Settings.ACTION_DREAM_SETTINGS), - 0, - ) - } - } - } - } - - launch { hydrator.activate() } - - awaitCancellation() - } - - @AssistedFactory - interface Factory { - fun create(): CommunalToDreamButtonViewModel - } -} diff --git a/packages/SystemUI/src/com/android/systemui/grid/ui/compose/SpannedGrids.kt b/packages/SystemUI/src/com/android/systemui/grid/ui/compose/SpannedGrids.kt index 96ef03c996a9..e06c228e24b2 100644 --- a/packages/SystemUI/src/com/android/systemui/grid/ui/compose/SpannedGrids.kt +++ b/packages/SystemUI/src/com/android/systemui/grid/ui/compose/SpannedGrids.kt @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.android.systemui.grid.ui.compose +import androidx.collection.IntIntPair import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope @@ -24,7 +24,6 @@ import androidx.compose.runtime.key import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.layout.Layout -import androidx.compose.ui.layout.Placeable import androidx.compose.ui.semantics.CollectionInfo import androidx.compose.ui.semantics.CollectionItemInfo import androidx.compose.ui.semantics.collectionInfo @@ -34,6 +33,8 @@ import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp +import androidx.compose.ui.util.fastForEachIndexed +import androidx.compose.ui.util.fastMapIndexed import kotlin.math.max /** @@ -65,7 +66,11 @@ fun HorizontalSpannedGrid( spans: List<Int>, modifier: Modifier = Modifier, keys: (spanIndex: Int) -> Any = { it }, - composables: @Composable BoxScope.(spanIndex: Int) -> Unit, + composables: + @Composable + BoxScope.( + spanIndex: Int, row: Int, isFirstInColumn: Boolean, isLastInColumn: Boolean, + ) -> Unit, ) { SpannedGrid( primarySpaces = rows, @@ -80,7 +85,7 @@ fun HorizontalSpannedGrid( } /** - * Horizontal (non lazy) grid that supports [spans] for its elements. + * Vertical (non lazy) grid that supports [spans] for its elements. * * The elements will be laid down horizontally first, and then by rows. So assuming LTR layout, it * will be (for a span list `[2, 1, 2, 1, 1, 1, 1, 1]` and 4 columns): @@ -107,7 +112,9 @@ fun VerticalSpannedGrid( spans: List<Int>, modifier: Modifier = Modifier, keys: (spanIndex: Int) -> Any = { it }, - composables: @Composable BoxScope.(spanIndex: Int) -> Unit, + composables: + @Composable + BoxScope.(spanIndex: Int, column: Int, isFirstInRow: Boolean, isLastInRow: Boolean) -> Unit, ) { SpannedGrid( primarySpaces = columns, @@ -130,7 +137,9 @@ private fun SpannedGrid( isVertical: Boolean, modifier: Modifier = Modifier, keys: (spanIndex: Int) -> Any = { it }, - composables: @Composable BoxScope.(spanIndex: Int) -> Unit, + composables: + @Composable + BoxScope.(spanIndex: Int, secondaryAxis: Int, isFirst: Boolean, isLast: Boolean) -> Unit, ) { val crossAxisArrangement = Arrangement.spacedBy(crossAxisSpacing) spans.forEachIndexed { index, span -> @@ -139,7 +148,6 @@ private fun SpannedGrid( "expected rance of [1, $primarySpaces]" } } - if (isVertical) { check(crossAxisSpacing >= 0.dp) { "Negative columnSpacing $crossAxisSpacing" } check(mainAxisSpacing >= 0.dp) { "Negative rowSpacing $mainAxisSpacing" } @@ -147,29 +155,30 @@ private fun SpannedGrid( check(mainAxisSpacing >= 0.dp) { "Negative columnSpacing $mainAxisSpacing" } check(crossAxisSpacing >= 0.dp) { "Negative rowSpacing $crossAxisSpacing" } } - - val totalMainAxisGroups: Int = + // List of primary axis index to secondary axis index + // This is keyed to the size of the spans list for performance reasons as we don't expect the + // spans value to change outside of edit mode. + val positions = remember(spans.size) { Array(spans.size) { IntIntPair(0, 0) } } + val totalMainAxisGroups = remember(primarySpaces, spans) { - var currentAccumulated = 0 - var groups = 1 - spans.forEach { span -> - if (currentAccumulated + span <= primarySpaces) { - currentAccumulated += span - } else { - groups += 1 - currentAccumulated = span + var mainAxisGroup = 0 + var currentSlot = 0 + spans.fastForEachIndexed { index, span -> + if (currentSlot + span > primarySpaces) { + currentSlot = 0 + mainAxisGroup += 1 } + positions[index] = IntIntPair(mainAxisGroup, currentSlot) + currentSlot += span } - groups + mainAxisGroup + 1 } - val slotPositionsAndSizesCache = remember { object { var sizes = IntArray(0) var positions = IntArray(0) } } - Layout( { (0 until spans.size).map { spanIndex -> @@ -184,7 +193,13 @@ private fun SpannedGrid( } } ) { - composables(spanIndex) + val position = positions[spanIndex] + composables( + spanIndex, + position.second, + position.second == 0, + positions.getOrNull(spanIndex + 1)?.first != position.first, + ) } } } @@ -205,7 +220,6 @@ private fun SpannedGrid( slotPositionsAndSizesCache.sizes, ) val cellSizesInCrossAxis = slotPositionsAndSizesCache.sizes - // with is needed because of the double receiver (Density, Arrangement). with(crossAxisArrangement) { arrange( @@ -216,68 +230,73 @@ private fun SpannedGrid( ) } val startPositions = slotPositionsAndSizesCache.positions - val mainAxisSpacingPx = mainAxisSpacing.roundToPx() val mainAxisTotalGaps = (totalMainAxisGroups - 1) * mainAxisSpacingPx - val mainAxisSize = if (isVertical) constraints.maxHeight else constraints.maxWidth + val mainAxisMaxSize = if (isVertical) constraints.maxHeight else constraints.maxWidth val mainAxisElementConstraint = - if (mainAxisSize == Constraints.Infinity) { + if (mainAxisMaxSize == Constraints.Infinity) { Constraints.Infinity } else { - max(0, (mainAxisSize - mainAxisTotalGaps) / totalMainAxisGroups) + max(0, (mainAxisMaxSize - mainAxisTotalGaps) / totalMainAxisGroups) } - val mainAxisSizes = IntArray(totalMainAxisGroups) { 0 } - - var currentSlot = 0 - var mainAxisGroup = 0 + var mainAxisTotalSize = mainAxisTotalGaps + var currentMainAxis = 0 + var currentMainAxisMax = 0 val placeables = - measurables.mapIndexed { index, measurable -> + measurables.fastMapIndexed { index, measurable -> val span = spans[index] - if (currentSlot + span > primarySpaces) { - currentSlot = 0 - mainAxisGroup += 1 - } + val position = positions[index] val crossAxisConstraint = - calculateWidth(cellSizesInCrossAxis, startPositions, currentSlot, span) - PlaceResult( - measurable.measure( - makeConstraint( - isVertical, - mainAxisElementConstraint, - crossAxisConstraint, - ) - ), - currentSlot, - mainAxisGroup, + calculateWidth(cellSizesInCrossAxis, startPositions, position.second, span) + + measurable + .measure( + makeConstraint(isVertical, mainAxisElementConstraint, crossAxisConstraint) ) .also { - currentSlot += span - mainAxisSizes[mainAxisGroup] = - max( - mainAxisSizes[mainAxisGroup], - if (isVertical) it.placeable.height else it.placeable.width, - ) + val placeableSize = if (isVertical) it.height else it.width + if (position.first != currentMainAxis) { + // New row -- Add the max size to the total and reset the max + mainAxisTotalSize += currentMainAxisMax + currentMainAxisMax = placeableSize + currentMainAxis = position.first + } else { + currentMainAxisMax = max(currentMainAxisMax, placeableSize) + } } } + mainAxisTotalSize += currentMainAxisMax - val mainAxisTotalSize = mainAxisTotalGaps + mainAxisSizes.sum() - val mainAxisStartingPoints = - mainAxisSizes.runningFold(0) { acc, value -> acc + value + mainAxisSpacingPx } val height = if (isVertical) mainAxisTotalSize else crossAxisSize val width = if (isVertical) crossAxisSize else mainAxisTotalSize layout(width, height) { - placeables.forEach { (placeable, slot, mainAxisGroup) -> + var previousMainAxis = 0 + var currentMainAxisPosition = 0 + var currentMainAxisMax = 0 + placeables.forEachIndexed { index, placeable -> + val slot = positions[index].second + val mainAxisSize = if (isVertical) placeable.height else placeable.width + + if (positions[index].first != previousMainAxis) { + // Move up a row + padding + currentMainAxisPosition += currentMainAxisMax + mainAxisSpacingPx + currentMainAxisMax = mainAxisSize + previousMainAxis = positions[index].first + } else { + currentMainAxisMax = max(currentMainAxisMax, mainAxisSize) + } + val x = if (isVertical) { startPositions[slot] } else { - mainAxisStartingPoints[mainAxisGroup] + currentMainAxisPosition } val y = if (isVertical) { - mainAxisStartingPoints[mainAxisGroup] + currentMainAxisPosition } else { startPositions[slot] } @@ -321,9 +340,3 @@ private fun calculateCellsCrossAxisSize( outArray[index] = slotSize + if (index < remainingPixels) 1 else 0 } } - -private data class PlaceResult( - val placeable: Placeable, - val slotIndex: Int, - val mainAxisGroup: Int, -) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModel.kt index 40010548a268..c088900f9304 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModel.kt @@ -17,33 +17,39 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.Flags +import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.communal.shared.model.CommunalBackgroundType import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor +import com.android.systemui.keyguard.domain.interactor.FromGlanceableHubTransitionInteractor import com.android.systemui.keyguard.shared.model.Edge import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.BlurConfig import com.android.systemui.keyguard.ui.transitions.PrimaryBouncerTransition +import com.android.systemui.statusbar.policy.KeyguardStateController import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flatMapLatest +@OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton class GlanceableHubToPrimaryBouncerTransitionViewModel @Inject constructor( private val blurConfig: BlurConfig, animationFlow: KeyguardTransitionAnimationFlow, - communalSettingsInteractor: CommunalSettingsInteractor, + private val communalSettingsInteractor: CommunalSettingsInteractor, + private val communalSceneInteractor: CommunalSceneInteractor, + private val keyguardStateController: KeyguardStateController, ) : PrimaryBouncerTransition { private val transitionAnimation = animationFlow .setup( - duration = FromLockscreenTransitionInteractor.TO_PRIMARY_BOUNCER_DURATION, + duration = FromGlanceableHubTransitionInteractor.TO_BOUNCER_DURATION, edge = Edge.INVALID, ) .setupWithoutSceneContainer(edge = Edge.create(GLANCEABLE_HUB, PRIMARY_BOUNCER)) @@ -59,6 +65,13 @@ constructor( transitionAnimation.immediatelyTransitionTo(blurConfig.maxBlurRadiusPx) } + /** Whether to delay the animation to fade in bouncer elements. */ + fun willDelayAppearAnimation(isLandscape: Boolean): Boolean = + communalSettingsInteractor.isV2FlagEnabled() && + communalSceneInteractor.isIdleOnCommunal.value && + !keyguardStateController.isKeyguardScreenRotationAllowed() && + isLandscape + override val notificationBlurRadius: Flow<Float> = transitionAnimation.immediatelyTransitionTo(0.0f) } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerLogger.kt index 9b443f56636a..5d62c022efba 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerLogger.kt @@ -90,15 +90,16 @@ constructor(@MediaCarouselControllerLog private val buffer: LogBuffer) { fun logCarouselVisible() = buffer.log(TAG, LogLevel.DEBUG, {}, { "showing carousel" }) - fun logMediaHostVisibility(location: Int, visible: Boolean) { + fun logMediaHostVisibility(location: Int, visible: Boolean, oldState: Boolean) { buffer.log( TAG, LogLevel.DEBUG, { int1 = location bool1 = visible + bool2 = oldState }, - { "media host visibility changed location=$location, visible:$visible" }, + { "media host visibility changed location=$location, visible:$visible, was:$oldState" }, ) } } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt index c6894082f1c8..69006c6107cc 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt @@ -1129,10 +1129,11 @@ constructor( traceSection("MediaHierarchyManager#updateHostAttachment") { if (SceneContainerFlag.isEnabled) { // No need to manage transition states - just update the desired location directly - logger.logMediaHostAttachment(desiredLocation) + val host = getHost(desiredLocation) + logger.logMediaHostAttachment(desiredLocation, host?.visible) mediaCarouselController.onDesiredLocationChanged( desiredLocation = desiredLocation, - desiredHostState = getHost(desiredLocation), + desiredHostState = host, animate = false, ) return @@ -1169,7 +1170,8 @@ constructor( // that and directly set the mediaFrame's bounds within the premeasured host. targetHost.addView(mediaFrame) } - logger.logMediaHostAttachment(currentAttachmentLocation) + val host = getHost(currentAttachmentLocation) + logger.logMediaHostAttachment(currentAttachmentLocation, host?.visible) if (isCrossFadeAnimatorRunning) { // When cross-fading with an animation, we only notify the media carousel of the // location change, once the view is reattached to the new place and not @@ -1313,6 +1315,7 @@ constructor( isHomeScreenShadeVisibleToUser() || isGlanceableHubVisibleToUser() val mediaVisible = qsExpanded || hasActiveMediaOrRecommendation + logger.logUserVisibilityChange(shadeVisible, mediaVisible) mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = shadeVisible && mediaVisible } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewLogger.kt index 1514db38d882..089d16b98de8 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewLogger.kt @@ -36,7 +36,7 @@ class MediaViewLogger @Inject constructor(@MediaViewLog private val buffer: LogB int1 = width int2 = height }, - { "size ($str1): $int1 x $int2" } + { "size ($str1): $int1 x $int2" }, ) } @@ -49,11 +49,31 @@ class MediaViewLogger @Inject constructor(@MediaViewLog private val buffer: LogB int1 = startLocation int2 = endLocation }, - { "location ($str1): $int1 -> $int2" } + { "location ($str1): $int1 -> $int2" }, ) } - fun logMediaHostAttachment(host: Int) { - buffer.log(TAG, LogLevel.DEBUG, { int1 = host }, { "Host (updateHostAttachment): $int1" }) + fun logMediaHostAttachment(host: Int, visible: Boolean?) { + buffer.log( + TAG, + LogLevel.DEBUG, + { + int1 = host + str1 = visible.toString() + }, + { "Host (updateHostAttachment): $int1 visible $str1" }, + ) + } + + fun logUserVisibilityChange(shadeVisible: Boolean, mediaVisible: Boolean) { + buffer.log( + TAG, + LogLevel.DEBUG, + { + bool1 = shadeVisible + bool2 = mediaVisible + }, + { "User visibility shade: $shadeVisible media: $mediaVisible" }, + ) } } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaHost.kt index 11251cdb6315..a518349ea424 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaHost.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaHost.kt @@ -208,6 +208,7 @@ class MediaHost( * the visibility has changed */ fun updateViewVisibility() { + val oldState = state.visible state.visible = if (mediaCarouselController.isLockedAndHidden()) { false @@ -217,9 +218,9 @@ class MediaHost( mediaDataManager.hasAnyMediaOrRecommendation() } val newVisibility = if (visible) View.VISIBLE else View.GONE - if (newVisibility != hostView.visibility) { + if (oldState != state.visible || newVisibility != hostView.visibility) { hostView.visibility = newVisibility - debugLogger.logMediaHostVisibility(location, visible) + debugLogger.logMediaHostVisibility(location, visible, oldState) visibleChangedListeners.forEach { it.invoke(visible) } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt index eb6f97942ec0..b80e6b403cf3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt @@ -35,11 +35,16 @@ fun List<BounceableTileViewModel>.bounceableInfo( index: Int, column: Int, columns: Int, + isFirstInRow: Boolean, + isLastInRow: Boolean, ): BounceableInfo { - // Only look for neighbor bounceables if they are on the same row + // A tile may be the last in the row without being on the last column val onLastColumn = sizedTile.onLastColumn(column, columns) - val previousTile = getOrNull(index - 1)?.takeIf { column != 0 } - val nextTile = getOrNull(index + 1)?.takeIf { !onLastColumn } + + // Only look for neighbor bounceables if they are on the same row + val previousTile = getOrNull(index - 1)?.takeIf { !isFirstInRow } + val nextTile = getOrNull(index + 1)?.takeIf { !isLastInRow } + return BounceableInfo(this[index], previousTile, nextTile, !onLastColumn) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt index 495870f0a978..cdc03bb9be35 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt @@ -57,7 +57,6 @@ fun ContentScope.QuickQuickSettings( onDispose { tiles.forEach { it.stopListening(token) } } } val columns = viewModel.columns - var cellIndex = 0 Box(modifier = modifier) { GridAnchor() VerticalSpannedGrid( @@ -67,17 +66,23 @@ fun ContentScope.QuickQuickSettings( spans = spans, modifier = Modifier.sysuiResTag("qqs_tile_layout"), keys = { sizedTiles[it].tile.spec }, - ) { spanIndex -> + ) { spanIndex, column, isFirstInColumn, isLastInColumn -> val it = sizedTiles[spanIndex] - val column = cellIndex % columns - cellIndex += it.width Element(it.tile.spec.toElementKey(spanIndex), Modifier) { Tile( tile = it.tile, iconOnly = it.isIcon, squishiness = { squishiness }, coroutineScope = scope, - bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns), + bounceableInfo = + bounceables.bounceableInfo( + it, + index = spanIndex, + column = column, + columns = columns, + isFirstInRow = isFirstInColumn, + isLastInRow = isLastInColumn, + ), tileHapticsViewModelFactoryProvider = viewModel.tileHapticsViewModelFactoryProvider, // There should be no QuickQuickSettings when the details view is enabled. diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt index dfee497655d1..0503049382a8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt @@ -85,8 +85,6 @@ constructor( remember(sizedTiles) { List(sizedTiles.size) { BounceableTileViewModel() } } val squishiness by viewModel.squishinessViewModel.squishiness.collectAsStateWithLifecycle() val scope = rememberCoroutineScope() - var cellIndex = 0 - val spans by remember(sizedTiles) { derivedStateOf { sizedTiles.fastMap { it.width } } } VerticalSpannedGrid( @@ -95,10 +93,9 @@ constructor( rowSpacing = dimensionResource(R.dimen.qs_tile_margin_vertical), spans = spans, keys = { sizedTiles[it].tile.spec }, - ) { spanIndex -> + ) { spanIndex, column, isFirstInColumn, isLastInColumn -> val it = sizedTiles[spanIndex] - val column = cellIndex % columns - cellIndex += it.width + Element(it.tile.spec.toElementKey(spanIndex), Modifier) { Tile( tile = it.tile, @@ -106,7 +103,15 @@ constructor( squishiness = { squishiness }, tileHapticsViewModelFactoryProvider = tileHapticsViewModelFactoryProvider, coroutineScope = scope, - bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns), + bounceableInfo = + bounceables.bounceableInfo( + it, + index = spanIndex, + column = column, + columns = columns, + isFirstInRow = isFirstInColumn, + isLastInRow = isLastInColumn, + ), detailsViewModel = detailsViewModel, ) } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java index e4cd7ea098af..305444f7ab5e 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java @@ -451,6 +451,8 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW } else { mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; } + } else if (state.glanceableHubOrientationAware) { + mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER; } else { mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; } @@ -627,6 +629,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW state.shadeOrQsExpanded, state.notificationShadeFocusable, state.glanceableHubShowing, + state.glanceableHubOrientationAware, state.bouncerShowing, state.keyguardFadingAway, state.keyguardGoingAway, @@ -763,6 +766,12 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW } @Override + public void setGlanceableHubOrientationAware(boolean isOrientationAware) { + mCurrentState.glanceableHubOrientationAware = isOrientationAware; + apply(mCurrentState); + } + + @Override public void setBackdropShowing(boolean showing) { mCurrentState.mediaBackdropShowing = showing; apply(mCurrentState); diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt index 6a4b52af498c..a1eac745b3a1 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt @@ -36,6 +36,7 @@ class NotificationShadeWindowState( @JvmField var notificationShadeFocusable: Boolean = false, @JvmField var bouncerShowing: Boolean = false, @JvmField var glanceableHubShowing: Boolean = false, + @JvmField var glanceableHubOrientationAware: Boolean = false, @JvmField var keyguardFadingAway: Boolean = false, @JvmField var keyguardGoingAway: Boolean = false, @JvmField var qsExpanded: Boolean = false, @@ -81,6 +82,7 @@ class NotificationShadeWindowState( notificationShadeFocusable.toString(), bouncerShowing.toString(), glanceableHubShowing.toString(), + glanceableHubOrientationAware.toString(), keyguardFadingAway.toString(), keyguardGoingAway.toString(), qsExpanded.toString(), @@ -122,6 +124,7 @@ class NotificationShadeWindowState( panelExpanded: Boolean, notificationShadeFocusable: Boolean, glanceableHubShowing: Boolean, + glanceableHubOrientationAware: Boolean, bouncerShowing: Boolean, keyguardFadingAway: Boolean, keyguardGoingAway: Boolean, @@ -153,6 +156,7 @@ class NotificationShadeWindowState( this.shadeOrQsExpanded = panelExpanded this.notificationShadeFocusable = notificationShadeFocusable this.glanceableHubShowing = glanceableHubShowing + this.glanceableHubOrientationAware = glanceableHubOrientationAware this.bouncerShowing = bouncerShowing this.keyguardFadingAway = keyguardFadingAway this.keyguardGoingAway = keyguardGoingAway @@ -202,6 +206,7 @@ class NotificationShadeWindowState( "panelExpanded", "notificationShadeFocusable", "glanceableHubShowing", + "glanceableHubOrientationAware", "bouncerShowing", "keyguardFadingAway", "keyguardGoingAway", @@ -223,7 +228,7 @@ class NotificationShadeWindowState( "dozing", "scrimsVisibility", "backgroundBlurRadius", - "communalVisible" + "communalVisible", ) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java index 4bb12e59a877..6ebe02469f5c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java @@ -57,6 +57,12 @@ public class NotificationGroupingUtil { private static final VisibilityApplicator VISIBILITY_APPLICATOR = new VisibilityApplicator(); private static final VisibilityApplicator APP_NAME_APPLICATOR = new AppNameApplicator(); private static final ResultApplicator LEFT_ICON_APPLICATOR = new LeftIconApplicator(); + private static final DataExtractor ICON_EXTRACTOR = new DataExtractor() { + @Override + public Object extractData(ExpandableNotificationRow row) { + return row.getEntry().getSbn().getNotification(); + } + }; private final ExpandableNotificationRow mRow; private final ArrayList<Processor> mProcessors = new ArrayList<>(); @@ -103,26 +109,31 @@ public class NotificationGroupingUtil { // To hide the icons if they are the same and the color is the same mProcessors.add(new Processor(mRow, com.android.internal.R.id.icon, + ICON_EXTRACTOR, iconVisibilityComparator, VISIBILITY_APPLICATOR)); // To grey out the icons when they are not the same, or they have the same color mProcessors.add(new Processor(mRow, com.android.internal.R.id.status_bar_latest_event_content, + ICON_EXTRACTOR, greyComparator, greyApplicator)); // To show the large icon on the left side instead if all the small icons are the same mProcessors.add(new Processor(mRow, com.android.internal.R.id.status_bar_latest_event_content, + ICON_EXTRACTOR, iconVisibilityComparator, LEFT_ICON_APPLICATOR)); // To only show the work profile icon in the group header mProcessors.add(new Processor(mRow, com.android.internal.R.id.profile_badge, + null /* Extractor */, BADGE_COMPARATOR, VISIBILITY_APPLICATOR)); // To hide the app name in group children mProcessors.add(new Processor(mRow, com.android.internal.R.id.app_name_text, + null, APP_NAME_COMPARATOR, APP_NAME_APPLICATOR)); // To hide the header text if it's the same @@ -242,20 +253,23 @@ public class NotificationGroupingUtil { private static class Processor { private final int mId; + private final DataExtractor mExtractor; private final ViewComparator mComparator; private final ResultApplicator mApplicator; private final ExpandableNotificationRow mParentRow; private boolean mApply; private View mParentView; + private Object mParentData; public static Processor forTextView(ExpandableNotificationRow row, int id) { - return new Processor(row, id, TEXT_VIEW_COMPARATOR, VISIBILITY_APPLICATOR); + return new Processor(row, id, null, TEXT_VIEW_COMPARATOR, VISIBILITY_APPLICATOR); } - Processor(ExpandableNotificationRow row, int id, + Processor(ExpandableNotificationRow row, int id, DataExtractor extractor, ViewComparator comparator, ResultApplicator applicator) { mId = id; + mExtractor = extractor; mApplicator = applicator; mComparator = comparator; mParentRow = row; @@ -265,6 +279,7 @@ public class NotificationGroupingUtil { NotificationViewWrapper wrapper = mParentRow.getNotificationViewWrapper(); View header = wrapper == null ? null : wrapper.getNotificationHeader(); mParentView = header == null ? null : header.findViewById(mId); + mParentData = mExtractor == null ? null : mExtractor.extractData(mParentRow); mApply = !mComparator.isEmpty(mParentView); } @@ -282,7 +297,9 @@ public class NotificationGroupingUtil { // when for example showing an undo notification return; } - mApply = mComparator.compare(mParentView, ownView); + Object childData = mExtractor == null ? null : mExtractor.extractData(row); + mApply = mComparator.compare(mParentView, ownView, + mParentData, childData); } public void apply(ExpandableNotificationRow row) { @@ -314,9 +331,11 @@ public class NotificationGroupingUtil { /** * @param parent the view with the given id in the group header * @param child the view with the given id in the child notification + * @param parentData optional data for the parent + * @param childData optional data for the child * @return whether to views are the same */ - boolean compare(View parent, View child); + boolean compare(View parent, View child, Object parentData, Object childData); boolean isEmpty(View view); } @@ -327,7 +346,7 @@ public class NotificationGroupingUtil { private static class BadgeComparator implements ViewComparator { @Override - public boolean compare(View parent, View child) { + public boolean compare(View parent, View child, Object parentData, Object childData) { return parent.getVisibility() != View.GONE; } @@ -345,7 +364,7 @@ public class NotificationGroupingUtil { private static class TextViewComparator implements ViewComparator { @Override - public boolean compare(View parent, View child) { + public boolean compare(View parent, View child, Object parentData, Object childData) { TextView parentView = (TextView) parent; CharSequence parentText = parentView == null ? "" : parentView.getText(); TextView childView = (TextView) child; @@ -361,7 +380,7 @@ public class NotificationGroupingUtil { private abstract static class IconComparator implements ViewComparator { @Override - public boolean compare(View parent, View child) { + public boolean compare(View parent, View child, Object parentData, Object childData) { return false; } @@ -421,14 +440,14 @@ public class NotificationGroupingUtil { private static class AppNameComparator extends TextViewComparator { @Override - public boolean compare(View parent, View child) { + public boolean compare(View parent, View child, Object parentData, Object childData) { if (isEmpty(child)) { // In headerless notifications the AppName view exists but is usually GONE (and not // populated). We need to treat this case as equal to the header in order to // deduplicate the view. return true; } - return super.compare(parent, child); + return super.compare(parent, child, parentData, childData); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java index 85fad420daf1..50cf015af5e3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java @@ -89,6 +89,9 @@ public interface NotificationShadeWindowController extends RemoteInputController /** Sets the state of whether the glanceable hub is showing or not. */ default void setGlanceableHubShowing(boolean showing) {} + /** Sets the state of whether the glanceable hub can change with user's orientation or not. */ + default void setGlanceableHubOrientationAware(boolean isOrientationAware) {} + /** Sets the state of whether the backdrop is showing or not. */ default void setBackdropShowing(boolean showing) {} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt index f52b9247f6cc..df8fb5e75368 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt @@ -91,7 +91,7 @@ constructor( ImageSpan(it, ImageSpan.ALIGN_CENTER) } val decoratedSummary = - SpannableString("x" + entry.ranking.summarization).apply { + SpannableString("x " + entry.ranking.summarization).apply { setSpan( /* what = */ imageSpan, /* start = */ 0, @@ -100,9 +100,9 @@ constructor( ) entry.ranking.summarization?.let { setSpan( - /* what = */ StyleSpan(Typeface.BOLD), - /* start = */ 1, - /* end = */ it.length, + /* what = */ StyleSpan(Typeface.ITALIC), + /* start = */ 2, + /* end = */ it.length + 2, /* flags = */ Spanned.SPAN_EXCLUSIVE_INCLUSIVE, ) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimator.kt index 74faf2576abd..0a24d7a71ce9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimator.kt @@ -15,12 +15,12 @@ */ package com.android.systemui.statusbar.notification +import android.util.FloatProperty import android.util.Property import android.view.View -import androidx.dynamicanimation.animation.DynamicAnimation -import androidx.dynamicanimation.animation.FloatPropertyCompat -import androidx.dynamicanimation.animation.SpringAnimation -import androidx.dynamicanimation.animation.SpringForce +import com.android.internal.dynamicanimation.animation.DynamicAnimation +import com.android.internal.dynamicanimation.animation.SpringAnimation +import com.android.internal.dynamicanimation.animation.SpringForce import com.android.systemui.res.R import com.android.systemui.statusbar.notification.PhysicsPropertyAnimator.Companion.createDefaultSpring import com.android.systemui.statusbar.notification.stack.AnimationProperties @@ -33,8 +33,8 @@ import com.android.systemui.statusbar.notification.stack.AnimationProperties */ data class PhysicsProperty(val tag: Int, val property: Property<View, Float>) { val offsetProperty = - object : FloatPropertyCompat<View>(property.name) { - override fun getValue(view: View): Float { + object : FloatProperty<View>(property.name) { + override fun get(view: View): Float { return property.get(view) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt index 248b5286803f..28923b0ab71e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.collection.coordinator +import android.app.NotificationChannel.SYSTEM_RESERVED_IDS import com.android.systemui.statusbar.notification.collection.GroupEntry import com.android.systemui.statusbar.notification.collection.PipelineEntry import com.android.systemui.statusbar.notification.collection.NotifPipeline @@ -89,6 +90,7 @@ class ConversationCoordinator @Inject constructor( object : NotifSectioner("Priority People", BUCKET_PRIORITY_PEOPLE) { override fun isInSection(entry: PipelineEntry): Boolean { return getPeopleType(entry) == TYPE_IMPORTANT_PERSON + && entry.representativeEntry?.channel?.id !in SYSTEM_RESERVED_IDS } } @@ -96,10 +98,12 @@ class ConversationCoordinator @Inject constructor( val peopleAlertingSectioner = object : NotifSectioner("People(alerting)", BUCKET_PEOPLE) { override fun isInSection(entry: PipelineEntry): Boolean { if (SortBySectionTimeFlag.isEnabled) { - return highPriorityProvider.isHighPriorityConversation(entry) - || isConversation(entry) + return (highPriorityProvider.isHighPriorityConversation(entry) + || isConversation(entry)) + && entry.representativeEntry?.channel?.id !in SYSTEM_RESERVED_IDS } else { return highPriorityProvider.isHighPriorityConversation(entry) + && entry.representativeEntry?.channel?.id !in SYSTEM_RESERVED_IDS } } @@ -111,11 +115,12 @@ class ConversationCoordinator @Inject constructor( } val peopleSilentSectioner = object : NotifSectioner("People(silent)", BUCKET_PEOPLE) { - // Because the peopleAlertingSectioner is above this one, it will claim all conversations that are alerting. - // All remaining conversations must be silent. + // Because the peopleAlertingSectioner is above this one, it will claim all conversations + // that are alerting. All remaining conversations must be silent. override fun isInSection(entry: PipelineEntry): Boolean { SortBySectionTimeFlag.assertInLegacyMode() return isConversation(entry) + && entry.representativeEntry?.channel?.id !in SYSTEM_RESERVED_IDS } override fun getComparator(): NotifComparator { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt index 7959e99f3189..2a01a14f56aa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt @@ -20,6 +20,7 @@ import android.app.Flags import android.app.Flags.notificationsRedesignTemplates import android.app.Notification import android.graphics.PorterDuff +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.View.GONE @@ -80,9 +81,13 @@ fun AODPromotedNotification( val content = viewModel.content ?: return val audiblyAlertedIconVisible = viewModel.audiblyAlertedIconVisible - key(content.identity) { - val layoutResource = content.layoutResource ?: return + val layoutResource = content.layoutResource + if (layoutResource == null) { + Log.w(TAG, "not displaying promoted notif with ineligible style on AOD") + return + } + key(content.identity) { val sidePaddings = dimensionResource(systemuiR.dimen.notification_side_paddings) val sidePaddingValues = PaddingValues(horizontal = sidePaddings, vertical = 0.dp) 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 a081ad5bb82c..6837cb2a6292 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 @@ -119,6 +119,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView protected Point mTargetPoint; private boolean mDismissed; private boolean mRefocusOnDismiss; + protected boolean mIsBlurSupported; public ActivatableNotificationView(Context context, AttributeSet attrs) { super(context, attrs); @@ -128,12 +129,13 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } private void updateColors() { - if (notificationRowTransparency()) { + if (usesTransparentBackground()) { mNormalColor = SurfaceEffectColors.surfaceEffect1(getContext()); } else { mNormalColor = mContext.getColor( com.android.internal.R.color.materialColorSurfaceContainerHigh); } + setBackgroundToNormalColor(); mTintedRippleColor = mContext.getColor( R.color.notification_ripple_tinted_color); mNormalRippleColor = mContext.getColor( @@ -144,6 +146,12 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mOverrideAmount = 0.0f; } + private void setBackgroundToNormalColor() { + if (mBackgroundNormal != null) { + mBackgroundNormal.setNormalColor(mNormalColor); + } + } + /** * Reload background colors from resources and invalidate views. */ @@ -173,6 +181,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mBackgroundNormal = findViewById(R.id.backgroundNormal); mFakeShadow = findViewById(R.id.fake_shadow); mShadowHidden = mFakeShadow.getVisibility() != VISIBLE; + setBackgroundToNormalColor(); initBackground(); updateBackgroundTint(); updateOutlineAlpha(); @@ -326,6 +335,21 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mBackgroundNormal.setBottomAmountClips(!isChildInGroup()); } + public void setIsBlurSupported(boolean isBlurSupported) { + if (!notificationRowTransparency()) { + return; + } + boolean usedTransparentBackground = usesTransparentBackground(); + mIsBlurSupported = isBlurSupported; + if (usedTransparentBackground != usesTransparentBackground()) { + updateBackgroundColors(); + } + } + + protected boolean usesTransparentBackground() { + return mIsBlurSupported && notificationRowTransparency(); + } + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); 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 179951f67902..3ef1fd2275a2 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 @@ -20,8 +20,8 @@ import static android.app.Flags.notificationsRedesignTemplates; import static android.app.Notification.Action.SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY; import static android.service.notification.NotificationListenerService.REASON_CANCEL; -import static com.android.systemui.Flags.notificationsPinnedHunInShade; import static com.android.systemui.Flags.notificationRowTransparency; +import static com.android.systemui.Flags.notificationsPinnedHunInShade; import static com.android.systemui.flags.Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE; import static com.android.systemui.statusbar.notification.NotificationUtils.logKey; import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.PARENT_DISMISSED; @@ -1678,14 +1678,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView if (view != null) { view.setBackgroundTintColor(color); } - if (notificationRowTransparency() - && (mBackgroundNormal != null)) { + if (notificationRowTransparency() && mBackgroundNormal != null) { if (NotificationBundleUi.isEnabled()) { - mBackgroundNormal.setBgIsColorized(mEntryAdapter.isColorized()); + mBackgroundNormal.setBgIsColorized( + usesTransparentBackground() && mEntryAdapter.isColorized()); } else { if (mEntry != null) { mBackgroundNormal.setBgIsColorized( - mEntry.getSbn().getNotification().isColorized()); + usesTransparentBackground() + && mEntry.getSbn().getNotification().isColorized()); } } } @@ -3021,6 +3022,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mUserLocked = userLocked; mPrivateLayout.setUserExpanding(userLocked); + mPublicLayout.setUserExpanding(userLocked); // This is intentionally not guarded with mIsSummaryWithChildren since we might have had // children but not anymore. if (mChildrenContainer != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java index 344d0f6d3741..ba80f016cad4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java @@ -51,6 +51,7 @@ import java.util.Objects; */ public class HybridConversationNotificationView extends HybridNotificationView { + private static final int MAX_SUMMARIZATION_LINES = 2; private ImageView mConversationIconView; private TextView mConversationSenderName; private ViewStub mConversationFacePileStub; @@ -292,11 +293,14 @@ public class HybridConversationNotificationView extends HybridNotificationView { @Nullable CharSequence summarization ) { if (AsyncHybridViewInflation.isUnexpectedlyInLegacyMode()) return; - if (summarization != null) { + if (!TextUtils.isEmpty(summarization)) { mConversationSenderName.setVisibility(GONE); titleText = null; contentText = summarization; + mTextView.setSingleLine(false); + mTextView.setMaxLines(MAX_SUMMARIZATION_LINES); } else { + mTextView.setSingleLine(true); if (conversationSenderName == null) { mConversationSenderName.setVisibility(GONE); } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java index 4978fa4880aa..e1219e88a405 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java @@ -73,7 +73,7 @@ public class NotificationBackgroundView extends View implements Dumpable, private int mDrawableAlpha = 255; private final ColorStateList mLightColoredStatefulColors; private final ColorStateList mDarkColoredStatefulColors; - private final int mNormalColor; + private int mNormalColor; private boolean mBgIsColorized = false; private boolean mForceOpaque = false; private final int convexR = 9; @@ -89,15 +89,13 @@ public class NotificationBackgroundView extends View implements Dumpable, R.color.notification_state_color_light); mDarkColoredStatefulColors = getResources().getColorStateList( R.color.notification_state_color_dark); - if (notificationRowTransparency()) { - mNormalColor = SurfaceEffectColors.surfaceEffect1(getContext()); - } else { - mNormalColor = mContext.getColor( - com.android.internal.R.color.materialColorSurfaceContainerHigh); - } mFocusOverlayStroke = getResources().getDimension(R.dimen.notification_focus_stroke_width); } + public void setNormalColor(int color) { + mNormalColor = color; + } + @Override public void onTargetVisibilityChanged(boolean targetVisible) { if (NotificationAddXOnHoverToDismiss.isUnexpectedlyInLegacyMode()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt index f0b5c3667962..8984f2c4220d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt @@ -50,6 +50,15 @@ object ActivatableNotificationViewBinder { view.registerListenersWhileAttached(touchHandler) } } + view.repeatWhenAttached { + repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { + viewModel.isBlurSupported.collect { supported -> + view.setIsBlurSupported(supported) + } + } + } + } } private suspend fun ActivatableNotificationView.registerListenersWhileAttached( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModel.kt index f46d42473863..9a86ffbe33b6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModel.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.row.ui.viewmodel import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor +import com.android.systemui.window.domain.interactor.WindowRootViewBlurInteractor import dagger.Module import dagger.Provides import kotlinx.coroutines.flow.Flow @@ -26,25 +27,34 @@ import kotlinx.coroutines.flow.map interface ActivatableNotificationViewModel : ExpandableOutlineViewModel { /** Does the view react to touches? */ val isTouchable: Flow<Boolean> + val isBlurSupported: Flow<Boolean> companion object { operator fun invoke( a11yInteractor: AccessibilityInteractor, - ): ActivatableNotificationViewModel = ActivatableNotificationViewModelImpl(a11yInteractor) + windowRootViewBlurInteractor: WindowRootViewBlurInteractor + ): ActivatableNotificationViewModel = + ActivatableNotificationViewModelImpl(a11yInteractor, windowRootViewBlurInteractor) } } private class ActivatableNotificationViewModelImpl( a11yInteractor: AccessibilityInteractor, + windowRootViewBlurInteractor: WindowRootViewBlurInteractor, ) : ActivatableNotificationViewModel { override val isTouchable: Flow<Boolean> = // If a11y touch exploration is enabled, then the activatable view should ignore touches a11yInteractor.isTouchExplorationEnabled.map { !it } + override val isBlurSupported: Flow<Boolean> = + windowRootViewBlurInteractor.isBlurCurrentlySupported } @Module object ActivatableNotificationViewModelModule { @Provides - fun provideViewModel(interactor: AccessibilityInteractor) = - ActivatableNotificationViewModel(interactor) + fun provideViewModel( + a11yInteractor: AccessibilityInteractor, + windowRootViewBlurInteractor: WindowRootViewBlurInteractor + ) = + ActivatableNotificationViewModel(a11yInteractor, windowRootViewBlurInteractor) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationProperties.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationProperties.java index 3d60092cf29a..4d01cbd19253 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationProperties.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationProperties.java @@ -23,7 +23,7 @@ import android.util.Property; import android.view.View; import android.view.animation.Interpolator; -import androidx.dynamicanimation.animation.DynamicAnimation; +import com.android.internal.dynamicanimation.animation.DynamicAnimation; import java.util.function.Consumer; 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 9a5cf9ceed53..19abfa8140df 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 @@ -32,10 +32,9 @@ import android.content.Context; import android.util.Property; import android.view.View; -import androidx.dynamicanimation.animation.DynamicAnimation; - import com.android.app.animation.Interpolators; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.dynamicanimation.animation.DynamicAnimation; import com.android.systemui.res.R; import com.android.systemui.shared.clocks.AnimatableClockView; import com.android.systemui.statusbar.NotificationShelf; 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 2ef6f362af34..29dbeb2c8ee4 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 @@ -30,10 +30,9 @@ import android.util.Property; import android.view.View; import android.view.animation.Interpolator; -import androidx.dynamicanimation.animation.DynamicAnimation; -import androidx.dynamicanimation.animation.SpringAnimation; - import com.android.app.animation.Interpolators; +import com.android.internal.dynamicanimation.animation.DynamicAnimation; +import com.android.internal.dynamicanimation.animation.SpringAnimation; import com.android.systemui.Dumpable; import com.android.systemui.res.R; import com.android.systemui.statusbar.notification.AnimatableProperty; diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelKosmos.kt deleted file mode 100644 index 43d3eb7b857a..000000000000 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelKosmos.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2024 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.communal.ui.viewmodel - -import android.service.dream.dreamManager -import com.android.internal.logging.uiEventLogger -import com.android.systemui.communal.domain.interactor.communalPrefsInteractor -import com.android.systemui.communal.domain.interactor.communalSettingsInteractor -import com.android.systemui.kosmos.Kosmos -import com.android.systemui.kosmos.testDispatcher -import com.android.systemui.plugins.activityStarter -import com.android.systemui.statusbar.policy.batteryController - -val Kosmos.communalToDreamButtonViewModel by - Kosmos.Fixture { - CommunalToDreamButtonViewModel( - backgroundContext = testDispatcher, - batteryController = batteryController, - prefsInteractor = communalPrefsInteractor, - settingsInteractor = communalSettingsInteractor, - activityStarter = activityStarter, - dreamManager = dreamManager, - uiEventLogger = uiEventLogger, - ) - } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelKosmos.kt index b233d3ff9e0f..c6f55f053d35 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelKosmos.kt @@ -16,16 +16,20 @@ package com.android.systemui.keyguard.ui.viewmodel +import com.android.systemui.communal.domain.interactor.communalSceneInteractor import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.statusbar.policy.keyguardStateController val Kosmos.glanceableHubToPrimaryBouncerTransitionViewModel by Fixture { GlanceableHubToPrimaryBouncerTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, blurConfig = blurConfig, communalSettingsInteractor = communalSettingsInteractor, + communalSceneInteractor = communalSceneInteractor, + keyguardStateController = keyguardStateController, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt index 02cf1f5a7214..dff9f3abfc05 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt @@ -29,6 +29,7 @@ import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository import com.android.systemui.communal.domain.interactor.communalInteractor import com.android.systemui.communal.domain.interactor.communalSceneInteractor +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.communal.ui.viewmodel.communalTransitionViewModel import com.android.systemui.concurrency.fakeExecutor import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor @@ -87,6 +88,7 @@ import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.wifiIntera import com.android.systemui.statusbar.policy.configurationController import com.android.systemui.statusbar.policy.data.repository.fakeDeviceProvisioningRepository import com.android.systemui.statusbar.policy.domain.interactor.deviceProvisioningInteractor +import com.android.systemui.statusbar.policy.keyguardStateController import com.android.systemui.statusbar.ui.viewmodel.keyguardStatusBarViewModel import com.android.systemui.util.time.systemClock import com.android.systemui.volume.domain.interactor.volumeDialogInteractor @@ -126,6 +128,7 @@ class KosmosJavaAdapter() { val keyguardInteractor by lazy { kosmos.keyguardInteractor } val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository } val keyguardTransitionInteractor by lazy { kosmos.keyguardTransitionInteractor } + val keyguardStateController by lazy { kosmos.keyguardStateController } val keyguardStatusBarViewModel by lazy { kosmos.keyguardStatusBarViewModel } val powerRepository by lazy { kosmos.fakePowerRepository } val clock by lazy { kosmos.systemClock } @@ -147,6 +150,7 @@ class KosmosJavaAdapter() { val deviceUnlockedInteractor by lazy { kosmos.deviceUnlockedInteractor } val communalInteractor by lazy { kosmos.communalInteractor } val communalSceneInteractor by lazy { kosmos.communalSceneInteractor } + val communalSettingsInteractor by lazy { kosmos.communalSettingsInteractor } val sceneContainerPlugin by lazy { kosmos.sceneContainerPlugin } val deviceProvisioningInteractor by lazy { kosmos.deviceProvisioningInteractor } val fakeDeviceProvisioningRepository by lazy { kosmos.fakeDeviceProvisioningRepository } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelKosmos.kt index 2523975c182c..7ccbdb79101c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelKosmos.kt @@ -19,9 +19,11 @@ package com.android.systemui.statusbar.notification.row.ui.viewmodel import com.android.systemui.accessibility.domain.interactor.accessibilityInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.window.domain.interactor.windowRootViewBlurInteractor val Kosmos.activatableNotificationViewModel by Fixture { ActivatableNotificationViewModel.invoke( a11yInteractor = accessibilityInteractor, + windowRootViewBlurInteractor = windowRootViewBlurInteractor, ) } diff --git a/proto/src/metrics_constants/OWNERS b/proto/src/metrics_constants/OWNERS index 7009282b66e1..169f887ede56 100644 --- a/proto/src/metrics_constants/OWNERS +++ b/proto/src/metrics_constants/OWNERS @@ -1,4 +1,2 @@ cwren@android.com -yanglu@google.com yaochen@google.com -yro@google.com diff --git a/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NonNull.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NonNull.java index db3cd8ed712f..1153a77d5c9a 100644 --- a/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NonNull.java +++ b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NonNull.java @@ -35,14 +35,4 @@ import java.lang.annotation.Target; @Retention(SOURCE) @Target({FIELD, METHOD, PARAMETER, TYPE_USE}) @libcore.api.IntraCoreApi -public @interface NonNull { - /** - * Min Android API level (inclusive) to which this annotation is applied. - */ - int from() default Integer.MIN_VALUE; - - /** - * Max Android API level to which this annotation is applied. - */ - int to() default Integer.MAX_VALUE; -} +public @interface NonNull {} diff --git a/ravenwood/runtime-helper-src/libcore-fake/libcore/util/Nullable.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/Nullable.java index 3371978b0568..295f083426ff 100644 --- a/ravenwood/runtime-helper-src/libcore-fake/libcore/util/Nullable.java +++ b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/Nullable.java @@ -35,14 +35,4 @@ import java.lang.annotation.Target; @Retention(SOURCE) @Target({FIELD, METHOD, PARAMETER, TYPE_USE}) @libcore.api.IntraCoreApi -public @interface Nullable { - /** - * Min Android API level (inclusive) to which this annotation is applied. - */ - int from() default Integer.MIN_VALUE; - - /** - * Max Android API level to which this annotation is applied. - */ - int to() default Integer.MAX_VALUE; -} +public @interface Nullable {} diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt index 735635cc309a..b41ce0f65017 100644 --- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt +++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt @@ -268,18 +268,45 @@ fun writeByteCodeToReturn(methodDescriptor: String, writer: MethodVisitor) { } /** + * Write bytecode to pop the 2 uninitialized instances out of the stack + * after performing constructor redirection. + */ +fun adjustStackForConstructorRedirection(writer: MethodVisitor) { + // Stack: { uninitialized, uninitialized, obj } + writer.visitInsn(Opcodes.SWAP) + // Stack: { uninitialized, obj, uninitialized } + writer.visitInsn(Opcodes.POP) + // Stack: { uninitialized, obj } + writer.visitInsn(Opcodes.SWAP) + // Stack: { obj, uninitialized } + writer.visitInsn(Opcodes.POP) + // Stack: { obj } + + // We end up with only the desired object on the stack +} + +/** * Given a method descriptor, insert an [argType] as the first argument to it. */ fun prependArgTypeToMethodDescriptor(methodDescriptor: String, classInternalName: String): String { val returnType = Type.getReturnType(methodDescriptor) val argTypes = Type.getArgumentTypes(methodDescriptor).toMutableList() - argTypes.add(0, Type.getType("L" + classInternalName + ";")) + argTypes.add(0, Type.getType("L$classInternalName;")) return Type.getMethodDescriptor(returnType, *argTypes.toTypedArray()) } /** + * Given a method descriptor, change the return type to [classInternalName]. + */ +fun changeMethodDescriptorReturnType(methodDescriptor: String, classInternalName: String): String { + val argTypes = Type.getArgumentTypes(methodDescriptor) + val returnType = Type.getType("L$classInternalName;") + return Type.getMethodDescriptor(returnType, *argTypes) +} + +/** * Return the "visibility" modifier from an `access` integer. * * (see https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.1-200-E.1) diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterRemapper.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterRemapper.kt index c5a2f9ff5e96..bba4681d3838 100644 --- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterRemapper.kt +++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterRemapper.kt @@ -15,6 +15,7 @@ */ package com.android.hoststubgen.filters +import com.android.hoststubgen.log import org.objectweb.asm.commons.Remapper /** @@ -23,19 +24,25 @@ import org.objectweb.asm.commons.Remapper class FilterRemapper(val filter: OutputFilter) : Remapper() { private val cache = mutableMapOf<String, String>() - override fun mapType(typeInternalName: String?): String? { + + override fun map(typeInternalName: String?): String? { if (typeInternalName == null) { return null } cache[typeInternalName]?.let { + // log.d("Cached rename from $typeInternalName to $it") return it } - var mapped = filter.remapType(typeInternalName) ?: typeInternalName + var mapped = filter.remapType(typeInternalName) + if (mapped != null) { + log.d("Renaming type $typeInternalName to $mapped") + } else { + // log.d("Not renaming type $typeInternalName") + } + mapped = mapped ?: typeInternalName cache[typeInternalName] = mapped return mapped } - - // TODO Do we need to implement mapPackage(), etc too? }
\ No newline at end of file diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt index d0c97c006647..dd353e9caeff 100644 --- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt +++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt @@ -100,7 +100,6 @@ interface PolicyFileProcessor { methodName: String, methodDesc: String, replaceSpec: TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec, - policy: FilterPolicyWithReason, ) } @@ -286,9 +285,10 @@ class TextFileFilterPolicyBuilder( methodName: String, methodDesc: String, replaceSpec: TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec, - policy: FilterPolicyWithReason, ) { - imf.setPolicyForMethod(className, methodName, methodDesc, policy) + // Keep the source method, because the target method may call it. + imf.setPolicyForMethod(className, methodName, methodDesc, + FilterPolicy.Keep.withReason(FILTER_REASON)) methodReplaceSpec.add(replaceSpec) } } @@ -642,7 +642,6 @@ class TextFileFilterPolicyParser { methodName, signature, spec, - policyWithReason, ) } else { // It's an in-class replace. diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt index a78c6552b8d0..bc90d1248322 100644 --- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt +++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt @@ -15,7 +15,6 @@ */ package com.android.hoststubgen.filters -import com.android.hoststubgen.log import java.util.regex.Pattern /** @@ -34,17 +33,12 @@ class TextFilePolicyRemapperFilter( val typeInternalNamePrefix: String, ) - private val cache = mutableMapOf<String, String>() - override fun remapType(className: String): String? { - var mapped: String = className typeRenameSpecs.forEach { if (it.typeInternalNamePattern.matcher(className).matches()) { - mapped = it.typeInternalNamePrefix + className - log.d("Renaming type $className to $mapped") + return it.typeInternalNamePrefix + className } } - cache[className] = mapped - return mapped + return null } } diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt index 70e7d46bb6cd..b8a357668c2b 100644 --- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt +++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt @@ -17,7 +17,10 @@ package com.android.hoststubgen.visitors import com.android.hoststubgen.asm.CLASS_INITIALIZER_DESC import com.android.hoststubgen.asm.CLASS_INITIALIZER_NAME +import com.android.hoststubgen.asm.CTOR_NAME import com.android.hoststubgen.asm.ClassNodes +import com.android.hoststubgen.asm.adjustStackForConstructorRedirection +import com.android.hoststubgen.asm.changeMethodDescriptorReturnType import com.android.hoststubgen.asm.prependArgTypeToMethodDescriptor import com.android.hoststubgen.asm.writeByteCodeToPushArguments import com.android.hoststubgen.asm.writeByteCodeToReturn @@ -33,6 +36,7 @@ import org.objectweb.asm.ClassVisitor import org.objectweb.asm.MethodVisitor import org.objectweb.asm.Opcodes import org.objectweb.asm.Opcodes.INVOKEINTERFACE +import org.objectweb.asm.Opcodes.INVOKESPECIAL import org.objectweb.asm.Opcodes.INVOKESTATIC import org.objectweb.asm.Opcodes.INVOKEVIRTUAL import org.objectweb.asm.Type @@ -376,53 +380,90 @@ class ImplGeneratingAdapter( val callerMethodName: String, next: MethodVisitor?, ) : MethodVisitor(OPCODE_VERSION, next) { - override fun visitMethodInsn( + + private fun doReplace( opcode: Int, - owner: String?, - name: String?, - descriptor: String?, - isInterface: Boolean, - ) { + owner: String, + name: String, + descriptor: String, + ): Boolean { when (opcode) { INVOKESTATIC, INVOKEVIRTUAL, INVOKEINTERFACE -> {} - else -> { - // Don't touch other opcodes. - super.visitMethodInsn(opcode, owner, name, descriptor, isInterface) - return - } + // We only support INVOKESPECIAL when replacing constructors. + INVOKESPECIAL -> if (name != CTOR_NAME) return false + // Don't touch other opcodes. + else -> return false } + val to = filter.getMethodCallReplaceTo( - currentClassName, callerMethodName, owner!!, name!!, descriptor!! + currentClassName, callerMethodName, owner, name, descriptor ) if (to == null // Don't replace if the target is the callsite. || (to.className == currentClassName && to.methodName == callerMethodName) ) { - super.visitMethodInsn(opcode, owner, name, descriptor, isInterface) - return + return false } - // Replace the method call with a (static) call to the target method. - // If it's a non-static call, the target method's first argument will receive "this". - // (Because of that, we don't need to manipulate the stack. Just replace the - // method call.) + if (opcode != INVOKESPECIAL) { + // It's either a static method call or virtual method call. + // Either way, we don't manipulate the stack and send the original arguments + // as is to the target method. + // + // If the call is a virtual call (INVOKEVIRTUAL or INVOKEINTERFACE), then + // the first argument in the stack is the "this" object, so the target + // method must have an extra argument as the first argument to receive it. + // We update the method descriptor with prependArgTypeToMethodDescriptor() + // to absorb this difference. + + val toDesc = if (opcode == INVOKESTATIC) { + descriptor + } else { + prependArgTypeToMethodDescriptor(descriptor, owner) + } - val toDesc = if (opcode == INVOKESTATIC) { - // Static call to static call, no need to change the desc. - descriptor + mv.visitMethodInsn( + INVOKESTATIC, + to.className, + to.methodName, + toDesc, + false + ) } else { - // Need to prepend the "this" type to the descriptor. - prependArgTypeToMethodDescriptor(descriptor, owner) + // Because an object initializer does not return a value, the newly created + // but uninitialized object will be dup-ed at the bottom of the stack. + // We first call the target method to consume the constructor arguments at the top. + + val toDesc = changeMethodDescriptorReturnType(descriptor, owner) + + // Before stack: { uninitialized, uninitialized, args... } + mv.visitMethodInsn( + INVOKESTATIC, + to.className, + to.methodName, + toDesc, + false + ) + // After stack: { uninitialized, uninitialized, obj } + + // Next we pop the 2 uninitialized instances out of the stack. + adjustStackForConstructorRedirection(mv) } - mv.visitMethodInsn( - INVOKESTATIC, - to.className, - to.methodName, - toDesc, - false - ) + return true + } + + override fun visitMethodInsn( + opcode: Int, + owner: String, + name: String, + descriptor: String, + isInterface: Boolean, + ) { + if (!doReplace(opcode, owner, name, descriptor)) { + super.visitMethodInsn(opcode, owner, name, descriptor, isInterface) + } } } } diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/01-hoststubgen-test-tiny-framework-orig-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/01-hoststubgen-test-tiny-framework-orig-dump.txt index 635f66d8e90c..2b942a91a8f8 100644 --- a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/01-hoststubgen-test-tiny-framework-orig-dump.txt +++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/01-hoststubgen-test-tiny-framework-orig-dump.txt @@ -1883,6 +1883,42 @@ BootstrapMethods: InnerClasses: public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester.class + Compiled from "TinyFrameworkMethodCallReplace.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester + minor version: 0 + major version: 65 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 1, attributes: 3 +Constant pool: +{ + public int i; + descriptor: I + flags: (0x0001) ACC_PUBLIC + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester(int); + descriptor: (I)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=2, locals=2, args_size=2 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: aload_0 + x: iload_1 + x: putfield #x // Field i:I + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + 0 10 1 i I +} +SourceFile: "TinyFrameworkMethodCallReplace.java" +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace +InnerClasses: + public static #x= #x of #x; // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class Compiled from "TinyFrameworkMethodCallReplace.java" public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo @@ -1891,7 +1927,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 3, attributes: 3 + interfaces: 0, fields: 0, methods: 4, attributes: 3 Constant pool: { public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo(); @@ -1937,10 +1973,28 @@ Constant pool: Start Length Slot Name Signature 0 4 0 a I 0 4 1 b I + + public static com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester newConstructorTester(int); + descriptor: (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=1, args_size=1 + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + x: dup + x: iload_0 + x: iconst_1 + x: iadd + x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester."<init>":(I)V + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 11 0 i I } SourceFile: "TinyFrameworkMethodCallReplace.java" NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace InnerClasses: + public static #x= #x of #x; // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.class Compiled from "TinyFrameworkMethodCallReplace.java" @@ -1950,7 +2004,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 5, attributes: 5 + interfaces: 0, fields: 0, methods: 6, attributes: 5 Constant pool: { public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace(); @@ -2008,6 +2062,21 @@ Constant pool: x: ireturn LineNumberTable: + public static com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester constructorReplaceTester(int); + descriptor: (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + x: dup + x: iload_0 + x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester."<init>":(I)V + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 9 0 i I + private static int originalAdd(int, int); descriptor: (II)I flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -2046,6 +2115,7 @@ RuntimeInvisibleAnnotations: android.hosttest.annotation.HostSideTestWholeClassKeep NestMembers: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo + com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester BootstrapMethods: x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; Method arguments: @@ -2053,8 +2123,9 @@ BootstrapMethods: #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.lambda$nonStaticMethodCallReplaceTester$0:(Ljava/util/concurrent/atomic/AtomicBoolean;)V #x ()V InnerClasses: + public static #x= #x of #x; // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace - public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles + public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class Compiled from "TinyFrameworkNative.java" public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative @@ -3198,7 +3269,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClas flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 2, attributes: 2 + interfaces: 0, fields: 0, methods: 3, attributes: 2 Constant pool: { public com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller(); @@ -3229,6 +3300,22 @@ Constant pool: LocalVariableTable: Start Length Slot Name Signature 0 12 0 value I + + public static int bar(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=2, locals=1, args_size=1 + x: iload_0 + x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getArray:(I)[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + x: iconst_0 + x: aaload + x: invokevirtual #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getValue:()I + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 10 0 value I } SourceFile: "TinyFrameworkRenamedClassCaller.java" RuntimeInvisibleAnnotations: @@ -3242,7 +3329,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed super_class: #x // java/lang/Object - interfaces: 0, fields: 1, methods: 2, attributes: 2 + interfaces: 0, fields: 1, methods: 3, attributes: 2 Constant pool: { private final int mValue; @@ -3278,6 +3365,26 @@ Constant pool: LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + + public static com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed[] getArray(int); + descriptor: (I)[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=6, locals=1, args_size=1 + x: iconst_1 + x: anewarray #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: dup + x: iconst_0 + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: dup + x: iload_0 + x: invokespecial #x // Method "<init>":(I)V + x: aastore + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 16 0 value I } SourceFile: "TinyFrameworkToBeRenamed.java" RuntimeInvisibleAnnotations: diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/03-hoststubgen-test-tiny-framework-host-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/03-hoststubgen-test-tiny-framework-host-dump.txt index 51a33554afa9..d493ad152225 100644 --- a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/03-hoststubgen-test-tiny-framework-host-dump.txt +++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/03-hoststubgen-test-tiny-framework-host-dump.txt @@ -2002,6 +2002,51 @@ BootstrapMethods: #x ()Ljava/lang/Integer; NestMembers: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester.class + Compiled from "TinyFrameworkMethodCallReplace.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester + minor version: 0 + major version: 65 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 1, attributes: 4 +Constant pool: +{ + public int i; + descriptor: I + flags: (0x0001) ACC_PUBLIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester(int); + descriptor: (I)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=2, locals=2, args_size=2 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: aload_0 + x: iload_1 + x: putfield #x // Field i:I + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + 0 10 1 i I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep +} +InnerClasses: + public static #x= #x of #x; // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace +SourceFile: "TinyFrameworkMethodCallReplace.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class Compiled from "TinyFrameworkMethodCallReplace.java" public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo @@ -2010,7 +2055,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 3, attributes: 4 + interfaces: 0, fields: 0, methods: 4, attributes: 4 Constant pool: { public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo(); @@ -2065,9 +2110,30 @@ Constant pool: RuntimeVisibleAnnotations: x: #x() com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + public static com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester newConstructorTester(int); + descriptor: (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=1, args_size=1 + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + x: dup + x: iload_0 + x: iconst_1 + x: iadd + x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester."<init>":(I)V + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 11 0 i I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep } InnerClasses: - public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace + public static #x= #x of #x; // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace + public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace SourceFile: "TinyFrameworkMethodCallReplace.java" RuntimeVisibleAnnotations: x: #x() @@ -2081,7 +2147,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 4, attributes: 6 + interfaces: 0, fields: 0, methods: 6, attributes: 6 Constant pool: { public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace(); @@ -2148,6 +2214,48 @@ Constant pool: x: #x() com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + public static com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester constructorReplaceTester(int); + descriptor: (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + x: dup + x: iload_0 + x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.newConstructorTester:(I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + x: swap + x: pop + x: swap + x: pop + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 13 0 i I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + private static int originalAdd(int, int); + descriptor: (II)I + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=2, args_size=2 + x: iload_0 + x: iload_1 + x: iadd + x: iconst_1 + x: isub + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 6 0 a I + 0 6 1 b I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + private static void lambda$nonStaticMethodCallReplaceTester$0(java.util.concurrent.atomic.AtomicBoolean); descriptor: (Ljava/util/concurrent/atomic/AtomicBoolean;)V flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC @@ -2167,6 +2275,7 @@ Constant pool: com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep } InnerClasses: + public static #x= #x of #x; // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles SourceFile: "TinyFrameworkMethodCallReplace.java" @@ -2184,6 +2293,7 @@ BootstrapMethods: #x ()V NestMembers: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo + com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class Compiled from "TinyFrameworkNative.java" public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative @@ -3392,7 +3502,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClas flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 2, attributes: 3 + interfaces: 0, fields: 0, methods: 3, attributes: 3 Constant pool: { public com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller(); @@ -3429,6 +3539,25 @@ Constant pool: RuntimeVisibleAnnotations: x: #x() com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + public static int bar(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=2, locals=1, args_size=1 + x: iload_0 + x: invokestatic #x // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getArray:(I)[Lrename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + x: iconst_0 + x: aaload + x: invokevirtual #x // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getValue:()I + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 10 0 value I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep } SourceFile: "TinyFrameworkRenamedClassCaller.java" RuntimeVisibleAnnotations: @@ -3867,7 +3996,7 @@ public class rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFramew flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed super_class: #x // java/lang/Object - interfaces: 0, fields: 1, methods: 2, attributes: 3 + interfaces: 0, fields: 1, methods: 3, attributes: 3 Constant pool: { private final int mValue; @@ -3891,7 +4020,7 @@ Constant pool: LineNumberTable: LocalVariableTable: Start Length Slot Name Signature - 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + 0 10 0 this Lrename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; 0 10 1 value I RuntimeVisibleAnnotations: x: #x() @@ -3908,7 +4037,30 @@ Constant pool: LineNumberTable: LocalVariableTable: Start Length Slot Name Signature - 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + 0 5 0 this Lrename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + public static rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed[] getArray(int); + descriptor: (I)[Lrename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=6, locals=1, args_size=1 + x: iconst_1 + x: anewarray #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: dup + x: iconst_0 + x: new #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: dup + x: iload_0 + x: invokespecial #x // Method "<init>":(I)V + x: aastore + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 16 0 value I RuntimeVisibleAnnotations: x: #x() com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt index a466a2e2c3a7..8978a7acefd8 100644 --- a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt +++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt @@ -2413,6 +2413,66 @@ BootstrapMethods: #x ()Ljava/lang/Integer; NestMembers: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester.class + Compiled from "TinyFrameworkMethodCallReplace.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester + minor version: 0 + major version: 65 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 4 +Constant pool: +{ + public int i; + descriptor: I + flags: (0x0001) ACC_PUBLIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester(int); + descriptor: (I)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + x: ldc #x // String <init> + x: ldc #x // String (I)V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: aload_0 + x: iload_1 + x: putfield #x // Field i:I + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + 11 10 1 i I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep +} +InnerClasses: + public static #x= #x of #x; // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace +SourceFile: "TinyFrameworkMethodCallReplace.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class Compiled from "TinyFrameworkMethodCallReplace.java" public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo @@ -2421,7 +2481,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 4, attributes: 4 + interfaces: 0, fields: 0, methods: 5, attributes: 4 Constant pool: { private static {}; @@ -2501,8 +2561,34 @@ Constant pool: RuntimeVisibleAnnotations: x: #x() com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + public static com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester newConstructorTester(int); + descriptor: (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo + x: ldc #x // String newConstructorTester + x: ldc #x // String (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + x: dup + x: iload_0 + x: iconst_1 + x: iadd + x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester."<init>":(I)V + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 11 0 i I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep } InnerClasses: + public static #x= #x of #x; // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace SourceFile: "TinyFrameworkMethodCallReplace.java" RuntimeVisibleAnnotations: @@ -2517,7 +2603,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 5, attributes: 6 + interfaces: 0, fields: 0, methods: 7, attributes: 6 Constant pool: { private static {}; @@ -2609,18 +2695,70 @@ Constant pool: x: #x() com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + public static com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester constructorReplaceTester(int); + descriptor: (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace + x: ldc #x // String constructorReplaceTester + x: ldc #x // String (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + x: dup + x: iload_0 + x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.newConstructorTester:(I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + x: swap + x: pop + x: swap + x: pop + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 13 0 i I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + private static int originalAdd(int, int); + descriptor: (II)I + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace + x: ldc #x // String originalAdd + x: ldc #x // String (II)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: iload_0 + x: iload_1 + x: iadd + x: iconst_1 + x: isub + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 6 0 a I + 11 6 1 b I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + private static void lambda$nonStaticMethodCallReplaceTester$0(java.util.concurrent.atomic.AtomicBoolean); descriptor: (Ljava/util/concurrent/atomic/AtomicBoolean;)V flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC Code: stack=4, locals=1, args_size=1 x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace - x: ldc #x // String lambda$nonStaticMethodCallReplaceTester$0 - x: ldc #x // String (Ljava/util/concurrent/atomic/AtomicBoolean;)V + x: ldc #x // String lambda$nonStaticMethodCallReplaceTester$0 + x: ldc #x // String (Ljava/util/concurrent/atomic/AtomicBoolean;)V x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V x: aload_0 - x: invokestatic #x // Method java/lang/Thread.currentThread:()Ljava/lang/Thread; + x: invokestatic #x // Method java/lang/Thread.currentThread:()Ljava/lang/Thread; x: invokevirtual #x // Method java/lang/Thread.isDaemon:()Z x: invokevirtual #x // Method java/util/concurrent/atomic/AtomicBoolean.set:(Z)V x: return @@ -2633,6 +2771,7 @@ Constant pool: com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep } InnerClasses: + public static #x= #x of #x; // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles SourceFile: "TinyFrameworkMethodCallReplace.java" @@ -2650,6 +2789,7 @@ BootstrapMethods: #x ()V NestMembers: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo + com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class Compiled from "TinyFrameworkNative.java" public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative @@ -4241,7 +4381,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClas flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 3, attributes: 3 + interfaces: 0, fields: 0, methods: 4, attributes: 3 Constant pool: { private static {}; @@ -4298,6 +4438,30 @@ Constant pool: RuntimeVisibleAnnotations: x: #x() com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + public static int bar(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller + x: ldc #x // String bar + x: ldc #x // String (I)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: iload_0 + x: invokestatic #x // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getArray:(I)[Lrename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + x: iconst_0 + x: aaload + x: invokevirtual #x // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getValue:()I + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 10 0 value I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep } SourceFile: "TinyFrameworkRenamedClassCaller.java" RuntimeVisibleAnnotations: @@ -4947,7 +5111,7 @@ public class rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFramew flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed super_class: #x // java/lang/Object - interfaces: 0, fields: 1, methods: 3, attributes: 3 + interfaces: 0, fields: 1, methods: 4, attributes: 3 Constant pool: { private final int mValue; @@ -4962,8 +5126,8 @@ Constant pool: flags: (0x000a) ACC_PRIVATE, ACC_STATIC Code: stack=2, locals=0, args_size=0 - x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: ldc #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V x: return @@ -4972,7 +5136,7 @@ Constant pool: flags: (0x0001) ACC_PUBLIC Code: stack=4, locals=2, args_size=2 - x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: ldc #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed x: ldc #x // String <init> x: ldc #x // String (I)V x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall @@ -4986,7 +5150,7 @@ Constant pool: LineNumberTable: LocalVariableTable: Start Length Slot Name Signature - 11 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + 11 10 0 this Lrename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; 11 10 1 value I RuntimeVisibleAnnotations: x: #x() @@ -4997,7 +5161,7 @@ Constant pool: flags: (0x0001) ACC_PUBLIC Code: stack=4, locals=1, args_size=1 - x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: ldc #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed x: ldc #x // String getValue x: ldc #x // String ()I x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall @@ -5008,7 +5172,35 @@ Constant pool: LineNumberTable: LocalVariableTable: Start Length Slot Name Signature - 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + 11 5 0 this Lrename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + public static rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed[] getArray(int); + descriptor: (I)[Lrename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=6, locals=1, args_size=1 + x: ldc #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: ldc #x // String getArray + x: ldc #x // String (I)[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: iconst_1 + x: anewarray #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: dup + x: iconst_0 + x: new #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: dup + x: iload_0 + x: invokespecial #x // Method "<init>":(I)V + x: aastore + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 16 0 value I RuntimeVisibleAnnotations: x: #x() com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt index 78341d7afbb9..406c61138705 100644 --- a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt +++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt @@ -1883,6 +1883,42 @@ BootstrapMethods: InnerClasses: public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester.class + Compiled from "TinyFrameworkMethodCallReplace.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 1, attributes: 3 +Constant pool: +{ + public int i; + descriptor: I + flags: (0x0001) ACC_PUBLIC + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester(int); + descriptor: (I)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=2, locals=2, args_size=2 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: aload_0 + x: iload_1 + x: putfield #x // Field i:I + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + 0 10 1 i I +} +SourceFile: "TinyFrameworkMethodCallReplace.java" +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace +InnerClasses: + public static #x= #x of #x; // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class Compiled from "TinyFrameworkMethodCallReplace.java" public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo @@ -1891,7 +1927,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 3, attributes: 3 + interfaces: 0, fields: 0, methods: 4, attributes: 3 Constant pool: { public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo(); @@ -1937,10 +1973,28 @@ Constant pool: Start Length Slot Name Signature 0 4 0 a I 0 4 1 b I + + public static com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester newConstructorTester(int); + descriptor: (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=1, args_size=1 + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + x: dup + x: iload_0 + x: iconst_1 + x: iadd + x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester."<init>":(I)V + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 11 0 i I } SourceFile: "TinyFrameworkMethodCallReplace.java" NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace InnerClasses: + public static #x= #x of #x; // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.class Compiled from "TinyFrameworkMethodCallReplace.java" @@ -1950,7 +2004,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 5, attributes: 5 + interfaces: 0, fields: 0, methods: 6, attributes: 5 Constant pool: { public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace(); @@ -2008,6 +2062,21 @@ Constant pool: x: ireturn LineNumberTable: + public static com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester constructorReplaceTester(int); + descriptor: (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + x: dup + x: iload_0 + x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester."<init>":(I)V + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 9 0 i I + private static int originalAdd(int, int); descriptor: (II)I flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -2046,6 +2115,7 @@ RuntimeInvisibleAnnotations: android.hosttest.annotation.HostSideTestWholeClassKeep NestMembers: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo + com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester BootstrapMethods: x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; Method arguments: @@ -2053,8 +2123,9 @@ BootstrapMethods: #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.lambda$nonStaticMethodCallReplaceTester$0:(Ljava/util/concurrent/atomic/AtomicBoolean;)V #x ()V InnerClasses: + public static #x= #x of #x; // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace - public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles + public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class Compiled from "TinyFrameworkNative.java" public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative @@ -3219,7 +3290,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClas flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 2, attributes: 2 + interfaces: 0, fields: 0, methods: 3, attributes: 2 Constant pool: { public com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller(); @@ -3250,6 +3321,22 @@ Constant pool: LocalVariableTable: Start Length Slot Name Signature 0 12 0 value I + + public static int bar(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=2, locals=1, args_size=1 + x: iload_0 + x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getArray:(I)[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + x: iconst_0 + x: aaload + x: invokevirtual #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getValue:()I + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 10 0 value I } SourceFile: "TinyFrameworkRenamedClassCaller.java" RuntimeInvisibleAnnotations: @@ -3263,7 +3350,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed super_class: #x // java/lang/Object - interfaces: 0, fields: 1, methods: 2, attributes: 2 + interfaces: 0, fields: 1, methods: 3, attributes: 2 Constant pool: { private final int mValue; @@ -3299,6 +3386,26 @@ Constant pool: LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + + public static com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed[] getArray(int); + descriptor: (I)[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=6, locals=1, args_size=1 + x: iconst_1 + x: anewarray #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: dup + x: iconst_0 + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: dup + x: iload_0 + x: invokespecial #x // Method "<init>":(I)V + x: aastore + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 16 0 value I } SourceFile: "TinyFrameworkToBeRenamed.java" RuntimeInvisibleAnnotations: diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-dump.txt index 2e0b1820a696..6a8e4885d1d0 100644 --- a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-dump.txt +++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-dump.txt @@ -2002,6 +2002,51 @@ BootstrapMethods: #x ()Ljava/lang/Integer; NestMembers: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester.class + Compiled from "TinyFrameworkMethodCallReplace.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 1, attributes: 4 +Constant pool: +{ + public int i; + descriptor: I + flags: (0x0001) ACC_PUBLIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester(int); + descriptor: (I)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=2, locals=2, args_size=2 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: aload_0 + x: iload_1 + x: putfield #x // Field i:I + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + 0 10 1 i I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep +} +InnerClasses: + public static #x= #x of #x; // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace +SourceFile: "TinyFrameworkMethodCallReplace.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class Compiled from "TinyFrameworkMethodCallReplace.java" public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo @@ -2010,7 +2055,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 3, attributes: 4 + interfaces: 0, fields: 0, methods: 4, attributes: 4 Constant pool: { public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo(); @@ -2065,9 +2110,30 @@ Constant pool: RuntimeVisibleAnnotations: x: #x() com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + public static com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester newConstructorTester(int); + descriptor: (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=1, args_size=1 + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + x: dup + x: iload_0 + x: iconst_1 + x: iadd + x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester."<init>":(I)V + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 11 0 i I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep } InnerClasses: - public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace + public static #x= #x of #x; // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace + public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace SourceFile: "TinyFrameworkMethodCallReplace.java" RuntimeVisibleAnnotations: x: #x() @@ -2081,7 +2147,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 4, attributes: 6 + interfaces: 0, fields: 0, methods: 6, attributes: 6 Constant pool: { public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace(); @@ -2148,6 +2214,48 @@ Constant pool: x: #x() com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + public static com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester constructorReplaceTester(int); + descriptor: (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + x: dup + x: iload_0 + x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.newConstructorTester:(I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + x: swap + x: pop + x: swap + x: pop + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 13 0 i I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + private static int originalAdd(int, int); + descriptor: (II)I + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=2, args_size=2 + x: iload_0 + x: iload_1 + x: iadd + x: iconst_1 + x: isub + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 6 0 a I + 0 6 1 b I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + private static void lambda$nonStaticMethodCallReplaceTester$0(java.util.concurrent.atomic.AtomicBoolean); descriptor: (Ljava/util/concurrent/atomic/AtomicBoolean;)V flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC @@ -2167,6 +2275,7 @@ Constant pool: com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep } InnerClasses: + public static #x= #x of #x; // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles SourceFile: "TinyFrameworkMethodCallReplace.java" @@ -2184,6 +2293,7 @@ BootstrapMethods: #x ()V NestMembers: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo + com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class Compiled from "TinyFrameworkNative.java" public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative @@ -3422,7 +3532,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClas flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 2, attributes: 3 + interfaces: 0, fields: 0, methods: 3, attributes: 3 Constant pool: { public com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClassCaller(); @@ -3459,6 +3569,25 @@ Constant pool: RuntimeVisibleAnnotations: x: #x() com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + public static int bar(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=2, locals=1, args_size=1 + x: iload_0 + x: invokestatic #x // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getArray:(I)[Lrename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + x: iconst_0 + x: aaload + x: invokevirtual #x // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getValue:()I + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 10 0 value I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep } SourceFile: "TinyFrameworkRenamedClassCaller.java" RuntimeVisibleAnnotations: @@ -3897,7 +4026,7 @@ public class rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFramew flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed super_class: #x // java/lang/Object - interfaces: 0, fields: 1, methods: 2, attributes: 3 + interfaces: 0, fields: 1, methods: 3, attributes: 3 Constant pool: { private final int mValue; @@ -3921,7 +4050,7 @@ Constant pool: LineNumberTable: LocalVariableTable: Start Length Slot Name Signature - 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + 0 10 0 this Lrename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; 0 10 1 value I RuntimeVisibleAnnotations: x: #x() @@ -3938,7 +4067,30 @@ Constant pool: LineNumberTable: LocalVariableTable: Start Length Slot Name Signature - 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + 0 5 0 this Lrename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + public static rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed[] getArray(int); + descriptor: (I)[Lrename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=6, locals=1, args_size=1 + x: iconst_1 + x: anewarray #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: dup + x: iconst_0 + x: new #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: dup + x: iload_0 + x: invokespecial #x // Method "<init>":(I)V + x: aastore + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 16 0 value I RuntimeVisibleAnnotations: x: #x() com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt index 51f79258d53a..d8e76321b038 100644 --- a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt +++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt @@ -2413,6 +2413,66 @@ BootstrapMethods: #x ()Ljava/lang/Integer; NestMembers: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested +## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester.class + Compiled from "TinyFrameworkMethodCallReplace.java" +public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 4 +Constant pool: +{ + public int i; + descriptor: I + flags: (0x0001) ACC_PUBLIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester(int); + descriptor: (I)V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + x: ldc #x // String <init> + x: ldc #x // String (I)V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: aload_0 + x: iload_1 + x: putfield #x // Field i:I + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + 11 10 1 i I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep +} +InnerClasses: + public static #x= #x of #x; // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace +SourceFile: "TinyFrameworkMethodCallReplace.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep +NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class Compiled from "TinyFrameworkMethodCallReplace.java" public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo @@ -2421,7 +2481,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 4, attributes: 4 + interfaces: 0, fields: 0, methods: 5, attributes: 4 Constant pool: { private static {}; @@ -2501,8 +2561,34 @@ Constant pool: RuntimeVisibleAnnotations: x: #x() com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + public static com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester newConstructorTester(int); + descriptor: (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo + x: ldc #x // String newConstructorTester + x: ldc #x // String (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + x: dup + x: iload_0 + x: iconst_1 + x: iadd + x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester."<init>":(I)V + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 11 0 i I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep } InnerClasses: + public static #x= #x of #x; // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace SourceFile: "TinyFrameworkMethodCallReplace.java" RuntimeVisibleAnnotations: @@ -2517,7 +2603,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 5, attributes: 6 + interfaces: 0, fields: 0, methods: 7, attributes: 6 Constant pool: { private static {}; @@ -2609,18 +2695,70 @@ Constant pool: x: #x() com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + public static com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester constructorReplaceTester(int); + descriptor: (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace + x: ldc #x // String constructorReplaceTester + x: ldc #x // String (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester + x: dup + x: iload_0 + x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.newConstructorTester:(I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester; + x: swap + x: pop + x: swap + x: pop + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 13 0 i I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + private static int originalAdd(int, int); + descriptor: (II)I + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace + x: ldc #x // String originalAdd + x: ldc #x // String (II)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: iload_0 + x: iload_1 + x: iadd + x: iconst_1 + x: isub + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 6 0 a I + 11 6 1 b I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + private static void lambda$nonStaticMethodCallReplaceTester$0(java.util.concurrent.atomic.AtomicBoolean); descriptor: (Ljava/util/concurrent/atomic/AtomicBoolean;)V flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC Code: stack=4, locals=1, args_size=1 x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace - x: ldc #x // String lambda$nonStaticMethodCallReplaceTester$0 - x: ldc #x // String (Ljava/util/concurrent/atomic/AtomicBoolean;)V + x: ldc #x // String lambda$nonStaticMethodCallReplaceTester$0 + x: ldc #x // String (Ljava/util/concurrent/atomic/AtomicBoolean;)V x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V x: aload_0 - x: invokestatic #x // Method java/lang/Thread.currentThread:()Ljava/lang/Thread; + x: invokestatic #x // Method java/lang/Thread.currentThread:()Ljava/lang/Thread; x: invokevirtual #x // Method java/lang/Thread.isDaemon:()Z x: invokevirtual #x // Method java/util/concurrent/atomic/AtomicBoolean.set:(Z)V x: return @@ -2633,6 +2771,7 @@ Constant pool: com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep } InnerClasses: + public static #x= #x of #x; // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace public static #x= #x of #x; // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace public static final #x= #x of #x; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles SourceFile: "TinyFrameworkMethodCallReplace.java" @@ -2650,6 +2789,7 @@ BootstrapMethods: #x ()V NestMembers: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo + com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class Compiled from "TinyFrameworkNative.java" public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative @@ -4271,7 +4411,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClas flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller super_class: #x // java/lang/Object - interfaces: 0, fields: 0, methods: 3, attributes: 3 + interfaces: 0, fields: 0, methods: 4, attributes: 3 Constant pool: { private static {}; @@ -4328,6 +4468,30 @@ Constant pool: RuntimeVisibleAnnotations: x: #x() com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + public static int bar(int); + descriptor: (I)I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller + x: ldc #x // String bar + x: ldc #x // String (I)I + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: iload_0 + x: invokestatic #x // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getArray:(I)[Lrename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + x: iconst_0 + x: aaload + x: invokevirtual #x // Method rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.getValue:()I + x: ireturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 10 0 value I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep } SourceFile: "TinyFrameworkRenamedClassCaller.java" RuntimeVisibleAnnotations: @@ -4977,7 +5141,7 @@ public class rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFramew flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed super_class: #x // java/lang/Object - interfaces: 0, fields: 1, methods: 3, attributes: 3 + interfaces: 0, fields: 1, methods: 4, attributes: 3 Constant pool: { private final int mValue; @@ -4992,8 +5156,8 @@ Constant pool: flags: (0x000a) ACC_PRIVATE, ACC_STATIC Code: stack=2, locals=0, args_size=0 - x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: ldc #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V x: return @@ -5002,7 +5166,7 @@ Constant pool: flags: (0x0001) ACC_PUBLIC Code: stack=4, locals=2, args_size=2 - x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: ldc #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed x: ldc #x // String <init> x: ldc #x // String (I)V x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall @@ -5016,7 +5180,7 @@ Constant pool: LineNumberTable: LocalVariableTable: Start Length Slot Name Signature - 11 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + 11 10 0 this Lrename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; 11 10 1 value I RuntimeVisibleAnnotations: x: #x() @@ -5027,7 +5191,7 @@ Constant pool: flags: (0x0001) ACC_PUBLIC Code: stack=4, locals=1, args_size=1 - x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: ldc #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed x: ldc #x // String getValue x: ldc #x // String ()I x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall @@ -5038,7 +5202,35 @@ Constant pool: LineNumberTable: LocalVariableTable: Start Length Slot Name Signature - 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + 11 5 0 this Lrename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep + + public static rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFrameworkToBeRenamed[] getArray(int); + descriptor: (I)[Lrename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=6, locals=1, args_size=1 + x: ldc #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: ldc #x // String getArray + x: ldc #x // String (I)[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed; + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: iconst_1 + x: anewarray #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: dup + x: iconst_0 + x: new #x // class rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed + x: dup + x: iload_0 + x: invokespecial #x // Method "<init>":(I)V + x: aastore + x: areturn + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 16 0 value I RuntimeVisibleAnnotations: x: #x() com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt index 1f64a3c78c53..cbaad2e85717 100644 --- a/ravenwood/tools/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt +++ b/ravenwood/tools/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt @@ -68,6 +68,10 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace class java.lang.Thread keep method start ()V @com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo.startThread +# Used to test constructor replacement. +class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester keepclass + method <init> (I)V @com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo.newConstructorTester + # "rename" takes a type internal name, so '/'s is used as a separator. # The leading / in the prefix is not needed (it'll be stripped), but it's added to make diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.java index 57c69a336654..d850be82719f 100644 --- a/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.java +++ b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.java @@ -41,10 +41,23 @@ public class TinyFrameworkMethodCallReplace { return originalAdd(1, 2); } + public static ConstructorTester constructorReplaceTester(int i) { + // This object construction will be replaced with ReplaceTo.newConstructorTester(). + return new ConstructorTester(i); + } + private static int originalAdd(int a, int b) { return a + b - 1; // Original is broken. } + public static class ConstructorTester { + public int i; + + public ConstructorTester(int i) { + this.i = i; + } + } + public static class ReplaceTo { public static void startThread(Thread thread) { thread.setDaemon(true); @@ -54,5 +67,9 @@ public class TinyFrameworkMethodCallReplace { public static int add(int a, int b) { return a + b; } + + public static ConstructorTester newConstructorTester(int i) { + return new ConstructorTester(i + 1); + } } } diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.java index 707bc0ebb4db..74e4610187c4 100644 --- a/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.java +++ b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller.java @@ -25,4 +25,9 @@ public class TinyFrameworkRenamedClassCaller { // so this code should work as-is. return new TinyFrameworkToBeRenamed(value).getValue(); } + + /** Calls the class that'll be renamed. */ + public static int bar(int value) { + return TinyFrameworkToBeRenamed.getArray(value)[0].getValue(); + } } diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.java index 8319ced6109a..7dcc83e79e26 100644 --- a/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.java +++ b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed.java @@ -31,4 +31,8 @@ public class TinyFrameworkToBeRenamed { public int getValue() { return mValue; } + + public static TinyFrameworkToBeRenamed[] getArray(int value) { + return new TinyFrameworkToBeRenamed[] { new TinyFrameworkToBeRenamed(value) }; + } } diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java index 68673dc2a5b8..89fcd30b3df5 100644 --- a/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java +++ b/ravenwood/tools/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java @@ -308,6 +308,11 @@ public class TinyFrameworkClassTest { } @Test + public void testTypeRenameArray() { + assertThat(TinyFrameworkRenamedClassCaller.bar(2)).isEqualTo(2); + } + + @Test public void testMethodCallReplaceNonStatic() throws Exception { assertThat(TinyFrameworkMethodCallReplace.nonStaticMethodCallReplaceTester()) .isEqualTo(true); @@ -318,4 +323,10 @@ public class TinyFrameworkClassTest { assertThat(TinyFrameworkMethodCallReplace.staticMethodCallReplaceTester()) .isEqualTo(3); } + + @Test + public void testConstructorCallReplace() throws Exception { + assertThat(TinyFrameworkMethodCallReplace.constructorReplaceTester(5).i) + .isEqualTo(6); + } } diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt index b6089eaff1ed..a7f481a02533 100644 --- a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt +++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt @@ -449,7 +449,6 @@ private class TextPolicyToAnnotationConverter( methodName: String, methodDesc: String, replaceSpec: TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec, - policy: FilterPolicyWithReason ) { // This can't be converted to an annotation. classHasMember = true diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java index bb3c710b0c23..0f6f86b39458 100644 --- a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java +++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java @@ -103,12 +103,16 @@ public class AutoclickController extends BaseEventStreamTransformation { @Override public void toggleAutoclickPause(boolean paused) { if (paused) { - if (mClickScheduler != null) { - mClickScheduler.cancel(); - } - if (mAutoclickIndicatorScheduler != null) { - mAutoclickIndicatorScheduler.cancel(); - } + cancelPendingClick(); + } + } + + @Override + public void onHoverChange(boolean hovered) { + // Cancel all pending clicks when the mouse moves outside the panel while + // autoclick is still paused. + if (!hovered && isPaused()) { + cancelPendingClick(); } } }; @@ -226,8 +230,17 @@ public class AutoclickController extends BaseEventStreamTransformation { } private boolean isPaused() { - // TODO (b/397460424): Unpause when hovering over panel. - return Flags.enableAutoclickIndicator() && mAutoclickTypePanel.isPaused(); + return Flags.enableAutoclickIndicator() && mAutoclickTypePanel.isPaused() + && !mAutoclickTypePanel.isHovered(); + } + + private void cancelPendingClick() { + if (mClickScheduler != null) { + mClickScheduler.cancel(); + } + if (mAutoclickIndicatorScheduler != null) { + mAutoclickIndicatorScheduler.cancel(); + } } @VisibleForTesting diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickLinearLayout.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickLinearLayout.java new file mode 100644 index 000000000000..fe8adf75704d --- /dev/null +++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickLinearLayout.java @@ -0,0 +1,80 @@ +/* + * Copyright 2025 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.accessibility.autoclick; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.widget.LinearLayout; + +/** + * A custom LinearLayout that provides enhanced hover event handling. + * This class overrides hover methods to track hover events for the entire panel ViewGroup, + * including the descendant buttons. This allows for consistent hover behavior and feedback + * across the entire layout. + */ +public class AutoclickLinearLayout extends LinearLayout { + public interface OnHoverChangedListener { + /** + * Called when the hover state of the AutoclickLinearLayout changes. + * + * @param hovered {@code true} if the view is now hovered, {@code false} otherwise. + */ + void onHoverChanged(boolean hovered); + } + + private OnHoverChangedListener mListener; + + public AutoclickLinearLayout(Context context) { + super(context); + } + + public AutoclickLinearLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public AutoclickLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public AutoclickLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + public void setOnHoverChangedListener(OnHoverChangedListener listener) { + mListener = listener; + } + + @Override + public boolean onInterceptHoverEvent(MotionEvent event) { + int action = event.getActionMasked(); + setHovered(action == MotionEvent.ACTION_HOVER_ENTER + || action == MotionEvent.ACTION_HOVER_MOVE); + + return false; + } + + @Override + public void onHoverChanged(boolean hovered) { + super.onHoverChanged(hovered); + + if (mListener != null) { + mListener.onHoverChanged(hovered); + } + } +} diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java index ab4b3b13eece..57bbb4a7a0a7 100644 --- a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java +++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java @@ -110,11 +110,18 @@ public class AutoclickTypePanel { * @param paused {@code true} to pause autoclick, {@code false} to resume. */ void toggleAutoclickPause(boolean paused); + + /** + * Called when the hovered state of the panel changes. + * + * @param hovered {@code true} if the panel is now hovered, {@code false} otherwise. + */ + void onHoverChange(boolean hovered); } private final Context mContext; - private final View mContentView; + private final AutoclickLinearLayout mContentView; private final WindowManager mWindowManager; @@ -164,8 +171,9 @@ public class AutoclickTypePanel { R.drawable.accessibility_autoclick_resume); mContentView = - LayoutInflater.from(context) + (AutoclickLinearLayout) LayoutInflater.from(context) .inflate(R.layout.accessibility_autoclick_type_panel, null); + mContentView.setOnHoverChangedListener(mClickPanelController::onHoverChange); mLeftClickButton = mContentView.findViewById(R.id.accessibility_autoclick_left_click_layout); mRightClickButton = @@ -339,6 +347,10 @@ public class AutoclickTypePanel { return mPaused; } + public boolean isHovered() { + return mContentView.isHovered(); + } + /** Toggles the panel expanded or collapsed state. */ private void togglePanelExpansion(@AutoclickType int clickType) { final LinearLayout button = getButtonFromClickType(clickType); @@ -520,7 +532,7 @@ public class AutoclickTypePanel { @VisibleForTesting @NonNull - View getContentViewForTesting() { + AutoclickLinearLayout getContentViewForTesting() { return mContentView; } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 4187ee274f56..5395d2a914ec 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -2625,6 +2625,13 @@ public final class ActiveServices { } notification.flags |= Notification.FLAG_FOREGROUND_SERVICE; r.foregroundNoti = notification; + if (r.isForeground && foregroundServiceType != previousFgsType) { + // An already foreground service is being started with a different fgs type + // which results in the type changing without typical startForeground + // logging. + Slog.w(TAG_SERVICE, "FGS type change for " + r.shortInstanceName + + " from " + previousFgsType + " to " + foregroundServiceType); + } mAm.mProcessStateController.setForegroundServiceType(r, foregroundServiceType); if (!r.isForeground) { final ServiceMap smap = getServiceMapLocked(r.userId); @@ -9191,7 +9198,9 @@ public final class ActiveServices { } else { synchronized (mAm.mPidsSelfLocked) { callerApp = mAm.mPidsSelfLocked.get(callingPid); - caller = callerApp.getThread(); + if (callerApp != null) { + caller = callerApp.getThread(); + } } } if (callerApp == null) { diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index c8b8909f203f..f7d7ed541780 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -3006,7 +3006,7 @@ public class AppOpsService extends IAppOpsService.Stub { UidState uidState = getUidStateLocked(uid, false); if (uidState != null) { int rawUidMode = mAppOpsCheckingService.getUidMode( - uidState.uid, getPersistentId(virtualDeviceId), code); + uidState.uid, getPersistentDeviceIdForOp(virtualDeviceId, code), code); if (rawUidMode != AppOpsManager.opToDefaultMode(code)) { return raw ? rawUidMode : @@ -3069,7 +3069,7 @@ public class AppOpsService extends IAppOpsService.Stub { int switchCode = AppOpsManager.opToSwitch(code); int rawUidMode = mAppOpsCheckingService.getUidMode(uid, - getPersistentId(virtualDeviceId), switchCode); + getPersistentDeviceIdForOp(virtualDeviceId, switchCode), switchCode); if (rawUidMode != AppOpsManager.opToDefaultMode(switchCode)) { return raw ? rawUidMode : evaluateForegroundMode(uid, switchCode, rawUidMode); @@ -3396,7 +3396,7 @@ public class AppOpsService extends IAppOpsService.Stub { } final Op op = getOpLocked(ops, code, uid, true); final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag, - getPersistentId(virtualDeviceId)); + getPersistentDeviceIdForOp(virtualDeviceId, code)); if (attributedOp.isRunning()) { Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName + " code " + code + " startTime of in progress event=" @@ -3418,15 +3418,15 @@ public class AppOpsService extends IAppOpsService.Stub { // If there is a non-default per UID policy (we set UID op mode only if // non-default) it takes over, otherwise use the per package policy. - } else if (mAppOpsCheckingService.getUidMode( - uidState.uid, getPersistentId(virtualDeviceId), switchCode) + } else if (mAppOpsCheckingService.getUidMode(uidState.uid, + getPersistentDeviceIdForOp(virtualDeviceId, switchCode), switchCode) != AppOpsManager.opToDefaultMode(switchCode)) { final int uidMode = uidState.evalMode( code, mAppOpsCheckingService.getUidMode( uidState.uid, - getPersistentId(virtualDeviceId), + getPersistentDeviceIdForOp(virtualDeviceId, switchCode), switchCode)); if (uidMode != AppOpsManager.MODE_ALLOWED) { if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code " @@ -3478,7 +3478,8 @@ public class AppOpsService extends IAppOpsService.Stub { virtualDeviceId, flags, AppOpsManager.MODE_ALLOWED); attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag, - getPersistentId(proxyVirtualDeviceId), uidState.getState(), flags, notedCount); + getPersistentDeviceIdForOp(proxyVirtualDeviceId, code), uidState.getState(), + flags, notedCount); if (shouldCollectAsyncNotedOp) { collectAsyncNotedOp(uid, packageName, code, attributionTag, flags, message, @@ -4045,7 +4046,7 @@ public class AppOpsService extends IAppOpsService.Stub { } final Op op = getOpLocked(ops, code, uid, true); final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag, - getPersistentId(virtualDeviceId)); + getPersistentDeviceIdForOp(virtualDeviceId, code)); final UidState uidState = ops.uidState; isRestricted = isOpRestrictedLocked(uid, code, packageName, attributionTag, virtualDeviceId, pvr.bypass, false); @@ -4058,8 +4059,9 @@ public class AppOpsService extends IAppOpsService.Stub { // If there is a non-default per UID policy (we set UID op mode only if // non-default) it takes over, otherwise use the per package policy. } else if ((rawUidMode = - mAppOpsCheckingService.getUidMode( - uidState.uid, getPersistentId(virtualDeviceId), switchCode)) + mAppOpsCheckingService.getUidMode( + uidState.uid, getPersistentDeviceIdForOp(virtualDeviceId, switchCode), + switchCode)) != AppOpsManager.opToDefaultMode(switchCode)) { final int uidMode = uidState.evalMode(code, rawUidMode); if (!shouldStartForMode(uidMode, startIfModeDefault)) { @@ -4107,11 +4109,13 @@ public class AppOpsService extends IAppOpsService.Stub { try { if (isRestricted) { attributedOp.createPaused(clientId, virtualDeviceId, proxyUid, proxyPackageName, - proxyAttributionTag, getPersistentId(proxyVirtualDeviceId), + proxyAttributionTag, + getPersistentDeviceIdForOp(proxyVirtualDeviceId, code), uidState.getState(), flags, attributionFlags, attributionChainId); } else { attributedOp.started(clientId, virtualDeviceId, proxyUid, proxyPackageName, - proxyAttributionTag, getPersistentId(proxyVirtualDeviceId), + proxyAttributionTag, + getPersistentDeviceIdForOp(proxyVirtualDeviceId, code), uidState.getState(), flags, attributionFlags, attributionChainId); startType = START_TYPE_STARTED; } @@ -4179,15 +4183,15 @@ public class AppOpsService extends IAppOpsService.Stub { final int switchCode = AppOpsManager.opToSwitch(code); // If there is a non-default mode per UID policy (we set UID op mode only if // non-default) it takes over, otherwise use the per package policy. - if (mAppOpsCheckingService.getUidMode( - uidState.uid, getPersistentId(virtualDeviceId), switchCode) + if (mAppOpsCheckingService.getUidMode(uidState.uid, + getPersistentDeviceIdForOp(virtualDeviceId, switchCode), switchCode) != AppOpsManager.opToDefaultMode(switchCode)) { final int uidMode = uidState.evalMode( code, mAppOpsCheckingService.getUidMode( uidState.uid, - getPersistentId(virtualDeviceId), + getPersistentDeviceIdForOp(virtualDeviceId, switchCode), switchCode)); if (!shouldStartForMode(uidMode, startIfModeDefault)) { if (DEBUG) { @@ -4350,7 +4354,8 @@ public class AppOpsService extends IAppOpsService.Stub { return; } final AttributedOp attributedOp = - op.mDeviceAttributedOps.getOrDefault(getPersistentId(virtualDeviceId), + op.mDeviceAttributedOps.getOrDefault( + getPersistentDeviceIdForOp(virtualDeviceId, code), new ArrayMap<>()).get(attributionTag); if (attributedOp == null) { Slog.e(TAG, "Attribution not found: uid=" + uid + " pkg=" + packageName + "(" @@ -4641,7 +4646,8 @@ public class AppOpsService extends IAppOpsService.Stub { return true; } if (mVirtualDeviceManagerInternal == null) { - return true; + Slog.w(TAG, "VirtualDeviceManagerInternal is null when device Id is non-default"); + return false; } if (mVirtualDeviceManagerInternal.isValidVirtualDeviceId(virtualDeviceId)) { mKnownDeviceIds.put(virtualDeviceId, @@ -7310,7 +7316,13 @@ public class AppOpsService extends IAppOpsService.Stub { return packageNames; } - @NonNull private String getPersistentId(int virtualDeviceId) { + // For ops associated with device aware permissions, if virtual device id is non-default, we + // will return string version of that id provided the virtual device has corresponding camera or + // audio policy. + @NonNull private String getPersistentDeviceIdForOp(int virtualDeviceId, int op) { + virtualDeviceId = PermissionManager.resolveDeviceIdForPermissionCheck(mContext, + virtualDeviceId, AppOpsManager.opToPermission(op)); + if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) { return PERSISTENT_DEVICE_ID_DEFAULT; } @@ -7319,6 +7331,7 @@ public class AppOpsService extends IAppOpsService.Stub { } String persistentId = mVirtualDeviceManagerInternal.getPersistentIdForDevice(virtualDeviceId); + if (persistentId == null) { persistentId = mKnownDeviceIds.get(virtualDeviceId); } diff --git a/services/core/java/com/android/server/appop/DiscreteOpsRegistry.java b/services/core/java/com/android/server/appop/DiscreteOpsRegistry.java index 84402c85471f..12c35ae92cbe 100644 --- a/services/core/java/com/android/server/appop/DiscreteOpsRegistry.java +++ b/services/core/java/com/android/server/appop/DiscreteOpsRegistry.java @@ -177,6 +177,8 @@ abstract class DiscreteOpsRegistry { */ abstract void writeAndClearOldAccessHistory(); + void shutdown() {} + /** Remove all discrete op events. */ abstract void clearHistory(); diff --git a/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java b/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java index 604cb30294a9..dc11be9aadb6 100644 --- a/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java +++ b/services/core/java/com/android/server/appop/DiscreteOpsSqlRegistry.java @@ -57,13 +57,18 @@ import java.util.Set; public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry { private static final String TAG = "DiscreteOpsSqlRegistry"; + private static final long DB_WRITE_INTERVAL = Duration.ofMinutes(10).toMillis(); + private static final long EXPIRED_ENTRY_DELETION_INTERVAL = Duration.ofHours(6).toMillis(); + + // Event type handled by SqliteWriteHandler + private static final int WRITE_DATABASE_RECURRING = 1; + private static final int DELETE_EXPIRED_ENTRIES = 2; + private static final int WRITE_DATABASE_CACHE_FULL = 3; + private final Context mContext; private final DiscreteOpsDbHelper mDiscreteOpsDbHelper; private final SqliteWriteHandler mSqliteWriteHandler; private final DiscreteOpCache mDiscreteOpCache = new DiscreteOpCache(512); - private static final long THREE_HOURS = Duration.ofHours(3).toMillis(); - private static final int WRITE_CACHE_EVICTED_OP_EVENTS = 1; - private static final int DELETE_OLD_OP_EVENTS = 2; // Attribution chain id is used to identify an attribution source chain, This is // set for startOp only. PermissionManagerService resets this ID on device restart, so // we use previously persisted chain id as offset, and add it to chain id received from @@ -83,6 +88,9 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry { mSqliteWriteHandler = new SqliteWriteHandler(thread.getLooper()); mDiscreteOpsDbHelper = new DiscreteOpsDbHelper(context, databaseFile); mChainIdOffset = mDiscreteOpsDbHelper.getLargestAttributionChainId(); + mSqliteWriteHandler.sendEmptyMessageDelayed(WRITE_DATABASE_RECURRING, DB_WRITE_INTERVAL); + mSqliteWriteHandler.sendEmptyMessageDelayed(DELETE_EXPIRED_ENTRIES, + EXPIRED_ENTRY_DELETION_INTERVAL); } @Override @@ -117,15 +125,14 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry { } @Override - void writeAndClearOldAccessHistory() { - // Let the sql impl also follow the same disk write frequencies as xml, - // controlled by AppOpsService. + void shutdown() { + mSqliteWriteHandler.removeAllPendingMessages(); mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.getAllEventsAndClear()); - if (!mSqliteWriteHandler.hasMessages(DELETE_OLD_OP_EVENTS)) { - if (mSqliteWriteHandler.sendEmptyMessageDelayed(DELETE_OLD_OP_EVENTS, THREE_HOURS)) { - Slog.w(TAG, "DELETE_OLD_OP_EVENTS is not queued"); - } - } + } + + @Override + void writeAndClearOldAccessHistory() { + // no-op } @Override @@ -175,7 +182,7 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry { @Nullable String attributionTagFilter, int opFlagsFilter, Set<String> attributionExemptPkgs) { // flush the cache into database before read. - writeAndClearOldAccessHistory(); + mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.getAllEventsAndClear()); boolean assembleChains = attributionExemptPkgs != null; IntArray opCodes = getAppOpCodes(filter, opNamesFilter); beginTimeMillis = Math.max(beginTimeMillis, Instant.now().minus(sDiscreteHistoryCutoff, @@ -363,20 +370,59 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry { @Override public void handleMessage(Message msg) { switch (msg.what) { - case WRITE_CACHE_EVICTED_OP_EVENTS: - List<DiscreteOp> opEvents = (List<DiscreteOp>) msg.obj; - mDiscreteOpsDbHelper.insertDiscreteOps(opEvents); - break; - case DELETE_OLD_OP_EVENTS: + case WRITE_DATABASE_RECURRING -> { + try { + List<DiscreteOp> evictedEvents; + synchronized (mDiscreteOpCache) { + evictedEvents = mDiscreteOpCache.evict(); + } + mDiscreteOpsDbHelper.insertDiscreteOps(evictedEvents); + } finally { + mSqliteWriteHandler.sendEmptyMessageDelayed(WRITE_DATABASE_RECURRING, + DB_WRITE_INTERVAL); + // Schedule a cleanup to truncate older (before cutoff time) entries. + if (!mSqliteWriteHandler.hasMessages(DELETE_EXPIRED_ENTRIES)) { + mSqliteWriteHandler.sendEmptyMessageDelayed(DELETE_EXPIRED_ENTRIES, + EXPIRED_ENTRY_DELETION_INTERVAL); + } + } + } + case DELETE_EXPIRED_ENTRIES -> { long cutOffTimeStamp = System.currentTimeMillis() - sDiscreteHistoryCutoff; mDiscreteOpsDbHelper.execSQL( DiscreteOpsTable.DELETE_TABLE_DATA_BEFORE_ACCESS_TIME, new Object[]{cutOffTimeStamp}); - break; - default: - throw new IllegalStateException("Unexpected value: " + msg.what); + } + case WRITE_DATABASE_CACHE_FULL -> { + try { + List<DiscreteOp> evictedEvents; + synchronized (mDiscreteOpCache) { + evictedEvents = mDiscreteOpCache.evict(); + // if nothing to evict, just write the whole cache to database. + if (evictedEvents.isEmpty() + && mDiscreteOpCache.size() >= mDiscreteOpCache.capacity()) { + evictedEvents.addAll(mDiscreteOpCache.mCache); + mDiscreteOpCache.clear(); + } + } + mDiscreteOpsDbHelper.insertDiscreteOps(evictedEvents); + } finally { + // Just in case initial message is not scheduled. + if (!mSqliteWriteHandler.hasMessages(WRITE_DATABASE_RECURRING)) { + mSqliteWriteHandler.sendEmptyMessageDelayed(WRITE_DATABASE_RECURRING, + DB_WRITE_INTERVAL); + } + } + } + default -> throw new IllegalStateException("Unexpected value: " + msg.what); } } + + void removeAllPendingMessages() { + removeMessages(WRITE_DATABASE_RECURRING); + removeMessages(DELETE_EXPIRED_ENTRIES); + removeMessages(WRITE_DATABASE_CACHE_FULL); + } } /** @@ -390,6 +436,7 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry { * 4) During shutdown. */ class DiscreteOpCache { + private static final String TAG = "DiscreteOpCache"; private final int mCapacity; private final ArraySet<DiscreteOp> mCache; @@ -404,23 +451,9 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry { return; } mCache.add(opEvent); + if (mCache.size() >= mCapacity) { - if (DEBUG_LOG) { - Slog.i(TAG, "Current discrete ops cache size: " + mCache.size()); - } - List<DiscreteOp> evictedEvents = evict(); - if (DEBUG_LOG) { - Slog.i(TAG, "Evicted discrete ops size: " + evictedEvents.size()); - } - // if nothing to evict, just write the whole cache to disk - if (evictedEvents.isEmpty()) { - Slog.w(TAG, "No discrete ops event is evicted, write cache to db."); - evictedEvents.addAll(mCache); - mCache.clear(); - } - Message msg = mSqliteWriteHandler.obtainMessage( - WRITE_CACHE_EVICTED_OP_EVENTS, evictedEvents); - mSqliteWriteHandler.sendMessage(msg); + mSqliteWriteHandler.sendEmptyMessage(WRITE_DATABASE_CACHE_FULL); } } } @@ -461,6 +494,14 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry { } } + int size() { + return mCache.size(); + } + + int capacity() { + return mCapacity; + } + /** * Remove all entries from the cache. */ diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java index 928a4b270b59..d267e0d9e536 100644 --- a/services/core/java/com/android/server/appop/HistoricalRegistry.java +++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java @@ -750,6 +750,7 @@ final class HistoricalRegistry { } // Do not call persistPendingHistory inside the memory lock, due to possible deadlock persistPendingHistory(); + mDiscreteRegistry.shutdown(); } void persistPendingHistory() { diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 964b97c7bbfd..551202c20cbb 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -1051,7 +1051,9 @@ final class LocalDisplayAdapter extends DisplayAdapter { void handleHdrSdrNitsChanged(float displayNits, float sdrNits) { final float newHdrSdrRatio; - if (displayNits != INVALID_NITS && sdrNits != INVALID_NITS) { + if (displayNits != INVALID_NITS && sdrNits != INVALID_NITS + && (mBacklightAdapter.mUseSurfaceControlBrightness || + mBacklightAdapter.mForceSurfaceControl)) { // Ensure the ratio stays >= 1.0f as values below that are nonsensical newHdrSdrRatio = Math.max(1.f, displayNits / sdrNits); } else { diff --git a/services/core/java/com/android/server/display/mode/ModeChangeObserver.java b/services/core/java/com/android/server/display/mode/ModeChangeObserver.java index bbc13cc6ae7e..2751835f9958 100644 --- a/services/core/java/com/android/server/display/mode/ModeChangeObserver.java +++ b/services/core/java/com/android/server/display/mode/ModeChangeObserver.java @@ -23,8 +23,6 @@ import android.view.Display; import android.view.DisplayAddress; import android.view.DisplayEventReceiver; -import com.android.internal.annotations.KeepForWeakReference; - import java.util.HashSet; import java.util.Set; @@ -35,7 +33,6 @@ final class ModeChangeObserver { private final DisplayModeDirector.Injector mInjector; @SuppressWarnings("unused") - @KeepForWeakReference private DisplayEventReceiver mModeChangeListener; private final SparseArray<Set<Integer>> mRejectedModesByDisplay = new SparseArray<>(); private Looper mLooper; diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java index 7e8bb28b6a37..144caea05d00 100644 --- a/services/core/java/com/android/server/dreams/DreamManagerService.java +++ b/services/core/java/com/android/server/dreams/DreamManagerService.java @@ -1365,6 +1365,21 @@ public final class DreamManagerService extends SystemService { } } + @Override + public void setScreensaverEnabled(boolean enabled) { + checkPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS); + final UserHandle userHandle = getCallingUserHandle(); + final long ident = Binder.clearCallingIdentity(); + try { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.SCREENSAVER_ENABLED, enabled ? 1 : 0, + userHandle.getIdentifier()); + mPowerManagerInternal.updateSettings(); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + boolean canLaunchDreamActivity(String dreamPackageName, String packageName, int callingUid) { if (dreamPackageName == null || packageName == null) { diff --git a/services/core/java/com/android/server/input/InputDataStore.java b/services/core/java/com/android/server/input/InputDataStore.java index 834f8154240e..6ed50b6fbdcb 100644 --- a/services/core/java/com/android/server/input/InputDataStore.java +++ b/services/core/java/com/android/server/input/InputDataStore.java @@ -89,6 +89,10 @@ public final class InputDataStore { final InputStream inputStream = mInputGestureFileInjector.openRead(userId); inputGestureDataList = readInputGesturesXml(inputStream, false); inputStream.close(); + } catch (FileNotFoundException exception) { + // There are valid reasons for the file to be missing, such as shortcuts having not + // been registered by the user. + return List.of(); } catch (IOException exception) { // In case we are unable to read from the file on disk or another IO operation error, // fail gracefully. diff --git a/services/core/java/com/android/server/inputmethod/OWNERS b/services/core/java/com/android/server/inputmethod/OWNERS index e507c6ba40a1..9d8aef943fa5 100644 --- a/services/core/java/com/android/server/inputmethod/OWNERS +++ b/services/core/java/com/android/server/inputmethod/OWNERS @@ -1,7 +1,6 @@ set noparent roosa@google.com -yukawa@google.com tarandeep@google.com fstern@google.com cosminbaies@google.com diff --git a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java index 463989adc98f..60d028b46970 100644 --- a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java +++ b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java @@ -390,10 +390,11 @@ public class BackgroundInstallControlService extends SystemService { .max(Comparator.comparingLong(PackageInstaller.SessionInfo::getCreatedMillis)); } - // ADB sets installerPackageName to null, this creates a loophole to bypass BIC which will be - // addressed with b/265203007 private boolean installedByAdb(String initiatingPackageName) { - if(PackageManagerServiceUtils.isInstalledByAdb(initiatingPackageName)) { + // GTS tests needs to adopt shell identity to install apps. + if(!SystemProperties.get("gts.transparency.bg-install-apps").isEmpty()) { + Slog.d(TAG, "handlePackageAdd: is GTS tests, skipping ADB check"); + } else if(PackageManagerServiceUtils.isInstalledByAdb(initiatingPackageName)) { Slog.d(TAG, "handlePackageAdd: is installed by ADB, skipping"); return true; } diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index f96846cdb2f4..acdc79fb9922 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -1067,6 +1067,9 @@ final class InstallPackageHelper { void doPostDexopt(List<ReconciledPackage> reconciledPackages, List<InstallRequest> requests, Map<String, Boolean> createdAppId, MoveInfo moveInfo, long acquireTime) { + for (InstallRequest request : requests) { + request.onWaitDexoptFinished(); + } boolean success = false; try { if (commitInstallPackages(reconciledPackages)) { @@ -1218,6 +1221,7 @@ final class InstallPackageHelper { CompletableFuture<Void> future = DexOptHelper.performDexoptIfNeededAsync(request, mDexManager); completableFutures.add(future); + request.onWaitDexoptStarted(); } if (!completableFutures.isEmpty()) { diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java index fbf5db5d9635..734920435e26 100644 --- a/services/core/java/com/android/server/pm/InstallRequest.java +++ b/services/core/java/com/android/server/pm/InstallRequest.java @@ -1028,6 +1028,18 @@ final class InstallRequest { } } + public void onWaitDexoptStarted() { + if (mPackageMetrics != null) { + mPackageMetrics.onStepStarted(PackageMetrics.STEP_WAIT_DEXOPT); + } + } + + public void onWaitDexoptFinished() { + if (mPackageMetrics != null) { + mPackageMetrics.onStepFinished(PackageMetrics.STEP_WAIT_DEXOPT); + } + } + public void onDexoptFinished(DexoptResult dexoptResult) { // Only report external profile warnings when installing from adb. The goal is to warn app // developers if they have provided bad external profiles, so it's not beneficial to report diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS index 62b89f3252e6..f98ec04f84d8 100644 --- a/services/core/java/com/android/server/pm/OWNERS +++ b/services/core/java/com/android/server/pm/OWNERS @@ -1,7 +1,6 @@ hackbod@android.com hackbod@google.com jsharkey@android.com -jsharkey@google.com narayan@google.com include /PACKAGE_MANAGER_OWNERS diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 136cb1259113..635ef069741b 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -5189,7 +5189,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { "Session " + sessionId + " is a parent of multi-package session and " + "requestUserPreapproval on the parent session isn't supported."); } - + if (statusReceiver == null) { + throw new IllegalArgumentException("Status receiver cannot be null."); + } synchronized (mLock) { assertPreparedAndNotSealedLocked("request of session " + sessionId); mPreapprovalDetails = details; @@ -5542,6 +5544,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { */ private static void sendOnUserActionRequired(Context context, IntentSender target, int sessionId, Intent intent) { + if (target == null) { + Slog.e(TAG, "Missing receiver for pending user action."); + return; + } final Intent fillIn = new Intent(); fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_PENDING_USER_ACTION); diff --git a/services/core/java/com/android/server/pm/PackageMetrics.java b/services/core/java/com/android/server/pm/PackageMetrics.java index 994ee421790c..22da3b2e7636 100644 --- a/services/core/java/com/android/server/pm/PackageMetrics.java +++ b/services/core/java/com/android/server/pm/PackageMetrics.java @@ -73,6 +73,7 @@ final class PackageMetrics { public static final int STEP_DEXOPT = 5; public static final int STEP_FREEZE_INSTALL = 6; public static final int STEP_RESTORE = 7; + public static final int STEP_WAIT_DEXOPT = 8; @IntDef(prefix = {"STEP_"}, value = { STEP_PREPARE, @@ -81,7 +82,8 @@ final class PackageMetrics { STEP_COMMIT, STEP_DEXOPT, STEP_FREEZE_INSTALL, - STEP_RESTORE + STEP_RESTORE, + STEP_WAIT_DEXOPT }) @Retention(RetentionPolicy.SOURCE) public @interface StepInt { diff --git a/services/core/java/com/android/server/pm/dex/OWNERS b/services/core/java/com/android/server/pm/dex/OWNERS index 5ca8ddd1fe17..70af4e7d36b2 100644 --- a/services/core/java/com/android/server/pm/dex/OWNERS +++ b/services/core/java/com/android/server/pm/dex/OWNERS @@ -1,4 +1,3 @@ -alanstokes@google.com jiakaiz@google.com ngeoffray@google.com mast@google.com diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index e3eced252d1f..dd454cd61b2c 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -7445,6 +7445,13 @@ public final class PowerManagerService extends SystemService public void setDevicePostured(boolean isPostured) { setDevicePosturedInternal(isPostured); } + + @Override + public void updateSettings() { + synchronized (mLock) { + updateSettingsLocked(); + } + } } /** diff --git a/services/core/java/com/android/server/power/stats/BatteryHistoryDirectory.java b/services/core/java/com/android/server/power/stats/BatteryHistoryDirectory.java index 29cc9ea13625..5563f98e8842 100644 --- a/services/core/java/com/android/server/power/stats/BatteryHistoryDirectory.java +++ b/services/core/java/com/android/server/power/stats/BatteryHistoryDirectory.java @@ -251,6 +251,10 @@ public class BatteryHistoryDirectory implements BatteryStatsHistory.BatteryHisto try (FileInputStream stream = file.openRead()) { byte[] header = new byte[FILE_FORMAT_BYTES]; if (stream.read(header, 0, FILE_FORMAT_BYTES) == -1) { + if (file.getBaseFile().length() == 0) { + return new byte[0]; + } + Slog.e(TAG, "Invalid battery history file format " + file.getBaseFile()); deleteFragment(fragment); return null; diff --git a/services/core/java/com/android/server/uri/OWNERS b/services/core/java/com/android/server/uri/OWNERS index cdc07ed7c67a..6599db7936c0 100644 --- a/services/core/java/com/android/server/uri/OWNERS +++ b/services/core/java/com/android/server/uri/OWNERS @@ -1,3 +1,2 @@ jsharkey@android.com -jsharkey@google.com varunshah@google.com diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index 12f553426c80..58534b95bdde 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -712,13 +712,17 @@ final class AccessibilityController { if (!isMagnifierActivated) { return; } - // All opening/closing situations. + // All opening/closing/recents transitions + boolean notify = (flags & TRANSIT_FLAG_IS_RECENTS) != 0; switch (type) { case WindowManager.TRANSIT_OPEN: case WindowManager.TRANSIT_TO_FRONT: case WindowManager.TRANSIT_CLOSE: case WindowManager.TRANSIT_TO_BACK: - mUserContextChangedNotifier.onWMTransition(type, flags); + notify = true; + } + if (notify) { + mUserContextChangedNotifier.onWMTransition(type, flags); } } @@ -1088,8 +1092,7 @@ final class AccessibilityController { // causing the notifying, or the recents/home window is removed, then we won't need the // delayed notification anymore. void onWMTransition(@TransitionType int type, @TransitionFlags int flags) { - if (type == WindowManager.TRANSIT_TO_FRONT - && (flags & TRANSIT_FLAG_IS_RECENTS) != 0) { + if ((flags & TRANSIT_FLAG_IS_RECENTS) != 0) { // Delay the recents to front transition notification then send after if needed. mHasDelayedNotificationForRecentsToFrontTransition = true; } else { diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 247264f049d6..bdde5fe9dcb5 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -58,6 +58,7 @@ import static android.os.Process.INVALID_UID; import static android.security.Flags.preventIntentRedirectAbortOrThrowException; import static android.security.Flags.preventIntentRedirectShowToast; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.WindowManager.TRANSIT_FLAG_AVOID_MOVE_TO_FRONT; import static android.view.WindowManager.TRANSIT_NONE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_FRONT; @@ -1841,6 +1842,9 @@ class ActivityStarter { // no-user-leaving implies not entering PiP. transition.setCanPipOnFinish(false /* canPipOnFinish */); } + if (avoidMoveToFront() && transition != null) { + transition.addFlag(TRANSIT_FLAG_AVOID_MOVE_TO_FRONT); + } if (isIndependentLaunch && transition != null) { transitionController.requestStartTransition(transition, mTargetTask == null ? started.getTask() : mTargetTask, diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java index f51e60c101e4..36686fc086f1 100644 --- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java +++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java @@ -312,7 +312,6 @@ public class BackgroundActivityStartController { private final @ActivityManager.ProcessState int mCallingUidProcState; private final boolean mIsCallingUidPersistentSystemProcess; final BackgroundStartPrivileges mBalAllowedByPiSender; - final BackgroundStartPrivileges mBalAllowedByPiCreatorWithHardening; final BackgroundStartPrivileges mBalAllowedByPiCreator; private final String mRealCallingPackage; private final int mRealCallingUid; @@ -379,22 +378,14 @@ public class BackgroundActivityStartController { if (mAutoOptInCaller) { // grant BAL privileges unless explicitly opted out - mBalAllowedByPiCreatorWithHardening = mBalAllowedByPiCreator = + mBalAllowedByPiCreator = callerBackgroundActivityStartMode == MODE_BACKGROUND_ACTIVITY_START_DENIED ? BackgroundStartPrivileges.NONE : BackgroundStartPrivileges.ALLOW_BAL; } else { // for PendingIntents we restrict BAL based on target_sdk - mBalAllowedByPiCreatorWithHardening = getBackgroundStartPrivilegesAllowedByCreator( + mBalAllowedByPiCreator = getBackgroundStartPrivilegesAllowedByCreator( callingUid, callingPackage, checkedOptions); - final BackgroundStartPrivileges mBalAllowedByPiCreatorWithoutHardening = - callerBackgroundActivityStartMode - == MODE_BACKGROUND_ACTIVITY_START_DENIED - ? BackgroundStartPrivileges.NONE - : BackgroundStartPrivileges.ALLOW_BAL; - mBalAllowedByPiCreator = balRequireOptInByPendingIntentCreator() - ? mBalAllowedByPiCreatorWithHardening - : mBalAllowedByPiCreatorWithoutHardening; } if (mAutoOptInReason != null) { @@ -585,9 +576,8 @@ public class BackgroundActivityStartController { if (mCallerApp != null) { sb.append("; inVisibleTask: ").append(mCallerApp.hasActivityInVisibleTask()); } - sb.append("; balAllowedByPiCreator: ").append(mBalAllowedByPiCreator); - sb.append("; balAllowedByPiCreatorWithHardening: ") - .append(mBalAllowedByPiCreatorWithHardening); + sb.append("; balAllowedByPiCreator: ") + .append(mBalAllowedByPiCreator); if (mResultForCaller != null) { sb.append("; resultIfPiCreatorAllowsBal: ") .append(balCodeToString(mResultForCaller.mCode)); @@ -638,14 +628,13 @@ public class BackgroundActivityStartController { } static class BalVerdict { - static final BalVerdict BLOCK = new BalVerdict(BAL_BLOCK, false, "Blocked"); + static final BalVerdict BLOCK = new BalVerdict(BAL_BLOCK, "Blocked"); static final BalVerdict ALLOW_BY_DEFAULT = - new BalVerdict(BAL_ALLOW_DEFAULT, false, "Default"); + new BalVerdict(BAL_ALLOW_DEFAULT, "Default"); // Careful using this - it will bypass all ASM checks. static final BalVerdict ALLOW_PRIVILEGED = - new BalVerdict(BAL_ALLOW_ALLOWLISTED_UID, false, "PRIVILEGED"); + new BalVerdict(BAL_ALLOW_ALLOWLISTED_UID, "PRIVILEGED"); private final @BalCode int mCode; - private final boolean mBackground; private final String mMessage; private String mProcessInfo; // indicates BAL would be blocked because only creator of the PI has the privilege to allow @@ -654,8 +643,7 @@ public class BackgroundActivityStartController { /** indicates that this verdict is based on the real calling UID and not the calling UID */ private boolean mBasedOnRealCaller; - BalVerdict(@BalCode int balCode, boolean background, String message) { - this.mBackground = background; + BalVerdict(@BalCode int balCode, String message) { this.mCode = balCode; this.mMessage = message; } @@ -708,16 +696,7 @@ public class BackgroundActivityStartController { builder.append(" [realCaller]"); } if (DEBUG_ACTIVITY_STARTS) { - builder.append(" ("); - if (mBackground) { - builder.append("Background "); - } - builder.append("Activity start "); - if (mCode == BAL_BLOCK) { - builder.append("denied"); - } else { - builder.append("allowed: ").append(mMessage); - } + builder.append(" (").append(mMessage); if (mProcessInfo != null) { builder.append(" "); builder.append(mProcessInfo); @@ -795,7 +774,6 @@ public class BackgroundActivityStartController { // to realCallingUid when calculating resultForRealCaller below. if (getService().hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) { state.setResultForRealCaller(new BalVerdict(BAL_ALLOW_SDK_SANDBOX, - /*background*/ false, "uid in SDK sandbox has visible (non-toast) window")); return allowBasedOnRealCaller(state); } @@ -1059,8 +1037,7 @@ public class BackgroundActivityStartController { || state.mAppSwitchState == APP_SWITCH_FG_ONLY || isHomeApp(state.mCallingUid, state.mCallingPackage); if (appSwitchAllowedOrFg && state.mCallingUidHasVisibleActivity) { - return new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, - /*background*/ false, "callingUid has visible window"); + return new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "callingUid has visible window"); } return BalVerdict.BLOCK; }; @@ -1068,7 +1045,7 @@ public class BackgroundActivityStartController { private final BalExemptionCheck mCheckCallerNonAppVisible = state -> { if (state.mCallingUidHasNonAppVisibleWindow) { return new BalVerdict(BAL_ALLOW_NON_APP_VISIBLE_WINDOW, - /*background*/ false, "callingUid has non-app visible window " + "callingUid has non-app visible window " + getService().mActiveUids.getNonAppVisibleWindowDetails(state.mCallingUid)); } return BalVerdict.BLOCK; @@ -1080,9 +1057,7 @@ public class BackgroundActivityStartController { if (state.mCallingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID || callingAppId == Process.NFC_UID) { - return new BalVerdict( - BAL_ALLOW_ALLOWLISTED_UID, /*background*/ false, - "Important callingUid"); + return new BalVerdict(BAL_ALLOW_ALLOWLISTED_UID, "Important callingUid"); } return BalVerdict.BLOCK; }; @@ -1090,9 +1065,7 @@ public class BackgroundActivityStartController { private final BalExemptionCheck mCheckCallerIsAllowlistedComponent = state -> { // Always allow home application to start activities. if (isHomeApp(state.mCallingUid, state.mCallingPackage)) { - return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, - /*background*/ false, - "Home app"); + return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, "Home app"); } final int callingAppId = UserHandle.getAppId(state.mCallingUid); @@ -1100,37 +1073,31 @@ public class BackgroundActivityStartController { final WindowState imeWindow = getService().mRootWindowContainer.getCurrentInputMethodWindow(); if (imeWindow != null && callingAppId == imeWindow.mOwnerUid) { - return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, - /*background*/ false, - "Active ime"); + return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, "Active ime"); } // don't abort if the callingUid is a persistent system process if (state.mIsCallingUidPersistentSystemProcess) { return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, - /*background*/ false, "callingUid is persistent system process"); + "callingUid is persistent system process"); } // don't abort if the caller has the same uid as the recents component if (getSupervisor().mRecentTasks.isCallerRecents(state.mCallingUid)) { - return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, - /*background*/ true, "Recents Component"); + return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, "Recents Component"); } // don't abort if the callingUid is the device owner if (getService().isDeviceOwner(state.mCallingUid)) { - return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, - /*background*/ true, "Device Owner"); + return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, "Device Owner"); } // don't abort if the callingUid is a affiliated profile owner if (getService().isAffiliatedProfileOwner(state.mCallingUid)) { - return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, - /*background*/ true, "Affiliated Profile Owner"); + return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, "Affiliated Profile Owner"); } // don't abort if the callingUid has companion device final int callingUserId = UserHandle.getUserId(state.mCallingUid); if (getService().isAssociatedCompanionApp(callingUserId, state.mCallingUid)) { - return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, - /*background*/ true, "Companion App"); + return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, "Companion App"); } return BalVerdict.BLOCK; }; @@ -1139,7 +1106,6 @@ public class BackgroundActivityStartController { // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission if (hasBalPermission(state.mCallingUid, state.mCallingPid)) { return new BalVerdict(BAL_ALLOW_PERMISSION, - /*background*/ true, "START_ACTIVITIES_FROM_BACKGROUND permission granted"); } return BalVerdict.BLOCK; @@ -1149,7 +1115,7 @@ public class BackgroundActivityStartController { if (getService().hasSystemAlertWindowPermission(state.mCallingUid, state.mCallingPid, state.mCallingPackage)) { return new BalVerdict(BAL_ALLOW_SAW_PERMISSION, - /*background*/ true, "SYSTEM_ALERT_WINDOW permission is granted"); + "SYSTEM_ALERT_WINDOW permission is granted"); } return BalVerdict.BLOCK; }; @@ -1159,7 +1125,7 @@ public class BackgroundActivityStartController { if (isSystemExemptFlagEnabled() && getService().getAppOpsManager().checkOpNoThrow( AppOpsManager.OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION, state.mCallingUid, state.mCallingPackage) == AppOpsManager.MODE_ALLOWED) { - return new BalVerdict(BAL_ALLOW_PERMISSION, /*background*/ true, + return new BalVerdict(BAL_ALLOW_PERMISSION, "OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop is granted"); } return BalVerdict.BLOCK; @@ -1200,8 +1166,7 @@ public class BackgroundActivityStartController { || state.mAppSwitchState == APP_SWITCH_FG_ONLY || isHomeApp(state.mRealCallingUid, state.mRealCallingPackage); if (appSwitchAllowedOrFg && state.mRealCallingUidHasVisibleActivity) { - return new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, - /*background*/ false, "realCallingUid has visible window"); + return new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "realCallingUid has visible window"); } return BalVerdict.BLOCK; }; @@ -1209,9 +1174,9 @@ public class BackgroundActivityStartController { private final BalExemptionCheck mCheckRealCallerNonAppVisible = state -> { if (state.mRealCallingUidHasNonAppVisibleWindow) { return new BalVerdict(BAL_ALLOW_NON_APP_VISIBLE_WINDOW, - /*background*/ false, "realCallingUid has non-app visible window " - + getService().mActiveUids.getNonAppVisibleWindowDetails( - state.mRealCallingUid)); + "realCallingUid has non-app visible window " + + getService().mActiveUids.getNonAppVisibleWindowDetails( + state.mRealCallingUid)); } return BalVerdict.BLOCK; }; @@ -1230,9 +1195,7 @@ public class BackgroundActivityStartController { == MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS; if (allowAlways && hasBalPermission(state.mRealCallingUid, state.mRealCallingPid)) { - return new BalVerdict(BAL_ALLOW_PERMISSION, - /*background*/ false, - "realCallingUid has BAL permission."); + return new BalVerdict(BAL_ALLOW_PERMISSION, "realCallingUid has BAL permission."); } return BalVerdict.BLOCK; }; @@ -1245,7 +1208,7 @@ public class BackgroundActivityStartController { && getService().hasSystemAlertWindowPermission(state.mRealCallingUid, state.mRealCallingPid, state.mRealCallingPackage)) { return new BalVerdict(BAL_ALLOW_SAW_PERMISSION, - /*background*/ true, "SYSTEM_ALERT_WINDOW permission is granted"); + "SYSTEM_ALERT_WINDOW permission is granted"); } return BalVerdict.BLOCK; }; @@ -1258,7 +1221,6 @@ public class BackgroundActivityStartController { if ((allowAlways || state.mAllowBalExemptionForSystemProcess) && state.mIsRealCallingUidPersistentSystemProcess) { return new BalVerdict(BAL_ALLOW_ALLOWLISTED_UID, - /*background*/ false, "realCallingUid is persistent system process AND intent " + "sender forced to allow."); } @@ -1270,7 +1232,6 @@ public class BackgroundActivityStartController { if (getService().isAssociatedCompanionApp( UserHandle.getUserId(state.mRealCallingUid), state.mRealCallingUid)) { return new BalVerdict(BAL_ALLOW_ALLOWLISTED_COMPONENT, - /*background*/ false, "realCallingUid is a companion app."); } return BalVerdict.BLOCK; diff --git a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java index ccf1aedb3177..31b239421baf 100644 --- a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java +++ b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java @@ -125,27 +125,27 @@ class BackgroundLaunchProcessController { long lastActivityFinishTime) { // Allow if the proc is instrumenting with background activity starts privs. if (checkConfiguration.checkOtherExemptions && hasBackgroundActivityStartPrivileges) { - return new BalVerdict(BAL_ALLOW_PERMISSION, /*background*/ true, + return new BalVerdict(BAL_ALLOW_PERMISSION, /*background*/ "process instrumenting with background activity starts privileges"); } // Allow if the flag was explicitly set. if (checkConfiguration.checkOtherExemptions && isBackgroundStartAllowedByToken(uid, packageName, checkConfiguration.isCheckingForFgsStart)) { return new BalVerdict(balImprovedMetrics() ? BAL_ALLOW_TOKEN : BAL_ALLOW_PERMISSION, - /*background*/ true, "process allowed by token"); + /*background*/ "process allowed by token"); } // Allow if the caller is bound by a UID that's currently foreground. // But still respect the appSwitchState. if (checkConfiguration.checkVisibility && appSwitchState != APP_SWITCH_DISALLOW && isBoundByForegroundUid()) { return new BalVerdict(balImprovedMetrics() ? BAL_ALLOW_BOUND_BY_FOREGROUND - : BAL_ALLOW_VISIBLE_WINDOW, /*background*/ false, + : BAL_ALLOW_VISIBLE_WINDOW, /*background*/ "process bound by foreground uid"); } // Allow if the caller has an activity in any foreground task. if (checkConfiguration.checkOtherExemptions && hasActivityInVisibleTask && appSwitchState != APP_SWITCH_DISALLOW) { - return new BalVerdict(BAL_ALLOW_FOREGROUND, /*background*/ false, + return new BalVerdict(BAL_ALLOW_FOREGROUND, /*background*/ "process has activity in foreground task"); } @@ -160,7 +160,7 @@ class BackgroundLaunchProcessController { long timeSinceLastStartOrFinish = now - Math.max(lastActivityLaunchTime, lastActivityFinishTime); if (timeSinceLastStartOrFinish < checkConfiguration.gracePeriod) { - return new BalVerdict(BAL_ALLOW_GRACE_PERIOD, /*background*/ true, + return new BalVerdict(BAL_ALLOW_GRACE_PERIOD, /*background*/ "within " + checkConfiguration.gracePeriod + "ms grace period (" + timeSinceLastStartOrFinish + "ms)"); } diff --git a/services/core/java/com/android/server/wm/ClientLifecycleManager.java b/services/core/java/com/android/server/wm/ClientLifecycleManager.java index d291d99f2a7a..98e453b3ff89 100644 --- a/services/core/java/com/android/server/wm/ClientLifecycleManager.java +++ b/services/core/java/com/android/server/wm/ClientLifecycleManager.java @@ -25,6 +25,7 @@ import android.app.servertransaction.LaunchActivityItem; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.os.Build; +import android.os.DeadObjectException; import android.os.IBinder; import android.os.RemoteException; import android.os.Trace; @@ -66,64 +67,80 @@ class ClientLifecycleManager { /** * Schedules a transaction, which may consist of multiple callbacks and a lifecycle request. * @param transaction A sequence of client transaction items. - * @throws RemoteException - * + * @return {@code false} if the transaction failed because of {@link RemoteException}. * @see ClientTransaction */ @VisibleForTesting - void scheduleTransaction(@NonNull ClientTransaction transaction) throws RemoteException { - final IApplicationThread client = transaction.getClient(); - try { - transaction.schedule(); - } catch (RemoteException e) { - Slog.w(TAG, "Failed to deliver transaction for " + client - + "\ntransaction=" + transaction); - throw e; + boolean scheduleTransaction(@NonNull ClientTransaction transaction) { + final RemoteException e = transaction.schedule(); + if (e != null) { + final WindowProcessController wpc = mWms.mAtmService.getProcessController( + transaction.getClient()); + Slog.w(TAG, "Failed to deliver transaction for " + wpc + "\ntransaction=" + this, e); + return false; } + return true; } /** * Similar to {@link #scheduleTransactionItem}, but it sends the transaction immediately and * it can be called without WM lock. * + * @return {@code false} if the transaction failed because of {@link RemoteException}. * @see WindowProcessController#setReportedProcState(int) */ - void scheduleTransactionItemNow(@NonNull IApplicationThread client, + boolean scheduleTransactionItemNow(@NonNull IApplicationThread client, @NonNull ClientTransactionItem transactionItem) throws RemoteException { final ClientTransaction clientTransaction = new ClientTransaction(client); clientTransaction.addTransactionItem(transactionItem); - scheduleTransaction(clientTransaction); + final boolean res = scheduleTransaction(clientTransaction); + if (!com.android.window.flags.Flags.cleanupDispatchPendingTransactionsRemoteException() + && !res) { + throw new DeadObjectException(); + } + return res; } /** - * Schedules a transaction with the given item, delivery to client application. + * Schedules a transaction with the given item, delivery to client application, which may be + * queued to dispatched later. * - * @throws RemoteException + * @return {@code false} if the transaction was dispatched immediately, but failed because of + * {@link RemoteException}. If the transaction is queued, any failure will be ignored. * @see ClientTransactionItem */ - void scheduleTransactionItem(@NonNull IApplicationThread client, + boolean scheduleTransactionItem(@NonNull IApplicationThread client, @NonNull ClientTransactionItem item) throws RemoteException { // Wait until RootWindowContainer#performSurfacePlacementNoTrace to dispatch all pending // transactions at once. final ClientTransaction clientTransaction = getOrCreatePendingTransaction(client); clientTransaction.addTransactionItem(item); - onClientTransactionItemScheduled(clientTransaction, false /* shouldDispatchImmediately */); + final boolean res = onClientTransactionItemScheduled(clientTransaction, + false /* shouldDispatchImmediately */); + if (!com.android.window.flags.Flags.cleanupDispatchPendingTransactionsRemoteException() + && !res) { + throw new DeadObjectException(); + } + return res; } /** - * Schedules a transaction with the given items, delivery to client application. + * Schedules a transaction with the given items, delivery to client application, which may be + * queued to dispatched later. * - * @throws RemoteException + * @return {@code false} if the transaction was dispatched immediately, but failed because of + * {@link RemoteException}. If the transaction is queued, any failure will be ignored. * @see ClientTransactionItem */ - void scheduleTransactionItems(@NonNull IApplicationThread client, + boolean scheduleTransactionItems(@NonNull IApplicationThread client, @NonNull ClientTransactionItem... items) throws RemoteException { - scheduleTransactionItems(client, false /* shouldDispatchImmediately */, items); + return scheduleTransactionItems(client, false /* shouldDispatchImmediately */, items); } /** - * Schedules a transaction with the given items, delivery to client application. + * Schedules a transaction with the given items, delivery to client application, which may be + * queued to dispatched later. * * @param shouldDispatchImmediately whether or not to dispatch the transaction immediately. This * should only be {@code true} when it is important to know the @@ -131,11 +148,11 @@ class ClientLifecycleManager { * launches an app, the server needs to know if the transaction * is dispatched successfully, and may restart the process if * not. - * - * @throws RemoteException + * @return {@code false} if the transaction was dispatched immediately, but failed because of + * {@link RemoteException}. If the transaction is queued, any failure will be ignored. * @see ClientTransactionItem */ - void scheduleTransactionItems(@NonNull IApplicationThread client, + boolean scheduleTransactionItems(@NonNull IApplicationThread client, boolean shouldDispatchImmediately, @NonNull ClientTransactionItem... items) throws RemoteException { // Wait until RootWindowContainer#performSurfacePlacementNoTrace to dispatch all pending @@ -147,7 +164,13 @@ class ClientLifecycleManager { clientTransaction.addTransactionItem(items[i]); } - onClientTransactionItemScheduled(clientTransaction, shouldDispatchImmediately); + final boolean res = onClientTransactionItemScheduled(clientTransaction, + shouldDispatchImmediately); + if (!com.android.window.flags.Flags.cleanupDispatchPendingTransactionsRemoteException() + && !res) { + throw new DeadObjectException(); + } + return res; } /** Executes all the pending transactions. */ @@ -159,12 +182,7 @@ class ClientLifecycleManager { final int size = mPendingTransactions.size(); for (int i = 0; i < size; i++) { final ClientTransaction transaction = mPendingTransactions.valueAt(i); - try { - scheduleTransaction(transaction); - } catch (RemoteException e) { - Slog.e(TAG, "Failed to deliver pending transaction", e); - // TODO(b/323801078): apply cleanup for individual transaction item if needed. - } + scheduleTransaction(transaction); } mPendingTransactions.clear(); Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); @@ -174,12 +192,7 @@ class ClientLifecycleManager { void dispatchPendingTransaction(@NonNull IApplicationThread client) { final ClientTransaction pendingTransaction = mPendingTransactions.remove(client.asBinder()); if (pendingTransaction != null) { - try { - scheduleTransaction(pendingTransaction); - } catch (RemoteException e) { - Slog.e(TAG, "Failed to deliver pending transaction", e); - // TODO(b/323801078): apply cleanup for individual transaction item if needed. - } + scheduleTransaction(pendingTransaction); } } @@ -211,15 +224,22 @@ class ClientLifecycleManager { return transaction; } - /** Must only be called with WM lock. */ - private void onClientTransactionItemScheduled( + /** + * Must only be called with WM lock. + * If the transaction should not be queued, it will be dispatched immediately. + * + * @return {@code false} if the transaction was dispatched immediately, but failed because of + * {@link RemoteException}. + */ + private boolean onClientTransactionItemScheduled( @NonNull ClientTransaction clientTransaction, - boolean shouldDispatchImmediately) throws RemoteException { + boolean shouldDispatchImmediately) { if (shouldDispatchImmediately || shouldDispatchPendingTransactionsImmediately()) { // Dispatch the pending transaction immediately. mPendingTransactions.remove(clientTransaction.getClient().asBinder()); - scheduleTransaction(clientTransaction); + return scheduleTransaction(clientTransaction); } + return true; } /** Must only be called with WM lock. */ diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java index d6ae65193121..c26acec19743 100644 --- a/services/core/java/com/android/server/wm/ContentRecorder.java +++ b/services/core/java/com/android/server/wm/ContentRecorder.java @@ -490,7 +490,7 @@ final class ContentRecorder implements WindowContainerListener { return null; } final Task taskToRecord = wc.asTask(); - if (taskToRecord == null) { + if (taskToRecord == null || !taskToRecord.isAttached()) { handleStartRecordingFailed(); ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Content Recording: Unable to retrieve task to start recording for " diff --git a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java index 0106a64660fe..7a959c14fbd2 100644 --- a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java +++ b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java @@ -52,6 +52,13 @@ public final class DesktopModeBoundsCalculator { .getInt("persist.wm.debug.desktop_mode_landscape_app_padding", 25); /** + * Proportion of window height top offset with respect to bottom offset, used for central task + * positioning. Should be kept in sync with constant in + * {@link com.android.wm.shell.desktopmode.DesktopTaskPosition} + */ + public static final float WINDOW_HEIGHT_PROPORTION = 0.375f; + + /** * Updates launch bounds for an activity with respect to its activity options, window layout, * android manifest and task configuration. */ @@ -63,7 +70,16 @@ public final class DesktopModeBoundsCalculator { final Rect stableBounds = new Rect(); task.getDisplayArea().getStableRect(stableBounds); - if (options != null && options.getLaunchBounds() != null) { + // If the options bounds size is flexible, update size with calculated desired size. + final boolean updateOptionBoundsSize = options != null + && options.getFlexibleLaunchSize(); + // If cascading is also enabled, the position of the options bounds must be respected + // during the size update. + final boolean shouldRespectOptionPosition = + updateOptionBoundsSize && DesktopModeFlags.ENABLE_CASCADING_WINDOWS.isTrue(); + + if (options != null && options.getLaunchBounds() != null + && !updateOptionBoundsSize) { outBounds.set(options.getLaunchBounds()); logger.accept("inherit-from-options=" + outBounds); } else if (layout != null) { @@ -76,26 +92,34 @@ public final class DesktopModeBoundsCalculator { stableBounds); logger.accept("layout specifies sizes, inheriting size and applying gravity"); } else if (verticalGravity > 0 || horizontalGravity > 0) { - outBounds.set(calculateInitialBounds(task, activity, stableBounds)); + outBounds.set(calculateInitialBounds(task, activity, stableBounds, options, + shouldRespectOptionPosition)); applyLayoutGravity(verticalGravity, horizontalGravity, outBounds, stableBounds); logger.accept("layout specifies gravity, applying desired bounds and gravity"); + logger.accept("respecting option bounds cascaded position=" + + shouldRespectOptionPosition); } } else { - outBounds.set(calculateInitialBounds(task, activity, stableBounds)); + outBounds.set(calculateInitialBounds(task, activity, stableBounds, options, + shouldRespectOptionPosition)); logger.accept("layout not specified, applying desired bounds"); + logger.accept("respecting option bounds cascaded position=" + + shouldRespectOptionPosition); } } /** * Calculates the initial bounds required for an application to fill a scale of the display * bounds without any letterboxing. This is done by taking into account the applications - * fullscreen size, aspect ratio, orientation and resizability to calculate an area this is - * compatible with the applications previous configuration. + * fullscreen size, aspect ratio, orientation and resizability to calculate an area that is + * compatible with the applications previous configuration. These bounds are then cascaded to + * either the center or to a cascading position supplied by Shell via the option bounds. */ @NonNull private static Rect calculateInitialBounds(@NonNull Task task, - @NonNull ActivityRecord activity, @NonNull Rect stableBounds + @NonNull ActivityRecord activity, @NonNull Rect stableBounds, + @Nullable ActivityOptions options, boolean shouldRespectOptionPosition ) { // Display bounds not taking into account insets. final TaskDisplayArea displayArea = task.getDisplayArea(); @@ -172,6 +196,9 @@ public final class DesktopModeBoundsCalculator { } default -> idealSize; }; + if (shouldRespectOptionPosition) { + return respectShellCascading(initialSize, stableBounds, options.getLaunchBounds()); + } return centerInScreen(initialSize, screenBounds); } @@ -266,14 +293,65 @@ public final class DesktopModeBoundsCalculator { * Adjusts bounds to be positioned in the middle of the screen. */ @NonNull - private static Rect centerInScreen(@NonNull Size desiredSize, + static Rect centerInScreen(@NonNull Size desiredSize, @NonNull Rect screenBounds) { - // TODO(b/325240051): Position apps with bottom heavy offset - final int heightOffset = (screenBounds.height() - desiredSize.getHeight()) / 2; + final int heightOffset = (int) + ((screenBounds.height() - desiredSize.getHeight()) * WINDOW_HEIGHT_PROPORTION); final int widthOffset = (screenBounds.width() - desiredSize.getWidth()) / 2; final Rect resultBounds = new Rect(0, 0, desiredSize.getWidth(), desiredSize.getHeight()); resultBounds.offset(screenBounds.left + widthOffset, screenBounds.top + heightOffset); return resultBounds; } + + /** + * Calculates final initial bounds based on the task's desired size and the cascading anchor + * point extracted from the option bounds. Cascading behaviour should be kept in sync with + * logic in {@link com.android.wm.shell.desktopmode.DesktopTaskPosition}. + */ + @NonNull + private static Rect respectShellCascading(@NonNull Size desiredSize, @NonNull Rect stableBounds, + @NonNull Rect optionBounds) { + final boolean leftAligned = stableBounds.left == optionBounds.left; + final boolean rightAligned = stableBounds.right == optionBounds.right; + final boolean topAligned = stableBounds.top == optionBounds.top; + final boolean bottomAligned = stableBounds.bottom == optionBounds.bottom; + if (leftAligned && topAligned) { + // Bounds cascaded to top left, respect top left position anchor point. + return new Rect( + optionBounds.left, + optionBounds.top, + optionBounds.left + desiredSize.getWidth(), + optionBounds.top + desiredSize.getHeight() + ); + } + if (leftAligned && bottomAligned) { + // Bounds cascaded to bottom left, respect bottom left position anchor point. + return new Rect( + optionBounds.left, + optionBounds.bottom - desiredSize.getHeight(), + optionBounds.left + desiredSize.getWidth(), + optionBounds.bottom + ); + } + if (rightAligned && topAligned) { + // Bounds cascaded to top right, respect top right position anchor point. + return new Rect( + optionBounds.right - desiredSize.getWidth(), + optionBounds.top, + optionBounds.right, + optionBounds.top + desiredSize.getHeight() + ); + } + if (rightAligned && bottomAligned) { + // Bounds cascaded to bottom right, respect bottom right position anchor point. + return new Rect( + optionBounds.right - desiredSize.getWidth(), + optionBounds.bottom - desiredSize.getHeight(), + optionBounds.right, + optionBounds.bottom); + } + // Bounds not cascaded to any corner, default to center position. + return centerInScreen(desiredSize, stableBounds); + } } diff --git a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java index a4eeb688162c..d466a646c7dd 100644 --- a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java @@ -42,6 +42,7 @@ class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { private static final String TAG = TAG_WITH_CLASS_NAME ? "DesktopModeLaunchParamsModifier" : TAG_ATM; + private static final boolean DEBUG = false; private StringBuilder mLogBuilder; @@ -133,6 +134,14 @@ class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { DesktopModeBoundsCalculator.updateInitialBounds(task, layout, activity, options, outParams.mBounds, this::appendLog); appendLog("final desktop mode task bounds set to %s", outParams.mBounds); + if (options != null && options.getFlexibleLaunchSize()) { + // Return result done to prevent other modifiers from respecting option bounds and + // applying further cascading. Since other modifiers are being skipped in this case, + // this modifier is now also responsible to respecting the options launch windowing + // mode. + outParams.mWindowingMode = options.getLaunchWindowingMode(); + return RESULT_DONE; + } return RESULT_CONTINUE; } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 64c19ff70c9f..574ab05075c4 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -6575,6 +6575,22 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp .getKeyguardController().isKeyguardLocked(mDisplayId); } + boolean isKeyguardLockedOrAodShowing() { + return isKeyguardLocked() || isAodShowing(); + } + + /** + * @return whether aod is showing for this display + */ + boolean isAodShowing() { + final boolean isAodShowing = mRootWindowContainer.mTaskSupervisor + .getKeyguardController().isAodShowing(mDisplayId); + if (mDisplayId == DEFAULT_DISPLAY && isAodShowing) { + return !isKeyguardGoingAway(); + } + return isAodShowing; + } + /** * @return whether keyguard is going away on this display */ diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index 6d73739e5046..4eeed5ec8423 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.WindowManager.TRANSIT_FLAG_AOD_APPEARING; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION; @@ -216,6 +217,9 @@ class KeyguardController { } else if (keyguardShowing && !state.mKeyguardShowing) { transition.addFlag(TRANSIT_FLAG_KEYGUARD_APPEARING); } + if (mWindowManager.mFlags.mAodTransition && aodShowing && !state.mAodShowing) { + transition.addFlag(TRANSIT_FLAG_AOD_APPEARING); + } } } // Update the task snapshot if the screen will not be turned off. To make sure that the @@ -238,19 +242,28 @@ class KeyguardController { state.mAodShowing = aodShowing; state.writeEventLog("setKeyguardShown"); - if (keyguardChanged) { - // Irrelevant to AOD. - state.mKeyguardGoingAway = false; - if (keyguardShowing) { - state.mDismissalRequested = false; + if (keyguardChanged || (mWindowManager.mFlags.mAodTransition && aodChanged)) { + if (keyguardChanged) { + // Irrelevant to AOD. + state.mKeyguardGoingAway = false; + if (keyguardShowing) { + state.mDismissalRequested = false; + } } if (goingAwayRemoved - || (keyguardShowing && !Display.isOffState(dc.getDisplayInfo().state))) { + || (keyguardShowing && !Display.isOffState(dc.getDisplayInfo().state)) + || (mWindowManager.mFlags.mAodTransition && aodShowing)) { // Keyguard decided to show or stopped going away. Send a transition to animate back // to the locked state before holding the sleep token again if (!ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) { - dc.requestTransitionAndLegacyPrepare( - TRANSIT_TO_FRONT, TRANSIT_FLAG_KEYGUARD_APPEARING, /* trigger= */ null); + if (keyguardChanged) { + dc.requestTransitionAndLegacyPrepare(TRANSIT_TO_FRONT, + TRANSIT_FLAG_KEYGUARD_APPEARING, /* trigger= */ null); + } + if (mWindowManager.mFlags.mAodTransition && aodChanged && aodShowing) { + dc.requestTransitionAndLegacyPrepare(TRANSIT_TO_FRONT, + TRANSIT_FLAG_AOD_APPEARING, /* trigger= */ null); + } } dc.mWallpaperController.adjustWallpaperWindows(); dc.executeAppTransition(); diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS index dede7676a4b6..243a5326b545 100644 --- a/services/core/java/com/android/server/wm/OWNERS +++ b/services/core/java/com/android/server/wm/OWNERS @@ -3,7 +3,6 @@ set noparent ogunwale@google.com jjaggi@google.com racarr@google.com -chaviw@google.com vishnun@google.com akulian@google.com roosa@google.com diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 3db1d50f3d6a..c78cdaa10df2 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -36,6 +36,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; +import static android.view.WindowManager.TRANSIT_FLAG_AOD_APPEARING; import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED; import static android.view.WindowManager.TRANSIT_OPEN; @@ -980,6 +981,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { return false; } + boolean isInAodAppearTransition() { + return (mFlags & TRANSIT_FLAG_AOD_APPEARING) != 0; + } + /** * Specifies configuration change explicitly for the window container, so it can be chosen as * transition target. This is usually used with transition mode diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index 11c5c9345ab2..9b3b4451a746 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -526,6 +526,19 @@ class TransitionController { return false; } + boolean isInAodAppearTransition() { + if (mCollectingTransition != null && mCollectingTransition.isInAodAppearTransition()) { + return true; + } + for (int i = mWaitingTransitions.size() - 1; i >= 0; --i) { + if (mWaitingTransitions.get(i).isInAodAppearTransition()) return true; + } + for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) { + if (mPlayingTransitions.get(i).isInAodAppearTransition()) return true; + } + return false; + } + /** * @return A pair of the transition and restore-behind target for the given {@param container}. * @param container An ancestor of a transient-launch activity diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index a8b9fedcdc73..644417ec98e5 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -166,6 +166,14 @@ class WallpaperController { mFindResults.setWallpaperTarget(w); return false; } + } else if (mService.mFlags.mAodTransition + && mDisplayContent.isKeyguardLockedOrAodShowing()) { + if (mService.mPolicy.isKeyguardHostWindow(w.mAttrs) + && w.mTransitionController.isInAodAppearTransition()) { + if (DEBUG_WALLPAPER) Slog.v(TAG, "Found aod transition wallpaper target: " + w); + mFindResults.setWallpaperTarget(w); + return true; + } } final boolean animationWallpaper = animatingContainer != null @@ -678,7 +686,8 @@ class WallpaperController { private WallpaperWindowToken getTokenForTarget(WindowState target) { if (target == null) return null; WindowState window = mFindResults.getTopWallpaper( - target.canShowWhenLocked() && mService.isKeyguardLocked()); + (target.canShowWhenLocked() && mService.isKeyguardLocked()) + || (mService.mFlags.mAodTransition && mDisplayContent.isAodShowing())); return window == null ? null : window.mToken.asWallpaperToken(); } @@ -721,7 +730,9 @@ class WallpaperController { if (mFindResults.wallpaperTarget == null && mFindResults.useTopWallpaperAsTarget) { mFindResults.setWallpaperTarget( - mFindResults.getTopWallpaper(mDisplayContent.isKeyguardLocked())); + mFindResults.getTopWallpaper(mService.mFlags.mAodTransition + ? mDisplayContent.isKeyguardLockedOrAodShowing() + : mDisplayContent.isKeyguardLocked())); } } @@ -885,11 +896,17 @@ class WallpaperController { if (mDisplayContent.mWmService.mFlags.mEnsureWallpaperInTransitions) { visibleRequested = mWallpaperTarget != null && mWallpaperTarget.isVisibleRequested(); } - updateWallpaperTokens(visibleRequested, mDisplayContent.isKeyguardLocked()); + updateWallpaperTokens(visibleRequested, + mService.mFlags.mAodTransition + ? mDisplayContent.isKeyguardLockedOrAodShowing() + : mDisplayContent.isKeyguardLocked()); ProtoLog.v(WM_DEBUG_WALLPAPER, "Wallpaper at display %d - visibility: %b, keyguardLocked: %b", - mDisplayContent.getDisplayId(), visible, mDisplayContent.isKeyguardLocked()); + mDisplayContent.getDisplayId(), visible, + mService.mFlags.mAodTransition + ? mDisplayContent.isKeyguardLockedOrAodShowing() + : mDisplayContent.isKeyguardLocked()); if (visible && mLastFrozen != mFindResults.isWallpaperTargetForLetterbox) { mLastFrozen = mFindResults.isWallpaperTargetForLetterbox; diff --git a/services/core/jni/stats/OWNERS b/services/core/jni/stats/OWNERS index ab2d91adaeab..8d87925fbe45 100644 --- a/services/core/jni/stats/OWNERS +++ b/services/core/jni/stats/OWNERS @@ -1,5 +1,4 @@ jeffreyhuang@google.com -jtnguyen@google.com muhammadq@google.com sharaieko@google.com singhtejinder@google.com diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index aee32a0473a3..215d6ca964eb 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -3582,14 +3582,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @GuardedBy("getLockObject()") private boolean maybeMigrateMemoryTaggingLocked(String backupId) { - if (!Flags.setMtePolicyCoexistence()) { - Slog.i(LOG_TAG, "Memory Tagging not migrated because coexistence " - + "support is disabled."); - return false; - } if (mOwners.isMemoryTaggingMigrated()) { - // TODO: Remove log after Flags.setMtePolicyCoexistence full rollout. - Slog.v(LOG_TAG, "Memory Tagging was previously migrated to policy engine."); return false; } @@ -16354,7 +16347,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static <V> PolicyDefinition<V> getPolicyDefinitionForIdentifier( @NonNull String identifier) { Objects.requireNonNull(identifier); - if (Flags.setMtePolicyCoexistence() && MEMORY_TAGGING_POLICY.equals(identifier)) { + if (MEMORY_TAGGING_POLICY.equals(identifier)) { return (PolicyDefinition<V>) PolicyDefinition.MEMORY_TAGGING; } else { return (PolicyDefinition<V>) getPolicyDefinitionForRestriction(identifier); @@ -23759,46 +23752,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)); } - if (Flags.setMtePolicyCoexistence()) { - enforcePermission(MANAGE_DEVICE_POLICY_MTE, caller.getPackageName(), - UserHandle.USER_ALL); - } else { - Preconditions.checkCallAuthorization( - isDefaultDeviceOwner(caller) - || isProfileOwnerOfOrganizationOwnedDevice(caller)); - } + enforcePermission(MANAGE_DEVICE_POLICY_MTE, caller.getPackageName(), + UserHandle.USER_ALL); synchronized (getLockObject()) { - if (Flags.setMtePolicyCoexistence()) { - final EnforcingAdmin admin = enforcePermissionAndGetEnforcingAdmin(null, - MANAGE_DEVICE_POLICY_MTE, callerPackageName, caller.getUserId()); - if (flags != DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY) { - mDevicePolicyEngine.setGlobalPolicy( - PolicyDefinition.MEMORY_TAGGING, - admin, - new IntegerPolicyValue(flags)); - } else { - mDevicePolicyEngine.removeGlobalPolicy( - PolicyDefinition.MEMORY_TAGGING, - admin); - } + final EnforcingAdmin admin = enforcePermissionAndGetEnforcingAdmin(null, + MANAGE_DEVICE_POLICY_MTE, callerPackageName, caller.getUserId()); + if (flags != DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY) { + mDevicePolicyEngine.setGlobalPolicy( + PolicyDefinition.MEMORY_TAGGING, + admin, + new IntegerPolicyValue(flags)); } else { - ActiveAdmin admin = - getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked(); - if (admin != null) { - final String memtagProperty = "arm64.memtag.bootctl"; - if (flags == DevicePolicyManager.MTE_ENABLED) { - mInjector.systemPropertiesSet(memtagProperty, "memtag"); - } else if (flags == DevicePolicyManager.MTE_DISABLED) { - mInjector.systemPropertiesSet(memtagProperty, "memtag-off"); - } else if (flags == DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY) { - if (admin.mtePolicy != DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY) { - mInjector.systemPropertiesSet(memtagProperty, "default"); - } - } - admin.mtePolicy = flags; - saveSettingsLocked(caller.getUserId()); - } + mDevicePolicyEngine.removeGlobalPolicy( + PolicyDefinition.MEMORY_TAGGING, + admin); } DevicePolicyEventLogger.createEvent(DevicePolicyEnums.SET_MTE_POLICY) @@ -23817,10 +23785,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Preconditions.checkCallAuthorization(isSystemUid(getCallerIdentity()), "Only system services can call setMtePolicyBySystem"); - if (!Flags.setMtePolicyCoexistence()) { - throw new UnsupportedOperationException("System can not set MTE policy only"); - } - EnforcingAdmin admin = EnforcingAdmin.createSystemEnforcingAdmin(systemEntity); if (policy != DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY) { mDevicePolicyEngine.setGlobalPolicy( @@ -23858,31 +23822,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public int getMtePolicy(String callerPackageName) { final CallerIdentity caller = getCallerIdentity(callerPackageName); - if (Flags.setMtePolicyCoexistence()) { - enforcePermission(MANAGE_DEVICE_POLICY_MTE, caller.getPackageName(), - UserHandle.USER_ALL); - } else { - Preconditions.checkCallAuthorization( - isDefaultDeviceOwner(caller) - || isProfileOwnerOfOrganizationOwnedDevice(caller) - || isSystemUid(caller)); - } + enforcePermission(MANAGE_DEVICE_POLICY_MTE, caller.getPackageName(), + UserHandle.USER_ALL); synchronized (getLockObject()) { - if (Flags.setMtePolicyCoexistence()) { - final EnforcingAdmin admin = enforcePermissionAndGetEnforcingAdmin(null, - MANAGE_DEVICE_POLICY_MTE, callerPackageName, caller.getUserId()); - final Integer policyFromAdmin = mDevicePolicyEngine.getGlobalPolicySetByAdmin( - PolicyDefinition.MEMORY_TAGGING, admin); - return (policyFromAdmin != null ? policyFromAdmin - : DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY); - } else { - ActiveAdmin admin = - getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked(); - return admin != null - ? admin.mtePolicy - : DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY; - } + final EnforcingAdmin admin = enforcePermissionAndGetEnforcingAdmin(null, + MANAGE_DEVICE_POLICY_MTE, callerPackageName, caller.getUserId()); + final Integer policyFromAdmin = mDevicePolicyEngine.getGlobalPolicySetByAdmin( + PolicyDefinition.MEMORY_TAGGING, admin); + return (policyFromAdmin != null ? policyFromAdmin + : DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY); } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java index caaf0964bb4e..6dfe08c1eb7e 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java @@ -433,10 +433,8 @@ class OwnersData { out.attributeBoolean(null, ATTR_RESET_PASSWORD_WITH_TOKEN_MIGRATED, mResetPasswordWithTokenMigrated); } - if (Flags.setMtePolicyCoexistence()) { - out.attributeBoolean(null, ATTR_MEMORY_TAGGING_MIGRATED, - mMemoryTaggingMigrated); - } + out.attributeBoolean(null, ATTR_MEMORY_TAGGING_MIGRATED, + mMemoryTaggingMigrated); if (Flags.setKeyguardDisabledFeaturesCoexistence()) { out.attributeBoolean(null, ATTR_SET_KEYGUARD_DISABLED_FEATURES_MIGRATED, mSetKeyguardDisabledFeaturesMigrated); @@ -514,8 +512,7 @@ class OwnersData { mResetPasswordWithTokenMigrated = Flags.resetPasswordWithTokenCoexistence() && parser.getAttributeBoolean(null, ATTR_RESET_PASSWORD_WITH_TOKEN_MIGRATED, false); - mMemoryTaggingMigrated = Flags.setMtePolicyCoexistence() - && parser.getAttributeBoolean(null, + mMemoryTaggingMigrated = parser.getAttributeBoolean(null, ATTR_MEMORY_TAGGING_MIGRATED, false); mSetKeyguardDisabledFeaturesMigrated = Flags.setKeyguardDisabledFeaturesCoexistence() diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml index 5fe5b237bdef..d6a685378d9e 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml +++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml @@ -18,6 +18,9 @@ <option name="test-suite-tag" value="apct" /> <option name="test-suite-tag" value="apct-instrumentation" /> + <!-- Needed for reading the app files for the test artifacts --> + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="cleanup-apks" value="true" /> <option name="install-arg" value="-t" /> diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceMockedTest.java index 6ad3df1dd6f2..ac11216bdf0a 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceMockedTest.java @@ -102,11 +102,12 @@ import java.io.FileInputStream; import java.io.IOException; /** - * Run as {@code atest FrameworksMockingServicesTests:com.android.server.pm.UserManagerServiceTest} + * Run as {@code atest + * FrameworksMockingServicesTests:com.android.server.pm.UserManagerServiceMockedTest} */ -public final class UserManagerServiceTest { +public final class UserManagerServiceMockedTest { - private static final String TAG = UserManagerServiceTest.class.getSimpleName(); + private static final String TAG = UserManagerServiceMockedTest.class.getSimpleName(); /** * Id for a simple user (that doesn't have profiles). diff --git a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java index 17d8882b487c..ea83825cd810 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java @@ -571,6 +571,95 @@ public class AutoclickControllerTest { assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting()).isNotEqualTo(-1); } + @Test + @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR) + public void pauseButton_panelNotHovered_clickNotTriggeredWhenPaused() { + injectFakeMouseActionHoverMoveEvent(); + + // Pause autoclick and ensure the panel is not hovered. + AutoclickTypePanel mockAutoclickTypePanel = mock(AutoclickTypePanel.class); + when(mockAutoclickTypePanel.isPaused()).thenReturn(true); + when(mockAutoclickTypePanel.isHovered()).thenReturn(false); + mController.mAutoclickTypePanel = mockAutoclickTypePanel; + + // Send hover move event. + MotionEvent hoverMove = MotionEvent.obtain( + /* downTime= */ 0, + /* eventTime= */ 100, + /* action= */ MotionEvent.ACTION_HOVER_MOVE, + /* x= */ 30f, + /* y= */ 0f, + /* metaState= */ 0); + hoverMove.setSource(InputDevice.SOURCE_MOUSE); + mController.onMotionEvent(hoverMove, hoverMove, /* policyFlags= */ 0); + + // Verify click is not triggered. + assertThat(mController.mClickScheduler.getIsActiveForTesting()).isFalse(); + assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting()).isEqualTo(-1); + } + + @Test + @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR) + public void pauseButton_panelHovered_clickTriggeredWhenPaused() { + injectFakeMouseActionHoverMoveEvent(); + + // Pause autoclick and hover the panel. + AutoclickTypePanel mockAutoclickTypePanel = mock(AutoclickTypePanel.class); + when(mockAutoclickTypePanel.isPaused()).thenReturn(true); + when(mockAutoclickTypePanel.isHovered()).thenReturn(true); + mController.mAutoclickTypePanel = mockAutoclickTypePanel; + + // Send hover move event. + MotionEvent hoverMove = MotionEvent.obtain( + /* downTime= */ 0, + /* eventTime= */ 100, + /* action= */ MotionEvent.ACTION_HOVER_MOVE, + /* x= */ 30f, + /* y= */ 0f, + /* metaState= */ 0); + hoverMove.setSource(InputDevice.SOURCE_MOUSE); + mController.onMotionEvent(hoverMove, hoverMove, /* policyFlags= */ 0); + + // Verify click is triggered. + assertThat(mController.mClickScheduler.getIsActiveForTesting()).isTrue(); + assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting()).isNotEqualTo(-1); + } + + @Test + @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR) + public void pauseButton_unhoveringCancelsClickWhenPaused() { + injectFakeMouseActionHoverMoveEvent(); + + // Pause autoclick and hover the panel. + AutoclickTypePanel mockAutoclickTypePanel = mock(AutoclickTypePanel.class); + when(mockAutoclickTypePanel.isPaused()).thenReturn(true); + when(mockAutoclickTypePanel.isHovered()).thenReturn(true); + mController.mAutoclickTypePanel = mockAutoclickTypePanel; + + // Send hover move event. + MotionEvent hoverMove = MotionEvent.obtain( + /* downTime= */ 0, + /* eventTime= */ 100, + /* action= */ MotionEvent.ACTION_HOVER_MOVE, + /* x= */ 30f, + /* y= */ 0f, + /* metaState= */ 0); + hoverMove.setSource(InputDevice.SOURCE_MOUSE); + mController.onMotionEvent(hoverMove, hoverMove, /* policyFlags= */ 0); + + // Verify click is triggered. + assertThat(mController.mClickScheduler.getIsActiveForTesting()).isTrue(); + assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting()).isNotEqualTo(-1); + + // Now simulate the pointer being moved outside the panel. + when(mockAutoclickTypePanel.isHovered()).thenReturn(false); + mController.clickPanelController.onHoverChange(/* hovered= */ false); + + // Verify pending click is canceled. + assertThat(mController.mClickScheduler.getIsActiveForTesting()).isFalse(); + assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting()).isEqualTo(-1); + } + private void injectFakeMouseActionHoverMoveEvent() { MotionEvent event = getFakeMotionHoverMoveEvent(); event.setSource(InputDevice.SOURCE_MOUSE); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickLinearLayoutTest.java b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickLinearLayoutTest.java new file mode 100644 index 000000000000..9e629f7c87a2 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickLinearLayoutTest.java @@ -0,0 +1,102 @@ +/* + * Copyright 2025 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.accessibility.autoclick; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static com.google.common.truth.Truth.assertThat; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableContext; +import android.view.MotionEvent; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Test cases for {@link AutoclickLinearLayout}. */ +@RunWith(AndroidTestingRunner.class) +public class AutoclickLinearLayoutTest { + private boolean mHovered; + + private final AutoclickLinearLayout.OnHoverChangedListener mListener = + new AutoclickLinearLayout.OnHoverChangedListener() { + @Override + public void onHoverChanged(boolean hovered) { + mHovered = hovered; + } + }; + + @Rule + public TestableContext mTestableContext = + new TestableContext(getInstrumentation().getContext()); + private AutoclickLinearLayout mAutoclickLinearLayout; + + @Before + public void setUp() { + mAutoclickLinearLayout = new AutoclickLinearLayout(mTestableContext); + } + + @Test + public void autoclickLinearLayout_hoverChangedListener_setHovered() { + mHovered = false; + mAutoclickLinearLayout.setOnHoverChangedListener(mListener); + mAutoclickLinearLayout.onHoverChanged(/* hovered= */ true); + assertThat(mHovered).isTrue(); + } + + @Test + public void autoclickLinearLayout_hoverChangedListener_setNotHovered() { + mHovered = true; + + mAutoclickLinearLayout.setOnHoverChangedListener(mListener); + mAutoclickLinearLayout.onHoverChanged(/* hovered= */ false); + assertThat(mHovered).isFalse(); + } + + @Test + public void autoclickLinearLayout_onInterceptHoverEvent_hovered() { + mAutoclickLinearLayout.setHovered(false); + mAutoclickLinearLayout.onInterceptHoverEvent( + getFakeMotionEvent(MotionEvent.ACTION_HOVER_ENTER)); + assertThat(mAutoclickLinearLayout.isHovered()).isTrue(); + + mAutoclickLinearLayout.setHovered(false); + mAutoclickLinearLayout.onInterceptHoverEvent( + getFakeMotionEvent(MotionEvent.ACTION_HOVER_MOVE)); + assertThat(mAutoclickLinearLayout.isHovered()).isTrue(); + } + + @Test + public void autoclickLinearLayout_onInterceptHoverEvent_hoveredExit() { + mAutoclickLinearLayout.setHovered(true); + mAutoclickLinearLayout.onInterceptHoverEvent( + getFakeMotionEvent(MotionEvent.ACTION_HOVER_EXIT)); + assertThat(mAutoclickLinearLayout.isHovered()).isFalse(); + } + + private MotionEvent getFakeMotionEvent(int motionEventAction) { + return MotionEvent.obtain( + /* downTime= */ 0, + /* eventTime= */ 0, + /* action= */ motionEventAction, + /* x= */ 0, + /* y= */ 0, + /* metaState= */ 0); + } +} diff --git a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java index 9e123406dff5..f7b16c808c50 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java @@ -78,6 +78,7 @@ public class AutoclickTypePanelTest { private @AutoclickType int mActiveClickType = AUTOCLICK_TYPE_LEFT_CLICK; private boolean mPaused; + private boolean mHovered; private final ClickPanelControllerInterface clickPanelController = new ClickPanelControllerInterface() { @@ -90,6 +91,11 @@ public class AutoclickTypePanelTest { public void toggleAutoclickPause(boolean paused) { mPaused = paused; } + + @Override + public void onHoverChange(boolean hovered) { + mHovered = hovered; + } }; @Before @@ -412,6 +418,33 @@ public class AutoclickTypePanelTest { upEvent.recycle(); } + @Test + public void hovered_IsHovered() { + AutoclickLinearLayout mContext = mAutoclickTypePanel.getContentViewForTesting(); + + assertThat(mAutoclickTypePanel.isHovered()).isFalse(); + mContext.onInterceptHoverEvent(getFakeMotionHoverMoveEvent()); + assertThat(mAutoclickTypePanel.isHovered()).isTrue(); + } + + @Test + public void hovered_OnHoverChange_isHovered() { + AutoclickLinearLayout mContext = mAutoclickTypePanel.getContentViewForTesting(); + + mHovered = false; + mContext.onHoverChanged(true); + assertThat(mHovered).isTrue(); + } + + @Test + public void hovered_OnHoverChange_isNotHovered() { + AutoclickLinearLayout mContext = mAutoclickTypePanel.getContentViewForTesting(); + + mHovered = true; + mContext.onHoverChanged(false); + assertThat(mHovered).isFalse(); + } + private void verifyButtonHasSelectedStyle(@NonNull LinearLayout button) { GradientDrawable gradientDrawable = (GradientDrawable) button.getBackground(); assertThat(gradientDrawable.getColor().getDefaultColor()) @@ -426,4 +459,14 @@ public class AutoclickTypePanelTest { assertThat(params.x).isEqualTo(expectedPosition[2]); assertThat(params.y).isEqualTo(expectedPosition[3]); } + + private MotionEvent getFakeMotionHoverMoveEvent() { + return MotionEvent.obtain( + /* downTime= */ 0, + /* eventTime= */ 0, + /* action= */ MotionEvent.ACTION_HOVER_MOVE, + /* x= */ 0, + /* y= */ 0, + /* metaState= */ 0); + } } diff --git a/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpSqlPersistenceTest.java b/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpSqlPersistenceTest.java index 84713079c9d3..01fee7f66497 100644 --- a/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpSqlPersistenceTest.java +++ b/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpSqlPersistenceTest.java @@ -226,9 +226,9 @@ public class DiscreteAppOpSqlPersistenceTest { mDiscreteRegistry.recordDiscreteAccess(event2); } - /** This clears in-memory cache and push records into the database. */ private void flushDiscreteOpsToDatabase() { - mDiscreteRegistry.writeAndClearOldAccessHistory(); + // This clears in-memory cache and push records from cache into the database. + mDiscreteRegistry.shutdown(); } /** diff --git a/services/tests/servicestests/src/com/android/server/appop/DiscreteOpsMigrationAndRollbackTest.java b/services/tests/servicestests/src/com/android/server/appop/DiscreteOpsMigrationAndRollbackTest.java index 21cc3bac3938..8eea1c73d4f2 100644 --- a/services/tests/servicestests/src/com/android/server/appop/DiscreteOpsMigrationAndRollbackTest.java +++ b/services/tests/servicestests/src/com/android/server/appop/DiscreteOpsMigrationAndRollbackTest.java @@ -106,7 +106,8 @@ public class DiscreteOpsMigrationAndRollbackTest { opEvent.getDuration(), opEvent.getAttributionFlags(), (int) opEvent.getChainId(), DiscreteOpsRegistry.ACCESS_TYPE_NOTE_OP); } - sqlRegistry.writeAndClearOldAccessHistory(); + // flush records from cache to the database. + sqlRegistry.shutdown(); assertThat(sqlRegistry.getAllDiscreteOps().size()).isEqualTo(RECORD_COUNT); assertThat(sqlRegistry.getLargestAttributionChainId()).isEqualTo(RECORD_COUNT); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 301a7544227f..9d4fe9e9765b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -41,8 +41,8 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; -import static android.content.pm.ApplicationInfo.CATEGORY_SOCIAL; import static android.content.pm.ApplicationInfo.CATEGORY_GAME; +import static android.content.pm.ApplicationInfo.CATEGORY_SOCIAL; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.content.res.Configuration.UI_MODE_TYPE_DESK; @@ -66,7 +66,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; @@ -196,7 +195,7 @@ public class ActivityRecordTests extends WindowTestsBase { // Because the booted state is set, avoid starting real home if there is no task. doReturn(false).when(mRootWindowContainer).resumeHomeActivity(any(), anyString(), any()); // Do not execute the transaction, because we can't verify the parameter after it recycles. - doNothing().when(mClientLifecycleManager).scheduleTransaction(any()); + doReturn(true).when(mClientLifecycleManager).scheduleTransaction(any()); } private TestStartingWindowOrganizer registerTestStartingWindowOrganizer() { @@ -266,7 +265,7 @@ public class ActivityRecordTests extends WindowTestsBase { break; } } - return null; + return true; }).when(mClientLifecycleManager).scheduleTransaction(any()); activity.setState(STOPPED, "testPausingWhenVisibleFromStopped"); diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java index c934c55dfb8e..e3a8776aca6a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerExemptionTests.java @@ -486,7 +486,7 @@ public class BackgroundActivityStartControllerExemptionTests { // setup state when(mCallerApp.areBackgroundActivityStartsAllowed(anyInt(), any())).thenReturn( - new BalVerdict(BAL_ALLOW_FOREGROUND, false, "allowed")); + new BalVerdict(BAL_ALLOW_FOREGROUND, "allowed")); when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW); // prepare call @@ -523,7 +523,7 @@ public class BackgroundActivityStartControllerExemptionTests { mCallerApp); when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW); when(mCallerApp.areBackgroundActivityStartsAllowed(anyInt(), any())).thenReturn( - new BalVerdict(BAL_ALLOW_FOREGROUND, false, "allowed")); + new BalVerdict(BAL_ALLOW_FOREGROUND, "allowed")); // prepare call PendingIntentRecord originatingPendingIntent = mPendingIntentRecord; @@ -572,7 +572,7 @@ public class BackgroundActivityStartControllerExemptionTests { when(mCallerApp.areBackgroundActivityStartsAllowed(anyInt(), any())).thenReturn( BalVerdict.BLOCK); when(otherProcess.areBackgroundActivityStartsAllowed(anyInt(), any())).thenReturn( - new BalVerdict(BAL_ALLOW_FOREGROUND, false, "allowed")); + new BalVerdict(BAL_ALLOW_FOREGROUND, "allowed")); // prepare call PendingIntentRecord originatingPendingIntent = mPendingIntentRecord; diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerLogTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerLogTests.java index 99e730ae76cf..cd5f3912bfc6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerLogTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerLogTests.java @@ -92,7 +92,7 @@ public class BackgroundActivityStartControllerLogTests { @Test public void intent_visible_noLog() { useIntent(); - BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false, "visible"); + BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "visible"); mState.setResultForCaller(finalVerdict); mState.setResultForRealCaller(BalVerdict.BLOCK); assertThat(mController.shouldLogStats(finalVerdict, mState)).isFalse(); @@ -101,7 +101,7 @@ public class BackgroundActivityStartControllerLogTests { @Test public void intent_saw_log() { useIntent(); - BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, false, "SAW"); + BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, "SAW"); mState.setResultForCaller(finalVerdict); mState.setResultForRealCaller(BalVerdict.BLOCK); assertThat(mController.shouldLogStats(finalVerdict, mState)).isTrue(); @@ -111,7 +111,7 @@ public class BackgroundActivityStartControllerLogTests { @Test public void pendingIntent_callerOnly_saw_log() { usePendingIntent(); - BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, false, "SAW"); + BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, "SAW"); mState.setResultForCaller(finalVerdict); mState.setResultForRealCaller(BalVerdict.BLOCK); assertThat(mController.shouldLogStats(finalVerdict, mState)).isTrue(); @@ -121,7 +121,7 @@ public class BackgroundActivityStartControllerLogTests { @Test public void pendingIntent_realCallerOnly_saw_log() { usePendingIntent(); - BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, false, "SAW") + BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, "SAW") .setBasedOnRealCaller(); mState.setResultForCaller(BalVerdict.BLOCK); mState.setResultForRealCaller(finalVerdict); @@ -131,7 +131,7 @@ public class BackgroundActivityStartControllerLogTests { @Test public void intent_shouldLogIntentActivity() { - BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, false, "SAW"); + BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, "SAW"); useIntent(APP1_UID); assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isFalse(); useIntent(SYSTEM_UID); @@ -140,7 +140,7 @@ public class BackgroundActivityStartControllerLogTests { @Test public void pendingIntent_shouldLogIntentActivityForCaller() { - BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, false, "SAW"); + BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, "SAW"); usePendingIntent(APP1_UID, APP2_UID); assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isFalse(); usePendingIntent(SYSTEM_UID, SYSTEM_UID); @@ -153,7 +153,7 @@ public class BackgroundActivityStartControllerLogTests { @Test public void pendingIntent_shouldLogIntentActivityForRealCaller() { - BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, false, + BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_SAW_PERMISSION, "SAW").setBasedOnRealCaller(); usePendingIntent(APP1_UID, APP2_UID); assertThat(mController.shouldLogIntentActivity(finalVerdict, mState)).isFalse(); @@ -168,7 +168,7 @@ public class BackgroundActivityStartControllerLogTests { @Test public void pendingIntent_realCallerOnly_visible_noLog() { usePendingIntent(); - BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false, + BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "visible").setBasedOnRealCaller(); mState.setResultForCaller(BalVerdict.BLOCK); mState.setResultForRealCaller(finalVerdict); @@ -178,7 +178,7 @@ public class BackgroundActivityStartControllerLogTests { @Test public void pendingIntent_callerOnly_visible_noLog() { usePendingIntent(); - BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false, "visible"); + BalVerdict finalVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "visible"); mState.setResultForCaller(finalVerdict); mState.setResultForRealCaller(BalVerdict.BLOCK); assertThat(mController.shouldLogStats(finalVerdict, mState)).isTrue(); diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java index 51706d72cb35..fe9a6e746513 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java @@ -305,7 +305,7 @@ public class BackgroundActivityStartControllerTests { @Test public void testRegularActivityStart_allowedByCaller_isAllowed() { // setup state - BalVerdict callerVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false, + BalVerdict callerVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "CallerIsVisible"); mController.setCallerVerdict(callerVerdict); mController.setRealCallerVerdict(BalVerdict.BLOCK); @@ -340,7 +340,7 @@ public class BackgroundActivityStartControllerTests { @Test public void testRegularActivityStart_allowedByRealCaller_isAllowed() { // setup state - BalVerdict realCallerVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false, + BalVerdict realCallerVerdict = new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "RealCallerIsVisible"); mController.setCallerVerdict(BalVerdict.BLOCK); mController.setRealCallerVerdict(realCallerVerdict); @@ -373,9 +373,9 @@ public class BackgroundActivityStartControllerTests { public void testRegularActivityStart_allowedByCallerAndRealCaller_returnsCallerVerdict() { // setup state BalVerdict callerVerdict = - new BalVerdict(BAL_ALLOW_PERMISSION, false, "CallerHasPermission"); + new BalVerdict(BAL_ALLOW_PERMISSION, "CallerHasPermission"); BalVerdict realCallerVerdict = - new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false, "RealCallerIsVisible"); + new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "RealCallerIsVisible"); mController.setCallerVerdict(callerVerdict); mController.setRealCallerVerdict(realCallerVerdict); @@ -411,9 +411,9 @@ public class BackgroundActivityStartControllerTests { public void testPendingIntent_allowedByCallerAndRealCallerButOptOut_isBlocked() { // setup state BalVerdict callerVerdict = - new BalVerdict(BAL_ALLOW_PERMISSION, false, "CallerhasPermission"); + new BalVerdict(BAL_ALLOW_PERMISSION, "CallerhasPermission"); BalVerdict realCallerVerdict = - new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false, "RealCallerIsVisible"); + new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "RealCallerIsVisible"); mController.setCallerVerdict(callerVerdict); mController.setRealCallerVerdict(realCallerVerdict); @@ -452,7 +452,7 @@ public class BackgroundActivityStartControllerTests { public void testPendingIntent_allowedByCallerAndOptIn_isAllowed() { // setup state BalVerdict callerVerdict = - new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false, "CallerIsVisible"); + new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "CallerIsVisible"); mController.setCallerVerdict(callerVerdict); mController.setRealCallerVerdict(BalVerdict.BLOCK); @@ -489,7 +489,7 @@ public class BackgroundActivityStartControllerTests { public void testPendingIntent_allowedByRealCallerAndOptIn_isAllowed() { // setup state BalVerdict realCallerVerdict = - new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, false, "RealCallerIsVisible"); + new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "RealCallerIsVisible"); mController.setCallerVerdict(BalVerdict.BLOCK); mController.setRealCallerVerdict(realCallerVerdict); @@ -571,7 +571,6 @@ public class BackgroundActivityStartControllerTests { + "callerApp: mCallerApp; " + "inVisibleTask: false; " + "balAllowedByPiCreator: BSP.ALLOW_BAL; " - + "balAllowedByPiCreatorWithHardening: BSP.ALLOW_BAL; " + "callerStartMode: MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; " + "hasRealCaller: true; " + "isCallForResult: false; " @@ -674,7 +673,6 @@ public class BackgroundActivityStartControllerTests { + "callerApp: mCallerApp; " + "inVisibleTask: false; " + "balAllowedByPiCreator: BSP.NONE; " - + "balAllowedByPiCreatorWithHardening: BSP.NONE; " + "callerStartMode: MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; " + "hasRealCaller: true; " + "isCallForResult: false; " diff --git a/services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java b/services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java index 02ad9dbfda8e..8d214dd2c940 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java @@ -16,11 +16,13 @@ package com.android.server.wm; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -32,17 +34,19 @@ import android.app.IApplicationThread; import android.app.servertransaction.ActivityLifecycleItem; import android.app.servertransaction.ClientTransaction; import android.app.servertransaction.ClientTransactionItem; +import android.os.DeadObjectException; import android.os.IBinder; import android.os.RemoteException; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.window.flags.Flags; + import org.junit.Before; 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; @@ -60,15 +64,11 @@ public class ClientLifecycleManagerTests extends SystemServiceTestsBase { @Mock private IApplicationThread mClient; @Mock - private IApplicationThread.Stub mNonBinderClient; - @Mock private ClientTransaction mTransaction; @Mock private ClientTransactionItem mTransactionItem; @Mock private ActivityLifecycleItem mLifecycleItem; - @Captor - private ArgumentCaptor<ClientTransaction> mTransactionCaptor; private WindowManagerService mWms; private ClientLifecycleManager mLifecycleManager; @@ -83,7 +83,6 @@ public class ClientLifecycleManagerTests extends SystemServiceTestsBase { doReturn(true).when(mLifecycleItem).isActivityLifecycleItem(); doReturn(mClientBinder).when(mClient).asBinder(); - doReturn(mNonBinderClient).when(mNonBinderClient).asBinder(); } @Test @@ -91,13 +90,11 @@ public class ClientLifecycleManagerTests extends SystemServiceTestsBase { spyOn(mWms.mWindowPlacerLocked); doReturn(true).when(mWms.mWindowPlacerLocked).isTraversalScheduled(); - // Use non binder client to get non-recycled ClientTransaction. - mLifecycleManager.scheduleTransactionItem(mNonBinderClient, mTransactionItem); + mLifecycleManager.scheduleTransactionItem(mClient, mTransactionItem); // When there is traversal scheduled, add transaction items to pending. assertEquals(1, mLifecycleManager.mPendingTransactions.size()); - ClientTransaction transaction = - mLifecycleManager.mPendingTransactions.get(mNonBinderClient); + ClientTransaction transaction = mLifecycleManager.mPendingTransactions.get(mClientBinder); assertEquals(1, transaction.getTransactionItems().size()); assertEquals(mTransactionItem, transaction.getTransactionItems().get(0)); // TODO(b/324203798): cleanup after remove UnsupportedAppUsage @@ -108,10 +105,10 @@ public class ClientLifecycleManagerTests extends SystemServiceTestsBase { // Add new transaction item to the existing pending. clearInvocations(mLifecycleManager); - mLifecycleManager.scheduleTransactionItem(mNonBinderClient, mLifecycleItem); + mLifecycleManager.scheduleTransactionItem(mClient, mLifecycleItem); assertEquals(1, mLifecycleManager.mPendingTransactions.size()); - transaction = mLifecycleManager.mPendingTransactions.get(mNonBinderClient); + transaction = mLifecycleManager.mPendingTransactions.get(mClientBinder); assertEquals(2, transaction.getTransactionItems().size()); assertEquals(mTransactionItem, transaction.getTransactionItems().get(0)); assertEquals(mLifecycleItem, transaction.getTransactionItems().get(1)); @@ -124,8 +121,7 @@ public class ClientLifecycleManagerTests extends SystemServiceTestsBase { @Test public void testScheduleTransactionItemNow() throws RemoteException { - // Use non binder client to get non-recycled ClientTransaction. - mLifecycleManager.scheduleTransactionItemNow(mNonBinderClient, mTransactionItem); + mLifecycleManager.scheduleTransactionItemNow(mClient, mTransactionItem); // Dispatch immediately. assertTrue(mLifecycleManager.mPendingTransactions.isEmpty()); @@ -137,13 +133,11 @@ public class ClientLifecycleManagerTests extends SystemServiceTestsBase { spyOn(mWms.mWindowPlacerLocked); doReturn(true).when(mWms.mWindowPlacerLocked).isTraversalScheduled(); - // Use non binder client to get non-recycled ClientTransaction. - mLifecycleManager.scheduleTransactionItems(mNonBinderClient, mTransactionItem, - mLifecycleItem); + mLifecycleManager.scheduleTransactionItems(mClient, mTransactionItem, mLifecycleItem); assertEquals(1, mLifecycleManager.mPendingTransactions.size()); final ClientTransaction transaction = - mLifecycleManager.mPendingTransactions.get(mNonBinderClient); + mLifecycleManager.mPendingTransactions.get(mClientBinder); assertEquals(2, transaction.getTransactionItems().size()); assertEquals(mTransactionItem, transaction.getTransactionItems().get(0)); assertEquals(mLifecycleItem, transaction.getTransactionItems().get(1)); @@ -160,8 +154,8 @@ public class ClientLifecycleManagerTests extends SystemServiceTestsBase { spyOn(mWms.mWindowPlacerLocked); doReturn(true).when(mWms.mWindowPlacerLocked).isTraversalScheduled(); - // Use non binder client to get non-recycled ClientTransaction. - mLifecycleManager.scheduleTransactionItems(mNonBinderClient, + mLifecycleManager.scheduleTransactionItems( + mClient, true /* shouldDispatchImmediately */, mTransactionItem, mLifecycleItem); @@ -187,7 +181,7 @@ public class ClientLifecycleManagerTests extends SystemServiceTestsBase { doReturn(true).when(mWms.mWindowPlacerLocked).isLayoutDeferred(); // Queue transactions during layout deferred. - mLifecycleManager.scheduleTransactionItem(mNonBinderClient, mLifecycleItem); + mLifecycleManager.scheduleTransactionItem(mClient, mLifecycleItem); verify(mLifecycleManager, never()).scheduleTransaction(any()); @@ -203,4 +197,42 @@ public class ClientLifecycleManagerTests extends SystemServiceTestsBase { verify(mLifecycleManager).scheduleTransaction(any()); } + + @EnableFlags(Flags.FLAG_CLEANUP_DISPATCH_PENDING_TRANSACTIONS_REMOTE_EXCEPTION) + @Test + public void testOnRemoteException_returnTrueOnSuccess() throws RemoteException { + final boolean res = mLifecycleManager.scheduleTransactionItemNow(mClient, mTransactionItem); + + assertTrue(res); + } + + @EnableFlags(Flags.FLAG_CLEANUP_DISPATCH_PENDING_TRANSACTIONS_REMOTE_EXCEPTION) + @Test + public void testOnRemoteException_returnFalseOnFailure() throws RemoteException { + final DeadObjectException e = new DeadObjectException(); + doThrow(e).when(mClient).scheduleTransaction(any()); + + // No exception when flag enabled. + final boolean res = mLifecycleManager.scheduleTransactionItemNow(mClient, mTransactionItem); + + assertFalse(res); + } + + @EnableFlags(Flags.FLAG_CLEANUP_DISPATCH_PENDING_TRANSACTIONS_REMOTE_EXCEPTION) + @Test + public void testOnRemoteException_returnTrueForQueueing() throws RemoteException { + spyOn(mWms.mWindowPlacerLocked); + doReturn(true).when(mWms.mWindowPlacerLocked).isLayoutDeferred(); + final DeadObjectException e = new DeadObjectException(); + doThrow(e).when(mClient).scheduleTransaction(any()); + + final boolean res = mLifecycleManager.scheduleTransactionItem(mClient, mTransactionItem); + + assertTrue(res); + + doReturn(false).when(mWms.mWindowPlacerLocked).isLayoutDeferred(); + mLifecycleManager.onLayoutContinued(); + + verify(mLifecycleManager).scheduleTransaction(any()); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java index 3a06fff1d1a7..bc37496d14a7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java @@ -42,8 +42,10 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.DesktopModeBoundsCalculator.DESKTOP_MODE_INITIAL_BOUNDS_SCALE; import static com.android.server.wm.DesktopModeBoundsCalculator.DESKTOP_MODE_LANDSCAPE_APP_PADDING; +import static com.android.server.wm.DesktopModeBoundsCalculator.centerInScreen; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE; +import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_DONE; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP; import static org.junit.Assert.assertEquals; @@ -60,6 +62,7 @@ import android.graphics.Rect; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; +import android.util.Size; import android.view.Gravity; import androidx.test.filters.SmallTest; @@ -1099,6 +1102,110 @@ public class DesktopModeLaunchParamsModifierTests extends } @Test + @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_SHELL_INITIAL_BOUNDS_REGRESSION_BUG_FIX}) + public void testOptionsBoundsSet_flexibleLaunchSize_windowingModeSet() { + setupDesktopModeLaunchParamsModifier(); + + final TestDisplayContent display = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN); + final Task task = new TaskBuilder(mSupervisor).setActivityType( + ACTIVITY_TYPE_STANDARD).setDisplay(display).build(); + final ActivityOptions options = ActivityOptions.makeBasic() + .setLaunchBounds(new Rect( + DISPLAY_STABLE_BOUNDS.left, + DISPLAY_STABLE_BOUNDS.top, + /* right = */ 500, + /* bottom = */ 500)) + .setFlexibleLaunchSize(true); + options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM); + + assertEquals(RESULT_DONE, + new CalculateRequestBuilder().setTask(task).setOptions(options).calculate()); + assertEquals(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_SHELL_INITIAL_BOUNDS_REGRESSION_BUG_FIX}) + public void testOptionsBoundsSet_flexibleLaunchSize_boundsSizeModified() { + setupDesktopModeLaunchParamsModifier(); + + final TestDisplayContent display = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN); + final Task task = new TaskBuilder(mSupervisor).setActivityType( + ACTIVITY_TYPE_STANDARD).setDisplay(display).build(); + final ActivityOptions options = ActivityOptions.makeBasic() + .setLaunchBounds(new Rect( + DISPLAY_STABLE_BOUNDS.left, + DISPLAY_STABLE_BOUNDS.top, + /* right = */ 500, + /* bottom = */ 500)) + .setFlexibleLaunchSize(true); + final int modifiedWidth = + (int) (DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + final int modifiedHeight = + (int) (DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + + assertEquals(RESULT_DONE, + new CalculateRequestBuilder().setTask(task).setOptions(options).calculate()); + assertEquals(modifiedWidth, mResult.mBounds.width()); + assertEquals(modifiedHeight, mResult.mBounds.height()); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_SHELL_INITIAL_BOUNDS_REGRESSION_BUG_FIX}) + public void testOptionsBoundsSet_flexibleLaunchSizeWithCascading_cornerCascadeRespected() { + setupDesktopModeLaunchParamsModifier(); + + final TestDisplayContent display = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN); + final Task task = new TaskBuilder(mSupervisor).setActivityType( + ACTIVITY_TYPE_STANDARD).setDisplay(display).build(); + // Set launch bounds with corner cascade. + final ActivityOptions options = ActivityOptions.makeBasic() + .setLaunchBounds(new Rect( + DISPLAY_STABLE_BOUNDS.left, + DISPLAY_STABLE_BOUNDS.top, + /* right = */ 500, + /* bottom = */ 500)) + .setFlexibleLaunchSize(true); + + assertEquals(RESULT_DONE, + new CalculateRequestBuilder().setTask(task).setOptions(options).calculate()); + assertEquals(DISPLAY_STABLE_BOUNDS.left, mResult.mBounds.left); + assertEquals(DISPLAY_STABLE_BOUNDS.top, mResult.mBounds.top); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_SHELL_INITIAL_BOUNDS_REGRESSION_BUG_FIX}) + public void testOptionsBoundsSet_flexibleLaunchSize_centerCascadeRespected() { + setupDesktopModeLaunchParamsModifier(); + + final TestDisplayContent display = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN); + final Task task = new TaskBuilder(mSupervisor).setActivityType( + ACTIVITY_TYPE_STANDARD).setDisplay(display).build(); + // Set launch bounds with center cascade. + final ActivityOptions options = ActivityOptions.makeBasic() + .setLaunchBounds(new Rect( + /* left = */ 320, + /* top = */ 100, + /* right = */ 640, + /* bottom = */ 200)) + .setFlexibleLaunchSize(true); + final int modifiedWidth = + (int) (DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + final int modifiedHeight = + (int) (DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + final Rect centerCascadedBounds = centerInScreen( + new Size(modifiedWidth, modifiedHeight), DISPLAY_STABLE_BOUNDS); + + assertEquals(RESULT_DONE, + new CalculateRequestBuilder().setTask(task).setOptions(options).calculate()); + assertEquals(centerCascadedBounds, mResult.mBounds); + assertEquals(centerCascadedBounds.top, mResult.mBounds.top); + } + + @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testNonEmptyLayoutBounds_CenterToDisplay() { setupDesktopModeLaunchParamsModifier(); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java index d228970e0371..9dc70266bf3d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java @@ -24,7 +24,6 @@ import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; @@ -295,7 +294,7 @@ public class WindowProcessControllerTests extends WindowTestsBase { @Test public void testCachedStateConfigurationChange() throws RemoteException { - doNothing().when(mClientLifecycleManager).scheduleTransactionItemNow(any(), any()); + doReturn(true).when(mClientLifecycleManager).scheduleTransactionItemNow(any(), any()); final IApplicationThread thread = mWpc.getThread(); final Configuration newConfig = new Configuration(mWpc.getConfiguration()); newConfig.densityDpi += 100; diff --git a/telecomm/java/android/telecom/OWNERS b/telecomm/java/android/telecom/OWNERS index 6656a01403b8..0854c5d45603 100644 --- a/telecomm/java/android/telecom/OWNERS +++ b/telecomm/java/android/telecom/OWNERS @@ -3,4 +3,3 @@ rgreenwalt@google.com tgunn@google.com breadley@google.com -hallliu@google.com diff --git a/tests/AppJankTest/src/android/app/jank/tests/JankTrackerTest.java b/tests/AppJankTest/src/android/app/jank/tests/JankTrackerTest.java index 1bdf019d6c42..9d87fbd67eef 100644 --- a/tests/AppJankTest/src/android/app/jank/tests/JankTrackerTest.java +++ b/tests/AppJankTest/src/android/app/jank/tests/JankTrackerTest.java @@ -18,10 +18,12 @@ package android.app.jank.tests; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import android.app.jank.Flags; import android.app.jank.JankTracker; import android.app.jank.StateTracker; +import android.content.Context; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; @@ -55,10 +57,9 @@ public class JankTrackerTest { * Start an empty activity so decore view is not null when creating the JankTracker instance. */ private static ActivityScenario<EmptyActivity> sEmptyActivityRule; - private static String sActivityName; - private static View sActivityDecorView; + private static Context sContext; @BeforeClass public static void classSetup() { @@ -66,6 +67,7 @@ public class JankTrackerTest { sEmptyActivityRule.onActivity(activity -> { sActivityDecorView = activity.getWindow().getDecorView(); sActivityName = activity.toString(); + sContext = activity.getApplicationContext(); }); } @@ -168,4 +170,14 @@ public class JankTrackerTest { assertNotNull(jankTracker); } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_DETAILED_APP_JANK_METRICS_API) + public void jankTracker_IsNull_WhenViewNotInHierarchy() { + TestWidget testWidget = new TestWidget(sContext); + JankTracker jankTracker = testWidget.getJankTracker(); + + assertNull(jankTracker); + } + } diff --git a/tests/EnforcePermission/OWNERS b/tests/EnforcePermission/OWNERS index 39550a394f33..160849e5616f 100644 --- a/tests/EnforcePermission/OWNERS +++ b/tests/EnforcePermission/OWNERS @@ -1,3 +1,2 @@ # Bug component: 315013 tweek@google.com -brufino@google.com diff --git a/tools/codegen/OWNERS b/tools/codegen/OWNERS index c9bd260ca7ae..e69de29bb2d1 100644 --- a/tools/codegen/OWNERS +++ b/tools/codegen/OWNERS @@ -1 +0,0 @@ -chiuwinson@google.com diff --git a/tools/hiddenapi/OWNERS b/tools/hiddenapi/OWNERS index dc82aac9d41c..d1e36b953e7f 100644 --- a/tools/hiddenapi/OWNERS +++ b/tools/hiddenapi/OWNERS @@ -1,6 +1,5 @@ # compat-team@ for changes to hiddenapi files mathewi@google.com -satayev@google.com # soong-team@ as the files these tools protect are tightly coupled with Soong file:platform/build/soong:/OWNERS diff --git a/tools/lint/OWNERS b/tools/lint/OWNERS index 8e4569ee2a30..4035e19158c6 100644 --- a/tools/lint/OWNERS +++ b/tools/lint/OWNERS @@ -1,6 +1,5 @@ mattgilbride@google.com azharaa@google.com -jsharkey@google.com per-file *CallingSettingsNonUserGetterMethods* = file:/packages/SettingsProvider/OWNERS per-file *RegisterReceiverFlagDetector* = jacobhobbie@google.com diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/OWNERS b/wifi/java/src/android/net/wifi/sharedconnectivity/OWNERS index 2a4acc111257..abb9aa4c05a2 100644 --- a/wifi/java/src/android/net/wifi/sharedconnectivity/OWNERS +++ b/wifi/java/src/android/net/wifi/sharedconnectivity/OWNERS @@ -1,4 +1,3 @@ # Bug component: 1216021 asapperstein@google.com -etancohen@google.com |