diff options
128 files changed, 1922 insertions, 878 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 525ae80ff9a7..a5178cfaeec8 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -34,6 +34,7 @@ java_defaults { ":android.view.inputmethod.flags-aconfig-java{.generated_srcjars}", ":android.widget.flags-aconfig-java{.generated_srcjars}", ":com.android.media.flags.bettertogether-aconfig-java{.generated_srcjars}", + ":sdk_sandbox_flags_lib{.generated_srcjars}", ], // Add aconfig-annotations-lib as a dependency for the optimization libs: ["aconfig-annotations-lib"], diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index a366464ceac2..7bc6f9bfafc7 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -23,7 +23,7 @@ import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.inMultiWindowMode; import static android.os.Process.myUid; - +import static com.android.sdksandbox.flags.Flags.sandboxActivitySdkBasedContext; import static java.lang.Character.MIN_VALUE; import android.annotation.AnimRes; @@ -8631,6 +8631,12 @@ public class Activity extends ContextThemeWrapper Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken, IBinder shareableActivityToken) { + if (sandboxActivitySdkBasedContext()) { + // Sandbox activities extract a token from the intent's extra to identify the related + // SDK as part of overriding attachBaseContext, then it wraps the passed context in an + // SDK ContextWrapper, so mIntent has to be set before calling attachBaseContext. + mIntent = intent; + } attachBaseContext(context); mFragments.attachHost(null /*parent*/); @@ -8656,6 +8662,7 @@ public class Activity extends ContextThemeWrapper mShareableActivityToken = shareableActivityToken; mIdent = ident; mApplication = application; + //TODO(b/300059435): do not set the mIntent again as part of the flag clean up. mIntent = intent; mReferrer = referrer; mComponent = intent.getComponent(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index f28b4b4eb207..00e546ad25b0 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -38,6 +38,7 @@ import static android.window.ConfigurationHelper.isDifferentDisplay; import static android.window.ConfigurationHelper.shouldUpdateResources; import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; import static com.android.internal.os.SafeZipPathValidatorCallback.VALIDATE_ZIP_PATH_FOR_PATH_TRAVERSAL; +import static com.android.sdksandbox.flags.Flags.sandboxActivitySdkBasedContext; import android.annotation.NonNull; import android.annotation.Nullable; @@ -53,6 +54,8 @@ import android.app.backup.BackupAgent; import android.app.backup.BackupAnnotations.BackupDestination; import android.app.backup.BackupAnnotations.OperationType; import android.app.compat.CompatChanges; +import android.app.sdksandbox.sandboxactivity.ActivityContextInfo; +import android.app.sdksandbox.sandboxactivity.ActivityContextInfoProvider; import android.app.servertransaction.ActivityLifecycleItem; import android.app.servertransaction.ActivityLifecycleItem.LifecycleState; import android.app.servertransaction.ActivityRelaunchItem; @@ -3655,15 +3658,16 @@ public final class ActivityThread extends ClientTransactionHandler } @UnsupportedAppUsage - public final void sendActivityResult( - IBinder token, String id, int requestCode, + public void sendActivityResult( + IBinder activityToken, String id, int requestCode, int resultCode, Intent data) { if (DEBUG_RESULTS) Slog.v(TAG, "sendActivityResult: id=" + id + " req=" + requestCode + " res=" + resultCode + " data=" + data); ArrayList<ResultInfo> list = new ArrayList<ResultInfo>(); list.add(new ResultInfo(id, requestCode, resultCode, data)); - final ClientTransaction clientTransaction = ClientTransaction.obtain(mAppThread, token); - clientTransaction.addCallback(ActivityResultItem.obtain(list)); + final ClientTransaction clientTransaction = ClientTransaction.obtain(mAppThread, + activityToken); + clientTransaction.addCallback(ActivityResultItem.obtain(activityToken, list)); try { mAppThread.scheduleTransaction(clientTransaction); } catch (RemoteException e) { @@ -3733,16 +3737,38 @@ public final class ActivityThread extends ClientTransactionHandler r.activityInfo.targetActivity); } - ContextImpl appContext = createBaseContextForActivity(r); + boolean isSandboxActivityContext = sandboxActivitySdkBasedContext() + && r.intent.isSandboxActivity(mSystemContext); + boolean isSandboxedSdkContextUsed = false; + ContextImpl activityBaseContext; + if (isSandboxActivityContext) { + activityBaseContext = createBaseContextForSandboxActivity(r); + if (activityBaseContext == null) { + // Failed to retrieve the SDK based sandbox activity context, falling back to the + // app based context. + activityBaseContext = createBaseContextForActivity(r); + } else { + isSandboxedSdkContextUsed = true; + } + } else { + activityBaseContext = createBaseContextForActivity(r); + } Activity activity = null; try { - java.lang.ClassLoader cl = appContext.getClassLoader(); + java.lang.ClassLoader cl; + if (isSandboxedSdkContextUsed) { + // In case of sandbox activity, the context refers to the an SDK with no visibility + // on the SandboxedActivity java class, the App context should be used instead. + cl = activityBaseContext.getApplicationContext().getClassLoader(); + } else { + cl = activityBaseContext.getClassLoader(); + } activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo), - appContext.getAttributionSource()); + activityBaseContext.getAttributionSource()); if (r.state != null) { r.state.setClassLoader(cl); } @@ -3773,7 +3799,8 @@ public final class ActivityThread extends ClientTransactionHandler } if (activity != null) { - CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); + CharSequence title = + r.activityInfo.loadLabel(activityBaseContext.getPackageManager()); Configuration config = new Configuration(mConfigurationController.getCompatConfiguration()); if (r.overrideConfig != null) { @@ -3790,11 +3817,11 @@ public final class ActivityThread extends ClientTransactionHandler // Activity resources must be initialized with the same loaders as the // application context. - appContext.getResources().addLoaders( + activityBaseContext.getResources().addLoaders( app.getResources().getLoaders().toArray(new ResourcesLoader[0])); - appContext.setOuterContext(activity); - activity.attach(appContext, this, getInstrumentation(), r.token, + activityBaseContext.setOuterContext(activity); + activity.attach(activityBaseContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, window, r.activityConfigCallback, @@ -3951,6 +3978,44 @@ public final class ActivityThread extends ClientTransactionHandler } /** + * Creates the base context for the sandbox activity based on its corresponding SDK {@link + * ApplicationInfo} and flags. + */ + @Nullable + private ContextImpl createBaseContextForSandboxActivity(@NonNull ActivityClientRecord r) { + ActivityContextInfoProvider contextInfoProvider = ActivityContextInfoProvider.getInstance(); + + ActivityContextInfo contextInfo; + try { + contextInfo = contextInfoProvider.getActivityContextInfo(r.intent); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Passed intent does not match an expected sandbox activity", e); + return null; + } catch (IllegalStateException e) { + Log.e(TAG, "SDK customized context flag is disabled", e); + return null; + } catch (Exception e) { // generic catch to unexpected exceptions + Log.e(TAG, "Failed to create context for sandbox activity", e); + return null; + } + + final int displayId = ActivityClient.getInstance().getDisplayId(r.token); + final LoadedApk sdkApk = getPackageInfo( + contextInfo.getSdkApplicationInfo(), + r.packageInfo.getCompatibilityInfo(), + ActivityContextInfo.CONTEXT_FLAGS); + + final ContextImpl activityContext = ContextImpl.createActivityContext( + this, sdkApk, r.activityInfo, r.token, displayId, r.overrideConfig); + + // Set sandbox app's context as the application context for sdk context + activityContext.mPackageInfo.makeApplicationInner( + /*forceDefaultAppClass=*/false, mInstrumentation); + + return activityContext; + } + + /** * Extended implementation of activity launch. Used when server requests a launch or relaunch. */ @Override @@ -4365,16 +4430,16 @@ public final class ActivityThread extends ClientTransactionHandler private void schedulePauseWithUserLeavingHint(ActivityClientRecord r) { final ClientTransaction transaction = ClientTransaction.obtain(this.mAppThread, r.token); - transaction.setLifecycleStateRequest(PauseActivityItem.obtain(r.activity.isFinishing(), - /* userLeaving */ true, r.activity.mConfigChangeFlags, /* dontReport */ false, - /* autoEnteringPip */ false)); + transaction.setLifecycleStateRequest(PauseActivityItem.obtain(r.token, + r.activity.isFinishing(), /* userLeaving */ true, r.activity.mConfigChangeFlags, + /* dontReport */ false, /* autoEnteringPip */ false)); executeTransaction(transaction); } private void scheduleResume(ActivityClientRecord r) { final ClientTransaction transaction = ClientTransaction.obtain(this.mAppThread, r.token); - transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(/* isForward */ false, - /* shouldSendCompatFakeFocus */ false)); + transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(r.token, + /* isForward */ false, /* shouldSendCompatFakeFocus */ false)); executeTransaction(transaction); } @@ -5958,8 +6023,8 @@ public final class ActivityThread extends ClientTransactionHandler ? r.createdConfig : mConfigurationController.getConfiguration(), r.overrideConfig); final ActivityRelaunchItem activityRelaunchItem = ActivityRelaunchItem.obtain( - null /* pendingResults */, null /* pendingIntents */, 0 /* configChanges */, - mergedConfiguration, r.mPreserveWindow); + r.token, null /* pendingResults */, null /* pendingIntents */, + 0 /* configChanges */, mergedConfiguration, r.mPreserveWindow); // Make sure to match the existing lifecycle state in the end of the transaction. final ActivityLifecycleItem lifecycleRequest = TransactionExecutorHelper.getLifecycleRequestForCurrentState(r); diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java index e40925441f0f..c2c54278a84e 100644 --- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java +++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java @@ -45,7 +45,7 @@ public class ActivityConfigurationChangeItem extends ActivityTransactionItem { CompatibilityInfo.applyOverrideScaleIfNeeded(mConfiguration); // Notify the client of an upcoming change in the token configuration. This ensures that // batches of config change items only process the newest configuration. - client.updatePendingActivityConfiguration(token, mConfiguration); + client.updatePendingActivityConfiguration(getActivityToken(), mConfiguration); } @Override @@ -61,8 +61,7 @@ public class ActivityConfigurationChangeItem extends ActivityTransactionItem { @Override public Context getContextToUpdate(@NonNull ClientTransactionHandler client, @Nullable IBinder token) { - // TODO(b/260873529): Update ClientTransaction to bundle multiple activity config updates. - return client.getActivity(token); + return client.getActivity(getActivityToken()); } // ObjectPoolItem implementation @@ -70,7 +69,9 @@ public class ActivityConfigurationChangeItem extends ActivityTransactionItem { private ActivityConfigurationChangeItem() {} /** Obtain an instance initialized with provided params. */ - public static ActivityConfigurationChangeItem obtain(@NonNull Configuration config) { + @NonNull + public static ActivityConfigurationChangeItem obtain(@NonNull IBinder activityToken, + @NonNull Configuration config) { if (config == null) { throw new IllegalArgumentException("Config must not be null."); } @@ -80,6 +81,7 @@ public class ActivityConfigurationChangeItem extends ActivityTransactionItem { if (instance == null) { instance = new ActivityConfigurationChangeItem(); } + instance.setActivityToken(activityToken); instance.mConfiguration = config; return instance; @@ -87,6 +89,7 @@ public class ActivityConfigurationChangeItem extends ActivityTransactionItem { @Override public void recycle() { + super.recycle(); mConfiguration = Configuration.EMPTY; ObjectPool.recycle(this); } @@ -96,32 +99,34 @@ public class ActivityConfigurationChangeItem extends ActivityTransactionItem { /** Write to Parcel. */ @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { + super.writeToParcel(dest, flags); dest.writeTypedObject(mConfiguration, flags); } /** Read from Parcel. */ - private ActivityConfigurationChangeItem(Parcel in) { + private ActivityConfigurationChangeItem(@NonNull Parcel in) { + super(in); mConfiguration = in.readTypedObject(Configuration.CREATOR); } public static final @NonNull Creator<ActivityConfigurationChangeItem> CREATOR = - new Creator<ActivityConfigurationChangeItem>() { - public ActivityConfigurationChangeItem createFromParcel(Parcel in) { - return new ActivityConfigurationChangeItem(in); - } + new Creator<>() { + public ActivityConfigurationChangeItem createFromParcel(@NonNull Parcel in) { + return new ActivityConfigurationChangeItem(in); + } - public ActivityConfigurationChangeItem[] newArray(int size) { - return new ActivityConfigurationChangeItem[size]; - } - }; + public ActivityConfigurationChangeItem[] newArray(int size) { + return new ActivityConfigurationChangeItem[size]; + } + }; @Override public boolean equals(@Nullable Object o) { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if (!super.equals(o)) { return false; } final ActivityConfigurationChangeItem other = (ActivityConfigurationChangeItem) o; @@ -130,11 +135,15 @@ public class ActivityConfigurationChangeItem extends ActivityTransactionItem { @Override public int hashCode() { - return mConfiguration.hashCode(); + int result = 17; + result = 31 * result + super.hashCode(); + result = 31 * result + Objects.hashCode(mConfiguration); + return result; } @Override public String toString() { - return "ActivityConfigurationChange{config=" + mConfiguration + "}"; + return "ActivityConfigurationChange{" + super.toString() + + ",config=" + mConfiguration + "}"; } } diff --git a/core/java/android/app/servertransaction/ActivityLifecycleItem.java b/core/java/android/app/servertransaction/ActivityLifecycleItem.java index cadb6606b1be..b34f6788fb60 100644 --- a/core/java/android/app/servertransaction/ActivityLifecycleItem.java +++ b/core/java/android/app/servertransaction/ActivityLifecycleItem.java @@ -17,6 +17,8 @@ package android.app.servertransaction; import android.annotation.IntDef; +import android.annotation.NonNull; +import android.os.Parcel; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -50,12 +52,13 @@ public abstract class ActivityLifecycleItem extends ActivityTransactionItem { public static final int ON_DESTROY = 6; public static final int ON_RESTART = 7; + ActivityLifecycleItem() {} + + ActivityLifecycleItem(@NonNull Parcel in) { + super(in); + } + /** A final lifecycle state that an activity should reach. */ @LifecycleState public abstract int getTargetState(); - - /** Called by subclasses to make sure base implementation is cleaned up */ - @Override - public void recycle() { - } } diff --git a/core/java/android/app/servertransaction/ActivityRelaunchItem.java b/core/java/android/app/servertransaction/ActivityRelaunchItem.java index a8b058ac3583..491d0260f6fb 100644 --- a/core/java/android/app/servertransaction/ActivityRelaunchItem.java +++ b/core/java/android/app/servertransaction/ActivityRelaunchItem.java @@ -56,18 +56,18 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { private ActivityClientRecord mActivityClientRecord; @Override - public void preExecute(ClientTransactionHandler client, IBinder token) { + public void preExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token) { // The local config is already scaled so only apply if this item is from server side. if (!client.isExecutingLocalTransaction()) { CompatibilityInfo.applyOverrideScaleIfNeeded(mConfig); } - mActivityClientRecord = client.prepareRelaunchActivity(token, mPendingResults, + mActivityClientRecord = client.prepareRelaunchActivity(getActivityToken(), mPendingResults, mPendingNewIntents, mConfigChanges, mConfig, mPreserveWindow); } @Override - public void execute(ClientTransactionHandler client, ActivityClientRecord r, - PendingTransactionActions pendingActions) { + public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r, + @NonNull PendingTransactionActions pendingActions) { if (mActivityClientRecord == null) { if (DEBUG_ORDER) Slog.d(TAG, "Activity relaunch cancelled"); return; @@ -78,9 +78,9 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { } @Override - public void postExecute(ClientTransactionHandler client, IBinder token, - PendingTransactionActions pendingActions) { - final ActivityClientRecord r = getActivityClientRecord(client, token); + public void postExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token, + @NonNull PendingTransactionActions pendingActions) { + final ActivityClientRecord r = getActivityClientRecord(client); client.reportRelaunch(r); } @@ -89,13 +89,16 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { private ActivityRelaunchItem() {} /** Obtain an instance initialized with provided params. */ - public static ActivityRelaunchItem obtain(List<ResultInfo> pendingResults, - List<ReferrerIntent> pendingNewIntents, int configChanges, MergedConfiguration config, - boolean preserveWindow) { + @NonNull + public static ActivityRelaunchItem obtain(@NonNull IBinder activityToken, + @Nullable List<ResultInfo> pendingResults, + @Nullable List<ReferrerIntent> pendingNewIntents, int configChanges, + @NonNull MergedConfiguration config, boolean preserveWindow) { ActivityRelaunchItem instance = ObjectPool.obtain(ActivityRelaunchItem.class); if (instance == null) { instance = new ActivityRelaunchItem(); } + instance.setActivityToken(activityToken); instance.mPendingResults = pendingResults; instance.mPendingNewIntents = pendingNewIntents; instance.mConfigChanges = configChanges; @@ -107,6 +110,7 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { @Override public void recycle() { + super.recycle(); mPendingResults = null; mPendingNewIntents = null; mConfigChanges = 0; @@ -121,7 +125,8 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { /** Write to Parcel. */ @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { + super.writeToParcel(dest, flags); dest.writeTypedList(mPendingResults, flags); dest.writeTypedList(mPendingNewIntents, flags); dest.writeInt(mConfigChanges); @@ -130,7 +135,8 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { } /** Read from Parcel. */ - private ActivityRelaunchItem(Parcel in) { + private ActivityRelaunchItem(@NonNull Parcel in) { + super(in); mPendingResults = in.createTypedArrayList(ResultInfo.CREATOR); mPendingNewIntents = in.createTypedArrayList(ReferrerIntent.CREATOR); mConfigChanges = in.readInt(); @@ -139,22 +145,22 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { } public static final @NonNull Creator<ActivityRelaunchItem> CREATOR = - new Creator<ActivityRelaunchItem>() { - public ActivityRelaunchItem createFromParcel(Parcel in) { - return new ActivityRelaunchItem(in); - } + new Creator<>() { + public ActivityRelaunchItem createFromParcel(@NonNull Parcel in) { + return new ActivityRelaunchItem(in); + } - public ActivityRelaunchItem[] newArray(int size) { - return new ActivityRelaunchItem[size]; - } - }; + public ActivityRelaunchItem[] newArray(int size) { + return new ActivityRelaunchItem[size]; + } + }; @Override public boolean equals(@Nullable Object o) { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if (!super.equals(o)) { return false; } final ActivityRelaunchItem other = (ActivityRelaunchItem) o; @@ -167,6 +173,7 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { @Override public int hashCode() { int result = 17; + result = 31 * result + super.hashCode(); result = 31 * result + Objects.hashCode(mPendingResults); result = 31 * result + Objects.hashCode(mPendingNewIntents); result = 31 * result + mConfigChanges; @@ -177,8 +184,11 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { @Override public String toString() { - return "ActivityRelaunchItem{pendingResults=" + mPendingResults - + ",pendingNewIntents=" + mPendingNewIntents + ",configChanges=" + mConfigChanges - + ",config=" + mConfig + ",preserveWindow" + mPreserveWindow + "}"; + return "ActivityRelaunchItem{" + super.toString() + + ",pendingResults=" + mPendingResults + + ",pendingNewIntents=" + mPendingNewIntents + + ",configChanges=" + mConfigChanges + + ",config=" + mConfig + + ",preserveWindow" + mPreserveWindow + "}"; } } diff --git a/core/java/android/app/servertransaction/ActivityResultItem.java b/core/java/android/app/servertransaction/ActivityResultItem.java index 27d104b59284..24fced4981d6 100644 --- a/core/java/android/app/servertransaction/ActivityResultItem.java +++ b/core/java/android/app/servertransaction/ActivityResultItem.java @@ -30,6 +30,7 @@ import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; +import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.Trace; @@ -61,24 +62,26 @@ public class ActivityResultItem extends ActivityTransactionItem { } @Override - public void execute(ClientTransactionHandler client, ActivityClientRecord r, - PendingTransactionActions pendingActions) { + public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r, + @NonNull PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDeliverResult"); client.handleSendResult(r, mResultInfoList, "ACTIVITY_RESULT"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } - // ObjectPoolItem implementation private ActivityResultItem() {} /** Obtain an instance initialized with provided params. */ - public static ActivityResultItem obtain(List<ResultInfo> resultInfoList) { + @NonNull + public static ActivityResultItem obtain(@NonNull IBinder activityToken, + @NonNull List<ResultInfo> resultInfoList) { ActivityResultItem instance = ObjectPool.obtain(ActivityResultItem.class); if (instance == null) { instance = new ActivityResultItem(); } + instance.setActivityToken(activityToken); instance.mResultInfoList = resultInfoList; return instance; @@ -86,41 +89,43 @@ public class ActivityResultItem extends ActivityTransactionItem { @Override public void recycle() { + super.recycle(); mResultInfoList = null; ObjectPool.recycle(this); } - // Parcelable implementation /** Write to Parcel. */ @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { + super.writeToParcel(dest, flags); dest.writeTypedList(mResultInfoList, flags); } /** Read from Parcel. */ - private ActivityResultItem(Parcel in) { + private ActivityResultItem(@NonNull Parcel in) { + super(in); mResultInfoList = in.createTypedArrayList(ResultInfo.CREATOR); } public static final @NonNull Parcelable.Creator<ActivityResultItem> CREATOR = - new Parcelable.Creator<ActivityResultItem>() { - public ActivityResultItem createFromParcel(Parcel in) { - return new ActivityResultItem(in); - } + new Parcelable.Creator<>() { + public ActivityResultItem createFromParcel(@NonNull Parcel in) { + return new ActivityResultItem(in); + } - public ActivityResultItem[] newArray(int size) { - return new ActivityResultItem[size]; - } - }; + public ActivityResultItem[] newArray(int size) { + return new ActivityResultItem[size]; + } + }; @Override public boolean equals(@Nullable Object o) { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if (!super.equals(o)) { return false; } final ActivityResultItem other = (ActivityResultItem) o; @@ -129,11 +134,15 @@ public class ActivityResultItem extends ActivityTransactionItem { @Override public int hashCode() { - return mResultInfoList.hashCode(); + int result = 17; + result = 31 * result + super.hashCode(); + result = 31 * result + Objects.hashCode(mResultInfoList); + return result; } @Override public String toString() { - return "ActivityResultItem{resultInfoList=" + mResultInfoList + "}"; + return "ActivityResultItem{" + super.toString() + + ",resultInfoList=" + mResultInfoList + "}"; } } diff --git a/core/java/android/app/servertransaction/ActivityTransactionItem.java b/core/java/android/app/servertransaction/ActivityTransactionItem.java index 469a9bfe59ef..0f8879e1429b 100644 --- a/core/java/android/app/servertransaction/ActivityTransactionItem.java +++ b/core/java/android/app/servertransaction/ActivityTransactionItem.java @@ -18,13 +18,18 @@ package android.app.servertransaction; import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; +import android.annotation.CallSuper; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.os.IBinder; +import android.os.Parcel; import com.android.internal.annotations.VisibleForTesting; +import java.util.Objects; + /** * An activity-targeting callback message to a client that can be scheduled and executed. * It also provides nullity-free version of @@ -37,11 +42,16 @@ import com.android.internal.annotations.VisibleForTesting; * @hide */ public abstract class ActivityTransactionItem extends ClientTransactionItem { - @Override - public final void execute(ClientTransactionHandler client, IBinder token, - PendingTransactionActions pendingActions) { - final ActivityClientRecord r = getActivityClientRecord(client, token); + /** Target client activity. */ + private IBinder mActivityToken; + + ActivityTransactionItem() {} + + @Override + public final void execute(@NonNull ClientTransactionHandler client, @NonNull IBinder token, + @NonNull PendingTransactionActions pendingActions) { + final ActivityClientRecord r = getActivityClientRecord(client); execute(client, r, pendingActions); } @@ -51,25 +61,80 @@ public abstract class ActivityTransactionItem extends ClientTransactionItem { */ @VisibleForTesting(visibility = PACKAGE) public abstract void execute(@NonNull ClientTransactionHandler client, - @NonNull ActivityClientRecord r, PendingTransactionActions pendingActions); + @NonNull ActivityClientRecord r, @NonNull PendingTransactionActions pendingActions); /** - * Gets the {@link ActivityClientRecord} instance that corresponds to the provided token. + * Gets the {@link ActivityClientRecord} instance that this transaction item is for. * @param client Target client handler. - * @param token Target activity token. - * @return The {@link ActivityClientRecord} instance that corresponds to the provided token. + * @return The {@link ActivityClientRecord} instance that this transaction item is for. */ - @NonNull ActivityClientRecord getActivityClientRecord( - @NonNull ClientTransactionHandler client, IBinder token) { - final ActivityClientRecord r = client.getActivityClient(token); + @NonNull + final ActivityClientRecord getActivityClientRecord(@NonNull ClientTransactionHandler client) { + final ActivityClientRecord r = client.getActivityClient(getActivityToken()); if (r == null) { throw new IllegalArgumentException("Activity client record must not be null to execute " + "transaction item: " + this); } - if (client.getActivity(token) == null) { + if (client.getActivity(getActivityToken()) == null) { throw new IllegalArgumentException("Activity must not be null to execute " + "transaction item: " + this); } return r; } + + @VisibleForTesting(visibility = PACKAGE) + @NonNull + @Override + public IBinder getActivityToken() { + return mActivityToken; + } + + void setActivityToken(@NonNull IBinder activityToken) { + mActivityToken = activityToken; + } + + // To be overridden + + ActivityTransactionItem(@NonNull Parcel in) { + mActivityToken = in.readStrongBinder(); + } + + @CallSuper + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeStrongBinder(mActivityToken); + } + + @CallSuper + @Override + public void recycle() { + mActivityToken = null; + } + + // Subclass must override and call super.equals to compare the mActivityToken. + @SuppressWarnings("EqualsGetClass") + @CallSuper + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final ActivityTransactionItem other = (ActivityTransactionItem) o; + return Objects.equals(mActivityToken, other.mActivityToken); + } + + @CallSuper + @Override + public int hashCode() { + return Objects.hashCode(mActivityToken); + } + + @CallSuper + @Override + public String toString() { + return "mActivityToken=" + mActivityToken; + } } diff --git a/core/java/android/app/servertransaction/ClientTransactionItem.java b/core/java/android/app/servertransaction/ClientTransactionItem.java index fe75d89e1257..30fc104a71b7 100644 --- a/core/java/android/app/servertransaction/ClientTransactionItem.java +++ b/core/java/android/app/servertransaction/ClientTransactionItem.java @@ -19,6 +19,8 @@ package android.app.servertransaction; import static android.app.servertransaction.ActivityLifecycleItem.LifecycleState; import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED; +import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ClientTransactionHandler; @@ -26,13 +28,15 @@ import android.content.Context; import android.os.IBinder; import android.os.Parcelable; +import com.android.internal.annotations.VisibleForTesting; + /** * A callback message to a client that can be scheduled and executed. * Examples of these might be activity configuration change, multi-window mode change, activity * result delivery etc. * * @see ClientTransaction - * @see com.android.server.am.ClientLifecycleManager + * @see com.android.server.wm.ClientLifecycleManager * @hide */ public abstract class ClientTransactionItem implements BaseClientRequest, Parcelable { @@ -57,6 +61,16 @@ public abstract class ClientTransactionItem implements BaseClientRequest, Parcel return null; } + /** + * Returns the activity token if this transaction item is activity-targeting. Otherwise, + * returns {@code null}. + */ + @VisibleForTesting(visibility = PACKAGE) + @Nullable + public IBinder getActivityToken() { + return null; + } + // Parcelable @Override diff --git a/core/java/android/app/servertransaction/DestroyActivityItem.java b/core/java/android/app/servertransaction/DestroyActivityItem.java index a074286a4ecd..a327a99435ce 100644 --- a/core/java/android/app/servertransaction/DestroyActivityItem.java +++ b/core/java/android/app/servertransaction/DestroyActivityItem.java @@ -36,13 +36,13 @@ public class DestroyActivityItem extends ActivityLifecycleItem { private int mConfigChanges; @Override - public void preExecute(ClientTransactionHandler client, IBinder token) { - client.getActivitiesToBeDestroyed().put(token, this); + public void preExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token) { + client.getActivitiesToBeDestroyed().put(getActivityToken(), this); } @Override - public void execute(ClientTransactionHandler client, ActivityClientRecord r, - PendingTransactionActions pendingActions) { + public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r, + @NonNull PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy"); client.handleDestroyActivity(r, mFinished, mConfigChanges, false /* getNonConfigInstance */, "DestroyActivityItem"); @@ -54,17 +54,19 @@ public class DestroyActivityItem extends ActivityLifecycleItem { return ON_DESTROY; } - // ObjectPoolItem implementation private DestroyActivityItem() {} /** Obtain an instance initialized with provided params. */ - public static DestroyActivityItem obtain(boolean finished, int configChanges) { + @NonNull + public static DestroyActivityItem obtain(@NonNull IBinder activityToken, boolean finished, + int configChanges) { DestroyActivityItem instance = ObjectPool.obtain(DestroyActivityItem.class); if (instance == null) { instance = new DestroyActivityItem(); } + instance.setActivityToken(activityToken); instance.mFinished = finished; instance.mConfigChanges = configChanges; @@ -79,25 +81,25 @@ public class DestroyActivityItem extends ActivityLifecycleItem { ObjectPool.recycle(this); } - // Parcelable implementation /** Write to Parcel. */ @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { + super.writeToParcel(dest, flags); dest.writeBoolean(mFinished); dest.writeInt(mConfigChanges); } /** Read from Parcel. */ - private DestroyActivityItem(Parcel in) { + private DestroyActivityItem(@NonNull Parcel in) { + super(in); mFinished = in.readBoolean(); mConfigChanges = in.readInt(); } - public static final @NonNull Creator<DestroyActivityItem> CREATOR = - new Creator<DestroyActivityItem>() { - public DestroyActivityItem createFromParcel(Parcel in) { + public static final @NonNull Creator<DestroyActivityItem> CREATOR = new Creator<>() { + public DestroyActivityItem createFromParcel(@NonNull Parcel in) { return new DestroyActivityItem(in); } @@ -111,7 +113,7 @@ public class DestroyActivityItem extends ActivityLifecycleItem { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if (!super.equals(o)) { return false; } final DestroyActivityItem other = (DestroyActivityItem) o; @@ -121,6 +123,7 @@ public class DestroyActivityItem extends ActivityLifecycleItem { @Override public int hashCode() { int result = 17; + result = 31 * result + super.hashCode(); result = 31 * result + (mFinished ? 1 : 0); result = 31 * result + mConfigChanges; return result; @@ -128,7 +131,8 @@ public class DestroyActivityItem extends ActivityLifecycleItem { @Override public String toString() { - return "DestroyActivityItem{finished=" + mFinished + ",mConfigChanges=" - + mConfigChanges + "}"; + return "DestroyActivityItem{" + super.toString() + + ",finished=" + mFinished + + ",mConfigChanges=" + mConfigChanges + "}"; } } diff --git a/core/java/android/app/servertransaction/EnterPipRequestedItem.java b/core/java/android/app/servertransaction/EnterPipRequestedItem.java index 7dcae654e1d0..743653f4896e 100644 --- a/core/java/android/app/servertransaction/EnterPipRequestedItem.java +++ b/core/java/android/app/servertransaction/EnterPipRequestedItem.java @@ -16,9 +16,10 @@ package android.app.servertransaction; -import android.annotation.Nullable; +import android.annotation.NonNull; import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; +import android.os.IBinder; import android.os.Parcel; /** @@ -28,8 +29,8 @@ import android.os.Parcel; public final class EnterPipRequestedItem extends ActivityTransactionItem { @Override - public void execute(ClientTransactionHandler client, ActivityClientRecord r, - PendingTransactionActions pendingActions) { + public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r, + @NonNull PendingTransactionActions pendingActions) { client.handlePictureInPictureRequested(r); } @@ -38,28 +39,32 @@ public final class EnterPipRequestedItem extends ActivityTransactionItem { private EnterPipRequestedItem() {} /** Obtain an instance initialized with provided params. */ - public static EnterPipRequestedItem obtain() { + @NonNull + public static EnterPipRequestedItem obtain(@NonNull IBinder activityToken) { EnterPipRequestedItem instance = ObjectPool.obtain(EnterPipRequestedItem.class); if (instance == null) { instance = new EnterPipRequestedItem(); } + instance.setActivityToken(activityToken); return instance; } @Override public void recycle() { + super.recycle(); ObjectPool.recycle(this); } // Parcelable implementation - @Override - public void writeToParcel(Parcel dest, int flags) { } + private EnterPipRequestedItem(@NonNull Parcel in) { + super(in); + } - public static final @android.annotation.NonNull Creator<EnterPipRequestedItem> CREATOR = - new Creator<EnterPipRequestedItem>() { - public EnterPipRequestedItem createFromParcel(Parcel in) { - return new EnterPipRequestedItem(); + public static final @NonNull Creator<EnterPipRequestedItem> CREATOR = + new Creator<>() { + public EnterPipRequestedItem createFromParcel(@NonNull Parcel in) { + return new EnterPipRequestedItem(in); } public EnterPipRequestedItem[] newArray(int size) { @@ -68,12 +73,7 @@ public final class EnterPipRequestedItem extends ActivityTransactionItem { }; @Override - public boolean equals(@Nullable Object o) { - return this == o; - } - - @Override public String toString() { - return "EnterPipRequestedItem{}"; + return "EnterPipRequestedItem{" + super.toString() + "}"; } } diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java index 5833f1b87254..9b37a35cdb8f 100644 --- a/core/java/android/app/servertransaction/LaunchActivityItem.java +++ b/core/java/android/app/servertransaction/LaunchActivityItem.java @@ -18,6 +18,8 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; +import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityClient; @@ -39,6 +41,7 @@ import android.os.Parcel; import android.os.PersistableBundle; import android.os.Trace; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; import com.android.internal.content.ReferrerIntent; @@ -51,6 +54,7 @@ import java.util.Objects; */ public class LaunchActivityItem extends ClientTransactionItem { + private IBinder mActivityToken; @UnsupportedAppUsage private Intent mIntent; private int mIdent; @@ -80,7 +84,7 @@ public class LaunchActivityItem extends ClientTransactionItem { private IActivityClientController mActivityClientController; @Override - public void preExecute(ClientTransactionHandler client, IBinder token) { + public void preExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token) { client.countLaunchingActivities(1); client.updateProcessState(mProcState, false); CompatibilityInfo.applyOverrideScaleIfNeeded(mCurConfig); @@ -92,10 +96,10 @@ public class LaunchActivityItem extends ClientTransactionItem { } @Override - public void execute(ClientTransactionHandler client, IBinder token, - PendingTransactionActions pendingActions) { + public void execute(@NonNull ClientTransactionHandler client, @NonNull IBinder token, + @NonNull PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); - ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo, + ActivityClientRecord r = new ActivityClientRecord(mActivityToken, mIntent, mIdent, mInfo, mOverrideConfig, mReferrer, mVoiceInteractor, mState, mPersistentState, mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo, client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble, @@ -105,31 +109,34 @@ public class LaunchActivityItem extends ClientTransactionItem { } @Override - public void postExecute(ClientTransactionHandler client, IBinder token, - PendingTransactionActions pendingActions) { + public void postExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token, + @NonNull PendingTransactionActions pendingActions) { client.countLaunchingActivities(-1); } - // ObjectPoolItem implementation private LaunchActivityItem() {} /** Obtain an instance initialized with provided params. */ - public static LaunchActivityItem obtain(Intent intent, int ident, ActivityInfo info, - Configuration curConfig, Configuration overrideConfig, int deviceId, - String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state, - PersistableBundle persistentState, List<ResultInfo> pendingResults, - List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions, - boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken, - IActivityClientController activityClientController, IBinder shareableActivityToken, - boolean launchedFromBubble, IBinder taskFragmentToken) { + @NonNull + public static LaunchActivityItem obtain(@NonNull IBinder activityToken, @NonNull Intent intent, + int ident, @NonNull ActivityInfo info, @NonNull Configuration curConfig, + @NonNull Configuration overrideConfig, int deviceId, @Nullable String referrer, + @Nullable IVoiceInteractor voiceInteractor, int procState, @Nullable Bundle state, + @Nullable PersistableBundle persistentState, @Nullable List<ResultInfo> pendingResults, + @Nullable List<ReferrerIntent> pendingNewIntents, + @Nullable ActivityOptions activityOptions, + boolean isForward, @Nullable ProfilerInfo profilerInfo, @NonNull IBinder assistToken, + @Nullable IActivityClientController activityClientController, + @NonNull IBinder shareableActivityToken, boolean launchedFromBubble, + @Nullable IBinder taskFragmentToken) { LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class); if (instance == null) { instance = new LaunchActivityItem(); } - setValues(instance, intent, ident, info, curConfig, overrideConfig, deviceId, referrer, - voiceInteractor, procState, state, persistentState, pendingResults, + setValues(instance, activityToken, intent, ident, info, curConfig, overrideConfig, deviceId, + referrer, voiceInteractor, procState, state, persistentState, pendingResults, pendingNewIntents, activityOptions, isForward, profilerInfo, assistToken, activityClientController, shareableActivityToken, launchedFromBubble, taskFragmentToken); @@ -137,19 +144,26 @@ public class LaunchActivityItem extends ClientTransactionItem { return instance; } + @VisibleForTesting(visibility = PACKAGE) + @NonNull + @Override + public IBinder getActivityToken() { + return mActivityToken; + } + @Override public void recycle() { - setValues(this, null, 0, null, null, null, 0, null, null, 0, null, null, null, null, + setValues(this, null, null, 0, null, null, null, 0, null, null, 0, null, null, null, null, null, false, null, null, null, null, false, null); ObjectPool.recycle(this); } - // Parcelable implementation /** Write from Parcel. */ @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeStrongBinder(mActivityToken); dest.writeTypedObject(mIntent, flags); dest.writeInt(mIdent); dest.writeTypedObject(mInfo, flags); @@ -174,8 +188,8 @@ public class LaunchActivityItem extends ClientTransactionItem { } /** Read from Parcel. */ - private LaunchActivityItem(Parcel in) { - setValues(this, in.readTypedObject(Intent.CREATOR), in.readInt(), + private LaunchActivityItem(@NonNull Parcel in) { + setValues(this, in.readStrongBinder(), in.readTypedObject(Intent.CREATOR), in.readInt(), in.readTypedObject(ActivityInfo.CREATOR), in.readTypedObject(Configuration.CREATOR), in.readTypedObject(Configuration.CREATOR), in.readInt(), in.readString(), IVoiceInteractor.Stub.asInterface(in.readStrongBinder()), in.readInt(), @@ -192,9 +206,8 @@ public class LaunchActivityItem extends ClientTransactionItem { in.readStrongBinder()); } - public static final @NonNull Creator<LaunchActivityItem> CREATOR = - new Creator<LaunchActivityItem>() { - public LaunchActivityItem createFromParcel(Parcel in) { + public static final @NonNull Creator<LaunchActivityItem> CREATOR = new Creator<>() { + public LaunchActivityItem createFromParcel(@NonNull Parcel in) { return new LaunchActivityItem(in); } @@ -214,7 +227,8 @@ public class LaunchActivityItem extends ClientTransactionItem { final LaunchActivityItem other = (LaunchActivityItem) o; final boolean intentsEqual = (mIntent == null && other.mIntent == null) || (mIntent != null && mIntent.filterEquals(other.mIntent)); - return intentsEqual && mIdent == other.mIdent + return intentsEqual + && Objects.equals(mActivityToken, other.mActivityToken) && mIdent == other.mIdent && activityInfoEqual(other.mInfo) && Objects.equals(mCurConfig, other.mCurConfig) && Objects.equals(mOverrideConfig, other.mOverrideConfig) && mDeviceId == other.mDeviceId @@ -234,6 +248,7 @@ public class LaunchActivityItem extends ClientTransactionItem { @Override public int hashCode() { int result = 17; + result = 31 * result + Objects.hashCode(mActivityToken); result = 31 * result + mIntent.filterHashCode(); result = 31 * result + mIdent; result = 31 * result + Objects.hashCode(mCurConfig); @@ -254,7 +269,7 @@ public class LaunchActivityItem extends ClientTransactionItem { return result; } - private boolean activityInfoEqual(ActivityInfo other) { + private boolean activityInfoEqual(@Nullable ActivityInfo other) { if (mInfo == null) { return other == null; } @@ -270,36 +285,51 @@ public class LaunchActivityItem extends ClientTransactionItem { * unparceling if a customized class loader is not set to the bundle. So the hash code is * simply determined by the bundle is empty or not. */ - private static int getRoughBundleHashCode(BaseBundle bundle) { + private static int getRoughBundleHashCode(@Nullable BaseBundle bundle) { return (bundle == null || bundle.isDefinitelyEmpty()) ? 0 : 1; } /** Compares the bundles without unparceling them (avoid BadParcelableException). */ - private static boolean areBundlesEqualRoughly(BaseBundle a, BaseBundle b) { + private static boolean areBundlesEqualRoughly(@Nullable BaseBundle a, @Nullable BaseBundle b) { return getRoughBundleHashCode(a) == getRoughBundleHashCode(b); } @Override public String toString() { - return "LaunchActivityItem{intent=" + mIntent + ",ident=" + mIdent + ",info=" + mInfo - + ",curConfig=" + mCurConfig + ",overrideConfig=" + mOverrideConfig - + ",deviceId=" + mDeviceId + ",referrer=" + mReferrer + ",procState=" + mProcState - + ",state=" + mState + ",persistentState=" + mPersistentState - + ",pendingResults=" + mPendingResults + ",pendingNewIntents=" + mPendingNewIntents - + ",options=" + mActivityOptions + ",profilerInfo=" + mProfilerInfo - + ",assistToken=" + mAssistToken + ",shareableActivityToken=" - + mShareableActivityToken + "}"; + return "LaunchActivityItem{activityToken=" + mActivityToken + + ",intent=" + mIntent + + ",ident=" + mIdent + + ",info=" + mInfo + + ",curConfig=" + mCurConfig + + ",overrideConfig=" + mOverrideConfig + + ",deviceId=" + mDeviceId + + ",referrer=" + mReferrer + + ",procState=" + mProcState + + ",state=" + mState + + ",persistentState=" + mPersistentState + + ",pendingResults=" + mPendingResults + + ",pendingNewIntents=" + mPendingNewIntents + + ",options=" + mActivityOptions + + ",profilerInfo=" + mProfilerInfo + + ",assistToken=" + mAssistToken + + ",shareableActivityToken=" + mShareableActivityToken + "}"; } // Using the same method to set and clear values to make sure we don't forget anything - private static void setValues(LaunchActivityItem instance, Intent intent, int ident, - ActivityInfo info, Configuration curConfig, Configuration overrideConfig, int deviceId, - String referrer, IVoiceInteractor voiceInteractor, - int procState, Bundle state, PersistableBundle persistentState, - List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, - ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo, - IBinder assistToken, IActivityClientController activityClientController, - IBinder shareableActivityToken, boolean launchedFromBubble, IBinder taskFragmentToken) { + private static void setValues(@Nullable LaunchActivityItem instance, + @Nullable IBinder activityToken, @Nullable Intent intent, int ident, + @Nullable ActivityInfo info, @Nullable Configuration curConfig, + @Nullable Configuration overrideConfig, int deviceId, + @Nullable String referrer, @Nullable IVoiceInteractor voiceInteractor, + int procState, @Nullable Bundle state, @Nullable PersistableBundle persistentState, + @Nullable List<ResultInfo> pendingResults, + @Nullable List<ReferrerIntent> pendingNewIntents, + @Nullable ActivityOptions activityOptions, boolean isForward, + @Nullable ProfilerInfo profilerInfo, @Nullable IBinder assistToken, + @Nullable IActivityClientController activityClientController, + @Nullable IBinder shareableActivityToken, boolean launchedFromBubble, + @Nullable IBinder taskFragmentToken) { + instance.mActivityToken = activityToken; instance.mIntent = intent; instance.mIdent = ident; instance.mInfo = info; diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java index f13bd748f486..fb57bed94160 100644 --- a/core/java/android/app/servertransaction/MoveToDisplayItem.java +++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java @@ -40,37 +40,34 @@ public class MoveToDisplayItem extends ActivityTransactionItem { private Configuration mConfiguration; @Override - public void preExecute(ClientTransactionHandler client, IBinder token) { + public void preExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token) { CompatibilityInfo.applyOverrideScaleIfNeeded(mConfiguration); // Notify the client of an upcoming change in the token configuration. This ensures that // batches of config change items only process the newest configuration. - client.updatePendingActivityConfiguration(token, mConfiguration); + client.updatePendingActivityConfiguration(getActivityToken(), mConfiguration); } @Override - public void execute(ClientTransactionHandler client, ActivityClientRecord r, - PendingTransactionActions pendingActions) { + public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r, + @NonNull PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityMovedToDisplay"); client.handleActivityConfigurationChanged(r, mConfiguration, mTargetDisplayId); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } - // ObjectPoolItem implementation private MoveToDisplayItem() {} /** Obtain an instance initialized with provided params. */ - public static MoveToDisplayItem obtain(int targetDisplayId, + @NonNull + public static MoveToDisplayItem obtain(@NonNull IBinder activityToken, int targetDisplayId, @NonNull Configuration configuration) { - if (configuration == null) { - throw new IllegalArgumentException("Configuration must not be null"); - } - MoveToDisplayItem instance = ObjectPool.obtain(MoveToDisplayItem.class); if (instance == null) { instance = new MoveToDisplayItem(); } + instance.setActivityToken(activityToken); instance.mTargetDisplayId = targetDisplayId; instance.mConfiguration = configuration; @@ -79,30 +76,31 @@ public class MoveToDisplayItem extends ActivityTransactionItem { @Override public void recycle() { + super.recycle(); mTargetDisplayId = 0; mConfiguration = Configuration.EMPTY; ObjectPool.recycle(this); } - // Parcelable implementation /** Write to Parcel. */ @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { + super.writeToParcel(dest, flags); dest.writeInt(mTargetDisplayId); dest.writeTypedObject(mConfiguration, flags); } /** Read from Parcel. */ - private MoveToDisplayItem(Parcel in) { + private MoveToDisplayItem(@NonNull Parcel in) { + super(in); mTargetDisplayId = in.readInt(); mConfiguration = in.readTypedObject(Configuration.CREATOR); } - public static final @NonNull Creator<MoveToDisplayItem> CREATOR = - new Creator<MoveToDisplayItem>() { - public MoveToDisplayItem createFromParcel(Parcel in) { + public static final @NonNull Creator<MoveToDisplayItem> CREATOR = new Creator<>() { + public MoveToDisplayItem createFromParcel(@NonNull Parcel in) { return new MoveToDisplayItem(in); } @@ -116,7 +114,7 @@ public class MoveToDisplayItem extends ActivityTransactionItem { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if (!super.equals(o)) { return false; } final MoveToDisplayItem other = (MoveToDisplayItem) o; @@ -127,6 +125,7 @@ public class MoveToDisplayItem extends ActivityTransactionItem { @Override public int hashCode() { int result = 17; + result = 31 * result + super.hashCode(); result = 31 * result + mTargetDisplayId; result = 31 * result + mConfiguration.hashCode(); return result; @@ -134,7 +133,8 @@ public class MoveToDisplayItem extends ActivityTransactionItem { @Override public String toString() { - return "MoveToDisplayItem{targetDisplayId=" + mTargetDisplayId + return "MoveToDisplayItem{" + super.toString() + + ",targetDisplayId=" + mTargetDisplayId + ",configuration=" + mConfiguration + "}"; } } diff --git a/core/java/android/app/servertransaction/NewIntentItem.java b/core/java/android/app/servertransaction/NewIntentItem.java index 723fa012c902..8e995aa05a48 100644 --- a/core/java/android/app/servertransaction/NewIntentItem.java +++ b/core/java/android/app/servertransaction/NewIntentItem.java @@ -25,6 +25,7 @@ import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; +import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.Trace; @@ -50,24 +51,26 @@ public class NewIntentItem extends ActivityTransactionItem { } @Override - public void execute(ClientTransactionHandler client, ActivityClientRecord r, - PendingTransactionActions pendingActions) { + public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r, + @NonNull PendingTransactionActions pendingActions) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityNewIntent"); client.handleNewIntent(r, mIntents); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } - // ObjectPoolItem implementation private NewIntentItem() {} /** Obtain an instance initialized with provided params. */ - public static NewIntentItem obtain(List<ReferrerIntent> intents, boolean resume) { + @NonNull + public static NewIntentItem obtain(@NonNull IBinder activityToken, + @NonNull List<ReferrerIntent> intents, boolean resume) { NewIntentItem instance = ObjectPool.obtain(NewIntentItem.class); if (instance == null) { instance = new NewIntentItem(); } + instance.setActivityToken(activityToken); instance.mIntents = intents; instance.mResume = resume; @@ -76,44 +79,46 @@ public class NewIntentItem extends ActivityTransactionItem { @Override public void recycle() { + super.recycle(); mIntents = null; mResume = false; ObjectPool.recycle(this); } - // Parcelable implementation /** Write to Parcel. */ @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { + super.writeToParcel(dest, flags); dest.writeBoolean(mResume); dest.writeTypedList(mIntents, flags); } /** Read from Parcel. */ - private NewIntentItem(Parcel in) { + private NewIntentItem(@NonNull Parcel in) { + super(in); mResume = in.readBoolean(); mIntents = in.createTypedArrayList(ReferrerIntent.CREATOR); } public static final @NonNull Parcelable.Creator<NewIntentItem> CREATOR = - new Parcelable.Creator<NewIntentItem>() { - public NewIntentItem createFromParcel(Parcel in) { - return new NewIntentItem(in); - } + new Parcelable.Creator<>() { + public NewIntentItem createFromParcel(@NonNull Parcel in) { + return new NewIntentItem(in); + } - public NewIntentItem[] newArray(int size) { - return new NewIntentItem[size]; - } - }; + public NewIntentItem[] newArray(int size) { + return new NewIntentItem[size]; + } + }; @Override public boolean equals(@Nullable Object o) { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if (!super.equals(o)) { return false; } final NewIntentItem other = (NewIntentItem) o; @@ -123,6 +128,7 @@ public class NewIntentItem extends ActivityTransactionItem { @Override public int hashCode() { int result = 17; + result = 31 * result + super.hashCode(); result = 31 * result + (mResume ? 1 : 0); result = 31 * result + mIntents.hashCode(); return result; @@ -130,6 +136,8 @@ public class NewIntentItem extends ActivityTransactionItem { @Override public String toString() { - return "NewIntentItem{intents=" + mIntents + ",resume=" + mResume + "}"; + return "NewIntentItem{" + super.toString() + + ",intents=" + mIntents + + ",resume=" + mResume + "}"; } } diff --git a/core/java/android/app/servertransaction/PauseActivityItem.java b/core/java/android/app/servertransaction/PauseActivityItem.java index 965e761ebfb3..a8e6772b4e32 100644 --- a/core/java/android/app/servertransaction/PauseActivityItem.java +++ b/core/java/android/app/servertransaction/PauseActivityItem.java @@ -42,8 +42,8 @@ public class PauseActivityItem extends ActivityLifecycleItem { private boolean mAutoEnteringPip; @Override - public void execute(ClientTransactionHandler client, ActivityClientRecord r, - PendingTransactionActions pendingActions) { + public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r, + @NonNull PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause"); client.handlePauseActivity(r, mFinished, mUserLeaving, mConfigChanges, mAutoEnteringPip, pendingActions, "PAUSE_ACTIVITY_ITEM"); @@ -56,27 +56,28 @@ public class PauseActivityItem extends ActivityLifecycleItem { } @Override - public void postExecute(ClientTransactionHandler client, IBinder token, - PendingTransactionActions pendingActions) { + public void postExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token, + @NonNull PendingTransactionActions pendingActions) { if (mDontReport) { return; } // TODO(lifecycler): Use interface callback instead of actual implementation. - ActivityClient.getInstance().activityPaused(token); + ActivityClient.getInstance().activityPaused(getActivityToken()); } - // ObjectPoolItem implementation private PauseActivityItem() {} /** Obtain an instance initialized with provided params. */ - public static PauseActivityItem obtain(boolean finished, boolean userLeaving, int configChanges, - boolean dontReport, boolean autoEnteringPip) { + @NonNull + public static PauseActivityItem obtain(@NonNull IBinder activityToken, boolean finished, + boolean userLeaving, int configChanges, boolean dontReport, boolean autoEnteringPip) { PauseActivityItem instance = ObjectPool.obtain(PauseActivityItem.class); if (instance == null) { instance = new PauseActivityItem(); } + instance.setActivityToken(activityToken); instance.mFinished = finished; instance.mUserLeaving = userLeaving; instance.mConfigChanges = configChanges; @@ -87,18 +88,10 @@ public class PauseActivityItem extends ActivityLifecycleItem { } /** Obtain an instance initialized with default params. */ - public static PauseActivityItem obtain() { - PauseActivityItem instance = ObjectPool.obtain(PauseActivityItem.class); - if (instance == null) { - instance = new PauseActivityItem(); - } - instance.mFinished = false; - instance.mUserLeaving = false; - instance.mConfigChanges = 0; - instance.mDontReport = true; - instance.mAutoEnteringPip = false; - - return instance; + @NonNull + public static PauseActivityItem obtain(@NonNull IBinder activityToken) { + return obtain(activityToken, false /* finished */, false /* userLeaving */, + 0 /* configChanges */, true /* dontReport */, false /* autoEnteringPip*/); } @Override @@ -116,7 +109,8 @@ public class PauseActivityItem extends ActivityLifecycleItem { /** Write to Parcel. */ @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { + super.writeToParcel(dest, flags); dest.writeBoolean(mFinished); dest.writeBoolean(mUserLeaving); dest.writeInt(mConfigChanges); @@ -125,7 +119,8 @@ public class PauseActivityItem extends ActivityLifecycleItem { } /** Read from Parcel. */ - private PauseActivityItem(Parcel in) { + private PauseActivityItem(@NonNull Parcel in) { + super(in); mFinished = in.readBoolean(); mUserLeaving = in.readBoolean(); mConfigChanges = in.readInt(); @@ -133,9 +128,8 @@ public class PauseActivityItem extends ActivityLifecycleItem { mAutoEnteringPip = in.readBoolean(); } - public static final @NonNull Creator<PauseActivityItem> CREATOR = - new Creator<PauseActivityItem>() { - public PauseActivityItem createFromParcel(Parcel in) { + public static final @NonNull Creator<PauseActivityItem> CREATOR = new Creator<>() { + public PauseActivityItem createFromParcel(@NonNull Parcel in) { return new PauseActivityItem(in); } @@ -149,7 +143,7 @@ public class PauseActivityItem extends ActivityLifecycleItem { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if (!super.equals(o)) { return false; } final PauseActivityItem other = (PauseActivityItem) o; @@ -161,6 +155,7 @@ public class PauseActivityItem extends ActivityLifecycleItem { @Override public int hashCode() { int result = 17; + result = 31 * result + super.hashCode(); result = 31 * result + (mFinished ? 1 : 0); result = 31 * result + (mUserLeaving ? 1 : 0); result = 31 * result + mConfigChanges; @@ -171,8 +166,11 @@ public class PauseActivityItem extends ActivityLifecycleItem { @Override public String toString() { - return "PauseActivityItem{finished=" + mFinished + ",userLeaving=" + mUserLeaving - + ",configChanges=" + mConfigChanges + ",dontReport=" + mDontReport + return "PauseActivityItem{" + super.toString() + + ",finished=" + mFinished + + ",userLeaving=" + mUserLeaving + + ",configChanges=" + mConfigChanges + + ",dontReport=" + mDontReport + ",autoEnteringPip=" + mAutoEnteringPip + "}"; } } diff --git a/core/java/android/app/servertransaction/PipStateTransactionItem.java b/core/java/android/app/servertransaction/PipStateTransactionItem.java index 167f5a43b1b1..30289ef9f794 100644 --- a/core/java/android/app/servertransaction/PipStateTransactionItem.java +++ b/core/java/android/app/servertransaction/PipStateTransactionItem.java @@ -16,12 +16,16 @@ package android.app.servertransaction; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.app.PictureInPictureUiState; +import android.os.IBinder; import android.os.Parcel; +import java.util.Objects; + /** * Request an activity to enter picture-in-picture mode. * @hide @@ -31,8 +35,8 @@ public final class PipStateTransactionItem extends ActivityTransactionItem { private PictureInPictureUiState mPipState; @Override - public void execute(ClientTransactionHandler client, ActivityClientRecord r, - PendingTransactionActions pendingActions) { + public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r, + @NonNull PendingTransactionActions pendingActions) { client.handlePictureInPictureStateChanged(r, mPipState); } @@ -41,11 +45,14 @@ public final class PipStateTransactionItem extends ActivityTransactionItem { private PipStateTransactionItem() {} /** Obtain an instance initialized with provided params. */ - public static PipStateTransactionItem obtain(PictureInPictureUiState pipState) { + @NonNull + public static PipStateTransactionItem obtain(@NonNull IBinder activityToken, + @NonNull PictureInPictureUiState pipState) { PipStateTransactionItem instance = ObjectPool.obtain(PipStateTransactionItem.class); if (instance == null) { instance = new PipStateTransactionItem(); } + instance.setActivityToken(activityToken); instance.mPipState = pipState; return instance; @@ -53,6 +60,7 @@ public final class PipStateTransactionItem extends ActivityTransactionItem { @Override public void recycle() { + super.recycle(); mPipState = null; ObjectPool.recycle(this); } @@ -61,33 +69,49 @@ public final class PipStateTransactionItem extends ActivityTransactionItem { /** Write to Parcel. */ @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { + super.writeToParcel(dest, flags); mPipState.writeToParcel(dest, flags); } /** Read from Parcel. */ - private PipStateTransactionItem(Parcel in) { + private PipStateTransactionItem(@NonNull Parcel in) { + super(in); mPipState = PictureInPictureUiState.CREATOR.createFromParcel(in); } - public static final @android.annotation.NonNull Creator<PipStateTransactionItem> CREATOR = - new Creator<PipStateTransactionItem>() { - public PipStateTransactionItem createFromParcel(Parcel in) { - return new PipStateTransactionItem(in); - } + public static final @NonNull Creator<PipStateTransactionItem> CREATOR = new Creator<>() { + public PipStateTransactionItem createFromParcel(@NonNull Parcel in) { + return new PipStateTransactionItem(in); + } - public PipStateTransactionItem[] newArray(int size) { - return new PipStateTransactionItem[size]; - } - }; + public PipStateTransactionItem[] newArray(int size) { + return new PipStateTransactionItem[size]; + } + }; @Override public boolean equals(@Nullable Object o) { - return this == o; + if (this == o) { + return true; + } + if (!super.equals(o)) { + return false; + } + final PipStateTransactionItem other = (PipStateTransactionItem) o; + return Objects.equals(mPipState, other.mPipState); + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + super.hashCode(); + result = 31 * result + Objects.hashCode(mPipState); + return result; } @Override public String toString() { - return "PipStateTransactionItem{}"; + return "PipStateTransactionItem{" + super.toString() + "}"; } } diff --git a/core/java/android/app/servertransaction/RefreshCallbackItem.java b/core/java/android/app/servertransaction/RefreshCallbackItem.java index 74abab22b0a6..00128f0d298f 100644 --- a/core/java/android/app/servertransaction/RefreshCallbackItem.java +++ b/core/java/android/app/servertransaction/RefreshCallbackItem.java @@ -48,12 +48,12 @@ public class RefreshCallbackItem extends ActivityTransactionItem { @Override public void execute(@NonNull ClientTransactionHandler client, - @NonNull ActivityClientRecord r, PendingTransactionActions pendingActions) {} + @NonNull ActivityClientRecord r, @NonNull PendingTransactionActions pendingActions) {} @Override - public void postExecute(ClientTransactionHandler client, IBinder token, - PendingTransactionActions pendingActions) { - final ActivityClientRecord r = getActivityClientRecord(client, token); + public void postExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token, + @NonNull PendingTransactionActions pendingActions) { + final ActivityClientRecord r = getActivityClientRecord(client); client.reportRefresh(r); } @@ -71,6 +71,7 @@ public class RefreshCallbackItem extends ActivityTransactionItem { @Override public void recycle() { + super.recycle(); ObjectPool.recycle(this); } @@ -79,7 +80,9 @@ public class RefreshCallbackItem extends ActivityTransactionItem { * @param postExecutionState indicating whether refresh should happen using the * "stopped -> resumed" cycle or "paused -> resumed" cycle. */ - public static RefreshCallbackItem obtain(@LifecycleState int postExecutionState) { + @NonNull + public static RefreshCallbackItem obtain(@NonNull IBinder activityToken, + @LifecycleState int postExecutionState) { if (postExecutionState != ON_STOP && postExecutionState != ON_PAUSE) { throw new IllegalArgumentException( "Only ON_STOP or ON_PAUSE are allowed as a post execution state for " @@ -90,6 +93,7 @@ public class RefreshCallbackItem extends ActivityTransactionItem { if (instance == null) { instance = new RefreshCallbackItem(); } + instance.setActivityToken(activityToken); instance.mPostExecutionState = postExecutionState; return instance; } @@ -99,7 +103,8 @@ public class RefreshCallbackItem extends ActivityTransactionItem { // Parcelable implementation @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { + super.writeToParcel(dest, flags); dest.writeInt(mPostExecutionState); } @@ -108,7 +113,7 @@ public class RefreshCallbackItem extends ActivityTransactionItem { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if (!super.equals(o)) { return false; } final RefreshCallbackItem other = (RefreshCallbackItem) o; @@ -118,23 +123,25 @@ public class RefreshCallbackItem extends ActivityTransactionItem { @Override public int hashCode() { int result = 17; + result = 31 * result + super.hashCode(); result = 31 * result + mPostExecutionState; return result; } @Override public String toString() { - return "RefreshCallbackItem{mPostExecutionState=" + mPostExecutionState + "}"; + return "RefreshCallbackItem{" + super.toString() + + ",mPostExecutionState=" + mPostExecutionState + "}"; } - private RefreshCallbackItem(Parcel in) { + private RefreshCallbackItem(@NonNull Parcel in) { + super(in); mPostExecutionState = in.readInt(); } - public static final @NonNull Creator<RefreshCallbackItem> CREATOR = - new Creator<RefreshCallbackItem>() { + public static final @NonNull Creator<RefreshCallbackItem> CREATOR = new Creator<>() { - public RefreshCallbackItem createFromParcel(Parcel in) { + public RefreshCallbackItem createFromParcel(@NonNull Parcel in) { return new RefreshCallbackItem(in); } diff --git a/core/java/android/app/servertransaction/ResumeActivityItem.java b/core/java/android/app/servertransaction/ResumeActivityItem.java index 222f8ca61e09..b11e73cbef96 100644 --- a/core/java/android/app/servertransaction/ResumeActivityItem.java +++ b/core/java/android/app/servertransaction/ResumeActivityItem.java @@ -44,15 +44,15 @@ public class ResumeActivityItem extends ActivityLifecycleItem { private boolean mShouldSendCompatFakeFocus; @Override - public void preExecute(ClientTransactionHandler client, IBinder token) { + public void preExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token) { if (mUpdateProcState) { client.updateProcessState(mProcState, false); } } @Override - public void execute(ClientTransactionHandler client, ActivityClientRecord r, - PendingTransactionActions pendingActions) { + public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r, + @NonNull PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume"); client.handleResumeActivity(r, true /* finalStateRequest */, mIsForward, mShouldSendCompatFakeFocus, "RESUME_ACTIVITY"); @@ -60,10 +60,11 @@ public class ResumeActivityItem extends ActivityLifecycleItem { } @Override - public void postExecute(ClientTransactionHandler client, IBinder token, - PendingTransactionActions pendingActions) { + public void postExecute(@NonNull ClientTransactionHandler client, IBinder token, + @NonNull PendingTransactionActions pendingActions) { // TODO(lifecycler): Use interface callback instead of actual implementation. - ActivityClient.getInstance().activityResumed(token, client.isHandleSplashScreenExit(token)); + ActivityClient.getInstance().activityResumed(getActivityToken(), + client.isHandleSplashScreenExit(getActivityToken())); } @Override @@ -71,18 +72,19 @@ public class ResumeActivityItem extends ActivityLifecycleItem { return ON_RESUME; } - // ObjectPoolItem implementation private ResumeActivityItem() {} /** Obtain an instance initialized with provided params. */ - public static ResumeActivityItem obtain(int procState, boolean isForward, - boolean shouldSendCompatFakeFocus) { + @NonNull + public static ResumeActivityItem obtain(@NonNull IBinder activityToken, int procState, + boolean isForward, boolean shouldSendCompatFakeFocus) { ResumeActivityItem instance = ObjectPool.obtain(ResumeActivityItem.class); if (instance == null) { instance = new ResumeActivityItem(); } + instance.setActivityToken(activityToken); instance.mProcState = procState; instance.mUpdateProcState = true; instance.mIsForward = isForward; @@ -92,11 +94,14 @@ public class ResumeActivityItem extends ActivityLifecycleItem { } /** Obtain an instance initialized with provided params. */ - public static ResumeActivityItem obtain(boolean isForward, boolean shouldSendCompatFakeFocus) { + @NonNull + public static ResumeActivityItem obtain(@NonNull IBinder activityToken, boolean isForward, + boolean shouldSendCompatFakeFocus) { ResumeActivityItem instance = ObjectPool.obtain(ResumeActivityItem.class); if (instance == null) { instance = new ResumeActivityItem(); } + instance.setActivityToken(activityToken); instance.mProcState = ActivityManager.PROCESS_STATE_UNKNOWN; instance.mUpdateProcState = false; instance.mIsForward = isForward; @@ -115,12 +120,12 @@ public class ResumeActivityItem extends ActivityLifecycleItem { ObjectPool.recycle(this); } - // Parcelable implementation /** Write to Parcel. */ @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { + super.writeToParcel(dest, flags); dest.writeInt(mProcState); dest.writeBoolean(mUpdateProcState); dest.writeBoolean(mIsForward); @@ -128,15 +133,15 @@ public class ResumeActivityItem extends ActivityLifecycleItem { } /** Read from Parcel. */ - private ResumeActivityItem(Parcel in) { + private ResumeActivityItem(@NonNull Parcel in) { + super(in); mProcState = in.readInt(); mUpdateProcState = in.readBoolean(); mIsForward = in.readBoolean(); mShouldSendCompatFakeFocus = in.readBoolean(); } - public static final @NonNull Creator<ResumeActivityItem> CREATOR = - new Creator<ResumeActivityItem>() { + public static final @NonNull Creator<ResumeActivityItem> CREATOR = new Creator<>() { public ResumeActivityItem createFromParcel(Parcel in) { return new ResumeActivityItem(in); } @@ -151,7 +156,7 @@ public class ResumeActivityItem extends ActivityLifecycleItem { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if (!super.equals(o)) { return false; } final ResumeActivityItem other = (ResumeActivityItem) o; @@ -163,6 +168,7 @@ public class ResumeActivityItem extends ActivityLifecycleItem { @Override public int hashCode() { int result = 17; + result = 31 * result + super.hashCode(); result = 31 * result + mProcState; result = 31 * result + (mUpdateProcState ? 1 : 0); result = 31 * result + (mIsForward ? 1 : 0); @@ -172,8 +178,10 @@ public class ResumeActivityItem extends ActivityLifecycleItem { @Override public String toString() { - return "ResumeActivityItem{procState=" + mProcState - + ",updateProcState=" + mUpdateProcState + ",isForward=" + mIsForward + return "ResumeActivityItem{" + super.toString() + + ",procState=" + mProcState + + ",updateProcState=" + mUpdateProcState + + ",isForward=" + mIsForward + ",shouldSendCompatFakeFocus=" + mShouldSendCompatFakeFocus + "}"; } } diff --git a/core/java/android/app/servertransaction/StartActivityItem.java b/core/java/android/app/servertransaction/StartActivityItem.java index 15f65f6d9d26..8b98b2184043 100644 --- a/core/java/android/app/servertransaction/StartActivityItem.java +++ b/core/java/android/app/servertransaction/StartActivityItem.java @@ -23,6 +23,7 @@ import android.annotation.Nullable; import android.app.ActivityOptions; import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; +import android.os.IBinder; import android.os.Parcel; import android.os.Trace; @@ -37,8 +38,8 @@ public class StartActivityItem extends ActivityLifecycleItem { private ActivityOptions mActivityOptions; @Override - public void execute(ClientTransactionHandler client, ActivityClientRecord r, - PendingTransactionActions pendingActions) { + public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r, + @NonNull PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "startActivityItem"); client.handleStartActivity(r, pendingActions, mActivityOptions); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); @@ -49,17 +50,19 @@ public class StartActivityItem extends ActivityLifecycleItem { return ON_START; } - // ObjectPoolItem implementation private StartActivityItem() {} /** Obtain an instance initialized with provided params. */ - public static StartActivityItem obtain(ActivityOptions activityOptions) { + @NonNull + public static StartActivityItem obtain(@NonNull IBinder activityToken, + @Nullable ActivityOptions activityOptions) { StartActivityItem instance = ObjectPool.obtain(StartActivityItem.class); if (instance == null) { instance = new StartActivityItem(); } + instance.setActivityToken(activityToken); instance.mActivityOptions = activityOptions; return instance; @@ -72,37 +75,37 @@ public class StartActivityItem extends ActivityLifecycleItem { ObjectPool.recycle(this); } - // Parcelable implementation /** Write to Parcel. */ @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { + super.writeToParcel(dest, flags); dest.writeBundle(mActivityOptions != null ? mActivityOptions.toBundle() : null); } /** Read from Parcel. */ - private StartActivityItem(Parcel in) { + private StartActivityItem(@NonNull Parcel in) { + super(in); mActivityOptions = ActivityOptions.fromBundle(in.readBundle()); } - public static final @NonNull Creator<StartActivityItem> CREATOR = - new Creator<StartActivityItem>() { - public StartActivityItem createFromParcel(Parcel in) { - return new StartActivityItem(in); - } + public static final @NonNull Creator<StartActivityItem> CREATOR = new Creator<>() { + public StartActivityItem createFromParcel(@NonNull Parcel in) { + return new StartActivityItem(in); + } - public StartActivityItem[] newArray(int size) { - return new StartActivityItem[size]; - } - }; + public StartActivityItem[] newArray(int size) { + return new StartActivityItem[size]; + } + }; @Override public boolean equals(@Nullable Object o) { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if (!super.equals(o)) { return false; } final StartActivityItem other = (StartActivityItem) o; @@ -112,13 +115,15 @@ public class StartActivityItem extends ActivityLifecycleItem { @Override public int hashCode() { int result = 17; + result = 31 * result + super.hashCode(); result = 31 * result + (mActivityOptions != null ? 1 : 0); return result; } @Override public String toString() { - return "StartActivityItem{options=" + mActivityOptions + "}"; + return "StartActivityItem{" + super.toString() + + ",options=" + mActivityOptions + "}"; } } diff --git a/core/java/android/app/servertransaction/StopActivityItem.java b/core/java/android/app/servertransaction/StopActivityItem.java index 7e9116dfdfc7..f4325670c4fc 100644 --- a/core/java/android/app/servertransaction/StopActivityItem.java +++ b/core/java/android/app/servertransaction/StopActivityItem.java @@ -37,8 +37,8 @@ public class StopActivityItem extends ActivityLifecycleItem { private int mConfigChanges; @Override - public void execute(ClientTransactionHandler client, ActivityClientRecord r, - PendingTransactionActions pendingActions) { + public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r, + @NonNull PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop"); client.handleStopActivity(r, mConfigChanges, pendingActions, true /* finalStateRequest */, "STOP_ACTIVITY_ITEM"); @@ -46,8 +46,8 @@ public class StopActivityItem extends ActivityLifecycleItem { } @Override - public void postExecute(ClientTransactionHandler client, IBinder token, - PendingTransactionActions pendingActions) { + public void postExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token, + @NonNull PendingTransactionActions pendingActions) { client.reportStop(pendingActions); } @@ -56,20 +56,22 @@ public class StopActivityItem extends ActivityLifecycleItem { return ON_STOP; } - // ObjectPoolItem implementation private StopActivityItem() {} /** * Obtain an instance initialized with provided params. + * @param activityToken the activity that stops. * @param configChanges Configuration pieces that changed. */ - public static StopActivityItem obtain(int configChanges) { + @NonNull + public static StopActivityItem obtain(@NonNull IBinder activityToken, int configChanges) { StopActivityItem instance = ObjectPool.obtain(StopActivityItem.class); if (instance == null) { instance = new StopActivityItem(); } + instance.setActivityToken(activityToken); instance.mConfigChanges = configChanges; return instance; @@ -82,23 +84,23 @@ public class StopActivityItem extends ActivityLifecycleItem { ObjectPool.recycle(this); } - // Parcelable implementation /** Write to Parcel. */ @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { + super.writeToParcel(dest, flags); dest.writeInt(mConfigChanges); } /** Read from Parcel. */ - private StopActivityItem(Parcel in) { + private StopActivityItem(@NonNull Parcel in) { + super(in); mConfigChanges = in.readInt(); } - public static final @NonNull Creator<StopActivityItem> CREATOR = - new Creator<StopActivityItem>() { - public StopActivityItem createFromParcel(Parcel in) { + public static final @NonNull Creator<StopActivityItem> CREATOR = new Creator<>() { + public StopActivityItem createFromParcel(@NonNull Parcel in) { return new StopActivityItem(in); } @@ -112,7 +114,7 @@ public class StopActivityItem extends ActivityLifecycleItem { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if (!super.equals(o)) { return false; } final StopActivityItem other = (StopActivityItem) o; @@ -122,12 +124,14 @@ public class StopActivityItem extends ActivityLifecycleItem { @Override public int hashCode() { int result = 17; + result = 31 * result + super.hashCode(); result = 31 * result + mConfigChanges; return result; } @Override public String toString() { - return "StopActivityItem{configChanges=" + mConfigChanges + "}"; + return "StopActivityItem{" + super.toString() + + ",configChanges=" + mConfigChanges + "}"; } } diff --git a/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java b/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java index 5cd3d68f0326..693599fa229c 100644 --- a/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java +++ b/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java @@ -35,16 +35,16 @@ public class TopResumedActivityChangeItem extends ActivityTransactionItem { private boolean mOnTop; @Override - public void execute(ClientTransactionHandler client, ActivityClientRecord r, - PendingTransactionActions pendingActions) { + public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r, + @NonNull PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "topResumedActivityChangeItem"); client.handleTopResumedActivityChanged(r, mOnTop, "topResumedActivityChangeItem"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @Override - public void postExecute(ClientTransactionHandler client, IBinder token, - PendingTransactionActions pendingActions) { + public void postExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token, + @NonNull PendingTransactionActions pendingActions) { if (mOnTop) { return; } @@ -58,18 +58,20 @@ public class TopResumedActivityChangeItem extends ActivityTransactionItem { ActivityClient.getInstance().activityTopResumedStateLost(); } - // ObjectPoolItem implementation private TopResumedActivityChangeItem() {} /** Obtain an instance initialized with provided params. */ - public static TopResumedActivityChangeItem obtain(boolean onTop) { + @NonNull + public static TopResumedActivityChangeItem obtain(@NonNull IBinder activityToken, + boolean onTop) { TopResumedActivityChangeItem instance = ObjectPool.obtain(TopResumedActivityChangeItem.class); if (instance == null) { instance = new TopResumedActivityChangeItem(); } + instance.setActivityToken(activityToken); instance.mOnTop = onTop; return instance; @@ -77,27 +79,28 @@ public class TopResumedActivityChangeItem extends ActivityTransactionItem { @Override public void recycle() { + super.recycle(); mOnTop = false; ObjectPool.recycle(this); } - // Parcelable implementation /** Write to Parcel. */ @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { + super.writeToParcel(dest, flags); dest.writeBoolean(mOnTop); } /** Read from Parcel. */ - private TopResumedActivityChangeItem(Parcel in) { + private TopResumedActivityChangeItem(@NonNull Parcel in) { + super(in); mOnTop = in.readBoolean(); } - public static final @NonNull Creator<TopResumedActivityChangeItem> CREATOR = - new Creator<TopResumedActivityChangeItem>() { - public TopResumedActivityChangeItem createFromParcel(Parcel in) { + public static final @NonNull Creator<TopResumedActivityChangeItem> CREATOR = new Creator<>() { + public TopResumedActivityChangeItem createFromParcel(@NonNull Parcel in) { return new TopResumedActivityChangeItem(in); } @@ -111,7 +114,7 @@ public class TopResumedActivityChangeItem extends ActivityTransactionItem { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if (!super.equals(o)) { return false; } final TopResumedActivityChangeItem other = (TopResumedActivityChangeItem) o; @@ -121,12 +124,14 @@ public class TopResumedActivityChangeItem extends ActivityTransactionItem { @Override public int hashCode() { int result = 17; + result = 31 * result + super.hashCode(); result = 31 * result + (mOnTop ? 1 : 0); return result; } @Override public String toString() { - return "TopResumedActivityChangeItem{onTop=" + mOnTop + "}"; + return "TopResumedActivityChangeItem{" + super.toString() + + ",onTop=" + mOnTop + "}"; } } diff --git a/core/java/android/app/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java index baf2a4722dff..0f9c517e2916 100644 --- a/core/java/android/app/servertransaction/TransactionExecutorHelper.java +++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java @@ -196,13 +196,13 @@ public class TransactionExecutorHelper { // Fall through to return the PAUSE item to ensure the activity is properly // resumed while relaunching. case ON_PAUSE: - lifecycleItem = PauseActivityItem.obtain(); + lifecycleItem = PauseActivityItem.obtain(r.token); break; case ON_STOP: - lifecycleItem = StopActivityItem.obtain(0 /* configChanges */); + lifecycleItem = StopActivityItem.obtain(r.token, 0 /* configChanges */); break; default: - lifecycleItem = ResumeActivityItem.obtain(false /* isForward */, + lifecycleItem = ResumeActivityItem.obtain(r.token, false /* isForward */, false /* shouldSendCompatFakeFocus */); break; } diff --git a/core/java/android/app/servertransaction/TransferSplashScreenViewStateItem.java b/core/java/android/app/servertransaction/TransferSplashScreenViewStateItem.java index 767fd28b8a2a..11947e9b11d8 100644 --- a/core/java/android/app/servertransaction/TransferSplashScreenViewStateItem.java +++ b/core/java/android/app/servertransaction/TransferSplashScreenViewStateItem.java @@ -20,10 +20,13 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityThread; import android.app.ClientTransactionHandler; +import android.os.IBinder; import android.os.Parcel; import android.view.SurfaceControl; import android.window.SplashScreenView.SplashScreenViewParcelable; +import java.util.Objects; + /** * Transfer a splash screen view to an Activity. * @hide @@ -36,36 +39,44 @@ public class TransferSplashScreenViewStateItem extends ActivityTransactionItem { @Override public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityThread.ActivityClientRecord r, - PendingTransactionActions pendingActions) { + @NonNull PendingTransactionActions pendingActions) { client.handleAttachSplashScreenView(r, mSplashScreenViewParcelable, mStartingWindowLeash); } @Override public void recycle() { + super.recycle(); + mSplashScreenViewParcelable = null; + mStartingWindowLeash = null; ObjectPool.recycle(this); } @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { + super.writeToParcel(dest, flags); dest.writeTypedObject(mSplashScreenViewParcelable, flags); dest.writeTypedObject(mStartingWindowLeash, flags); } private TransferSplashScreenViewStateItem() {} - private TransferSplashScreenViewStateItem(Parcel in) { + + private TransferSplashScreenViewStateItem(@NonNull Parcel in) { + super(in); mSplashScreenViewParcelable = in.readTypedObject(SplashScreenViewParcelable.CREATOR); mStartingWindowLeash = in.readTypedObject(SurfaceControl.CREATOR); } /** Obtain an instance initialized with provided params. */ + @NonNull public static TransferSplashScreenViewStateItem obtain( - @Nullable SplashScreenViewParcelable parcelable, + @NonNull IBinder activityToken, @Nullable SplashScreenViewParcelable parcelable, @Nullable SurfaceControl startingWindowLeash) { TransferSplashScreenViewStateItem instance = ObjectPool.obtain(TransferSplashScreenViewStateItem.class); if (instance == null) { instance = new TransferSplashScreenViewStateItem(); } + instance.setActivityToken(activityToken); instance.mSplashScreenViewParcelable = parcelable; instance.mStartingWindowLeash = startingWindowLeash; @@ -73,8 +84,8 @@ public class TransferSplashScreenViewStateItem extends ActivityTransactionItem { } public static final @NonNull Creator<TransferSplashScreenViewStateItem> CREATOR = - new Creator<TransferSplashScreenViewStateItem>() { - public TransferSplashScreenViewStateItem createFromParcel(Parcel in) { + new Creator<>() { + public TransferSplashScreenViewStateItem createFromParcel(@NonNull Parcel in) { return new TransferSplashScreenViewStateItem(in); } @@ -82,4 +93,33 @@ public class TransferSplashScreenViewStateItem extends ActivityTransactionItem { return new TransferSplashScreenViewStateItem[size]; } }; + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (!super.equals(o)) { + return false; + } + final TransferSplashScreenViewStateItem other = (TransferSplashScreenViewStateItem) o; + return Objects.equals(mSplashScreenViewParcelable, other.mSplashScreenViewParcelable) + && Objects.equals(mStartingWindowLeash, other.mStartingWindowLeash); + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + super.hashCode(); + result = 31 * result + Objects.hashCode(mSplashScreenViewParcelable); + result = 31 * result + Objects.hashCode(mStartingWindowLeash); + return result; + } + + @Override + public String toString() { + return "TransferSplashScreenViewStateItem{" + super.toString() + + ",splashScreenViewParcelable=" + mSplashScreenViewParcelable + + ",startingWindowLeash=" + mStartingWindowLeash + "}"; + } } diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java index 3aa287724263..2fb428b3e0b4 100644 --- a/core/java/android/companion/CompanionDeviceManager.java +++ b/core/java/android/companion/CompanionDeviceManager.java @@ -39,6 +39,7 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; +import android.companion.datatransfer.PermissionSyncRequest; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -180,7 +181,7 @@ public final class CompanionDeviceManager { public @interface DataSyncTypes {} /** - * Used by {@link #enableSystemDataSync(int, int)}}. + * Used by {@link #enableSystemDataSyncForTypes(int, int)}}. * Sync call metadata like muting, ending and silencing a call. * */ @@ -552,6 +553,39 @@ public final class CompanionDeviceManager { } /** + * @hide + */ + public void enablePermissionsSync(int associationId) { + try { + mService.enablePermissionsSync(associationId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public void disablePermissionsSync(int associationId) { + try { + mService.disablePermissionsSync(associationId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public PermissionSyncRequest getPermissionSyncRequest(int associationId) { + try { + return mService.getPermissionSyncRequest(associationId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * <p>Calling this API requires a uses-feature * {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} declaration in the manifest</p> * diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl index a3b202aa738d..c5a19888205c 100644 --- a/core/java/android/companion/ICompanionDeviceManager.aidl +++ b/core/java/android/companion/ICompanionDeviceManager.aidl @@ -24,6 +24,7 @@ import android.companion.IOnTransportsChangedListener; import android.companion.ISystemDataTransferCallback; import android.companion.AssociationInfo; import android.companion.AssociationRequest; +import android.companion.datatransfer.PermissionSyncRequest; import android.content.ComponentName; /** @@ -113,6 +114,12 @@ interface ICompanionDeviceManager { void disableSystemDataSync(int associationId, int flags); + void enablePermissionsSync(int associationId); + + void disablePermissionsSync(int associationId); + + PermissionSyncRequest getPermissionSyncRequest(int associationId); + @EnforcePermission("MANAGE_COMPANION_DEVICES") void enableSecureTransport(boolean enabled); diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index f1ae9be8528d..582c5c0c4dd4 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -4139,13 +4139,13 @@ public class InputMethodService extends AbstractInputMethodService { p.println(" mExtractedToken=" + mExtractedToken); p.println(" mIsInputViewShown=" + mIsInputViewShown + " mStatusIcon=" + mStatusIcon); - p.println("Last computed insets:"); - p.println(" contentTopInsets=" + mTmpInsets.contentTopInsets + p.println(" Last computed insets:"); + p.println(" contentTopInsets=" + mTmpInsets.contentTopInsets + " visibleTopInsets=" + mTmpInsets.visibleTopInsets + " touchableInsets=" + mTmpInsets.touchableInsets + " touchableRegion=" + mTmpInsets.touchableRegion); - p.println(" mSettingsObserver=" + mSettingsObserver); - p.println(" mNavigationBarController=" + mNavigationBarController.toDebugString()); + p.println(" mSettingsObserver=" + mSettingsObserver); + p.println(" mNavigationBarController=" + mNavigationBarController.toDebugString()); } private final ImeTracing.ServiceDumper mDumper = new ImeTracing.ServiceDumper() { diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig index 03063d00bac1..febe6f719baf 100644 --- a/core/java/android/os/flags.aconfig +++ b/core/java/android/os/flags.aconfig @@ -13,3 +13,10 @@ flag { description: "Replaces background PSS collection in AppProfiler with RSS" bug: "297542292" } + +flag { + name: "allow_private_profile" + namespace: "private_profile" + description: "Guards a new Private Profile type in UserManager - everything from its setup to config to deletion." + bug: "299069460" +} diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 637770c4fb21..04ae0aff10d0 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -2556,7 +2556,7 @@ public abstract class WallpaperService extends Service { private void doDetachEngine() { // Some wallpapers will not trigger the rendering threads of the remaining engines even // if they are visible, so we need to toggle the state to get their attention. - if (!mEngine.mDestroyed) { + if (mEngine != null && !mEngine.mDestroyed) { mEngine.detach(); synchronized (mActiveEngines) { for (IWallpaperEngineWrapper engineWrapper : mActiveEngines.values()) { diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java index 2761aaeb4a7d..bc837501037f 100644 --- a/core/java/android/view/InputWindowHandle.java +++ b/core/java/android/view/InputWindowHandle.java @@ -35,6 +35,8 @@ import java.lang.ref.WeakReference; * @hide */ public final class InputWindowHandle { + // TODO (b/300094445): Convert to use correct flagging infrastructure + public static final boolean USE_SURFACE_TRUSTED_OVERLAY = true; /** * An internal annotation for all the {@link android.os.InputConfig} flags that can be @@ -59,7 +61,6 @@ public final class InputWindowHandle { InputConfig.DUPLICATE_TOUCH_TO_WALLPAPER, InputConfig.IS_WALLPAPER, InputConfig.PAUSE_DISPATCHING, - InputConfig.TRUSTED_OVERLAY, InputConfig.WATCH_OUTSIDE_TOUCH, InputConfig.SLIPPERY, InputConfig.DISABLE_USER_ACTIVITY, @@ -272,4 +273,13 @@ public final class InputWindowHandle { } this.inputConfig &= ~inputConfig; } + + public void setTrustedOverlay(SurfaceControl.Transaction t, SurfaceControl sc, + boolean isTrusted) { + if (USE_SURFACE_TRUSTED_OVERLAY) { + t.setTrustedOverlay(sc, isTrusted); + } else if (isTrusted) { + inputConfig |= InputConfig.TRUSTED_OVERLAY; + } + } } diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig new file mode 100644 index 000000000000..f1d981ac5b4b --- /dev/null +++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig @@ -0,0 +1,8 @@ +package: "com.android.window.flags" + +flag { + name: "letterbox_background_wallpaper_flag" + namespace: "large_screen_experiences_app_compat" + description: "Whether the letterbox wallpaper style is enabled by default" + bug: "297195682" +} diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java index 1ed06b4eac3e..1bfb51cc4b82 100644 --- a/core/java/com/android/internal/jank/InteractionJankMonitor.java +++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java @@ -70,7 +70,6 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_CLEAR_ALL; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_DIALOG_OPEN; -import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_EXPAND_FROM_STATUS_BAR; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_APPEAR; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_DISAPPEAR; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_NOTIFICATION_ADD; @@ -269,7 +268,6 @@ public class InteractionJankMonitor { * eg: Exit the app using back gesture. */ public static final int CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK = 78; - public static final int CUJ_SHADE_EXPAND_FROM_STATUS_BAR = 79; public static final int CUJ_IME_INSETS_SHOW_ANIMATION = 80; public static final int CUJ_IME_INSETS_HIDE_ANIMATION = 81; @@ -364,7 +362,7 @@ public class InteractionJankMonitor { CUJ_TO_STATSD_INTERACTION_TYPE[76] = NO_STATSD_LOGGING; CUJ_TO_STATSD_INTERACTION_TYPE[77] = NO_STATSD_LOGGING; CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK; - CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SHADE_EXPAND_FROM_STATUS_BAR] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_EXPAND_FROM_STATUS_BAR; + CUJ_TO_STATSD_INTERACTION_TYPE[79] = NO_STATSD_LOGGING; // This is deprecated. CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_IME_INSETS_SHOW_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_SHOW_ANIMATION; CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_IME_INSETS_HIDE_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_HIDE_ANIMATION; CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_DOUBLE_TAP_DIVIDER; @@ -467,7 +465,6 @@ public class InteractionJankMonitor { CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION, CUJ_LAUNCHER_OPEN_SEARCH_RESULT, CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK, - CUJ_SHADE_EXPAND_FROM_STATUS_BAR, CUJ_IME_INSETS_SHOW_ANIMATION, CUJ_IME_INSETS_HIDE_ANIMATION, CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER, @@ -1082,8 +1079,6 @@ public class InteractionJankMonitor { return "LAUNCHER_OPEN_SEARCH_RESULT"; case CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK: return "LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK"; - case CUJ_SHADE_EXPAND_FROM_STATUS_BAR: - return "SHADE_EXPAND_FROM_STATUS_BAR"; case CUJ_IME_INSETS_SHOW_ANIMATION: return "IME_INSETS_SHOW_ANIMATION"; case CUJ_IME_INSETS_HIDE_ANIMATION: diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java index 819178f40451..89355072e29e 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java @@ -245,7 +245,7 @@ public class ActivityThreadTest { newConfig.smallestScreenWidthDp++; transaction = newTransaction(activityThread, activity.getActivityToken()); transaction.addCallback(ActivityConfigurationChangeItem.obtain( - new Configuration(newConfig))); + activity.getActivityToken(), new Configuration(newConfig))); appThread.scheduleTransaction(transaction); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); @@ -450,10 +450,12 @@ public class ActivityThreadTest { appThread.scheduleTransaction(transaction); transaction = newTransaction(activityThread, activity.getActivityToken()); - transaction.addCallback(ActivityConfigurationChangeItem.obtain(activityConfigLandscape)); + transaction.addCallback(ActivityConfigurationChangeItem.obtain( + activity.getActivityToken(), activityConfigLandscape)); transaction.addCallback(ConfigurationChangeItem.obtain( processConfigPortrait, DEVICE_ID_INVALID)); - transaction.addCallback(ActivityConfigurationChangeItem.obtain(activityConfigPortrait)); + transaction.addCallback(ActivityConfigurationChangeItem.obtain( + activity.getActivityToken(), activityConfigPortrait)); appThread.scheduleTransaction(transaction); activity.mTestLatch.await(TIMEOUT_SEC, TimeUnit.SECONDS); @@ -829,11 +831,12 @@ public class ActivityThreadTest { private static ClientTransaction newRelaunchResumeTransaction(Activity activity) { final Configuration currentConfig = activity.getResources().getConfiguration(); - final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null, - null, 0, new MergedConfiguration(currentConfig, currentConfig), + final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain( + activity.getActivityToken(), null, null, 0, + new MergedConfiguration(currentConfig, currentConfig), false /* preserveWindow */); final ResumeActivityItem resumeStateRequest = - ResumeActivityItem.obtain(true /* isForward */, + ResumeActivityItem.obtain(activity.getActivityToken(), true /* isForward */, false /* shouldSendCompatFakeFocus*/); final ClientTransaction transaction = newTransaction(activity); @@ -845,7 +848,7 @@ public class ActivityThreadTest { private static ClientTransaction newResumeTransaction(Activity activity) { final ResumeActivityItem resumeStateRequest = - ResumeActivityItem.obtain(true /* isForward */, + ResumeActivityItem.obtain(activity.getActivityToken(), true /* isForward */, false /* shouldSendCompatFakeFocus */); final ClientTransaction transaction = newTransaction(activity); @@ -855,7 +858,8 @@ public class ActivityThreadTest { } private static ClientTransaction newStopTransaction(Activity activity) { - final StopActivityItem stopStateRequest = StopActivityItem.obtain(0 /* configChanges */); + final StopActivityItem stopStateRequest = StopActivityItem.obtain( + activity.getActivityToken(), 0 /* configChanges */); final ClientTransaction transaction = newTransaction(activity); transaction.setLifecycleStateRequest(stopStateRequest); @@ -865,7 +869,8 @@ public class ActivityThreadTest { private static ClientTransaction newActivityConfigTransaction(Activity activity, Configuration config) { - final ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain(config); + final ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain( + activity.getActivityToken(), config); final ClientTransaction transaction = newTransaction(activity); transaction.addCallback(item); @@ -875,7 +880,8 @@ public class ActivityThreadTest { private static ClientTransaction newNewIntentTransaction(Activity activity, List<ReferrerIntent> intents, boolean resume) { - final NewIntentItem item = NewIntentItem.obtain(intents, resume); + final NewIntentItem item = NewIntentItem.obtain(activity.getActivityToken(), intents, + resume); final ClientTransaction transaction = newTransaction(activity); transaction.addCallback(item); diff --git a/core/tests/coretests/src/android/app/servertransaction/ActivityConfigurationChangeItemTest.java b/core/tests/coretests/src/android/app/servertransaction/ActivityConfigurationChangeItemTest.java index 1560c0c2c195..08033cc4009c 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ActivityConfigurationChangeItemTest.java +++ b/core/tests/coretests/src/android/app/servertransaction/ActivityConfigurationChangeItemTest.java @@ -65,7 +65,7 @@ public class ActivityConfigurationChangeItemTest { doReturn(mActivity).when(mHandler).getActivity(mToken); final ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem - .obtain(mConfiguration); + .obtain(mToken, mConfiguration); final Context context = item.getContextToUpdate(mHandler, mToken); assertEquals(mActivity, context); diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java index ca6735bc6c32..c8d8f4be9e0a 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java @@ -22,7 +22,6 @@ import static android.app.servertransaction.TestUtils.referrerIntentList; import static android.app.servertransaction.TestUtils.resultInfoList; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; @@ -61,39 +60,44 @@ import java.util.function.Supplier; @Presubmit public class ObjectPoolTests { + private final IBinder mActivityToken = new Binder(); + // 1. Check if two obtained objects from pool are not the same. // 2. Check if the state of the object is cleared after recycling. // 3. Check if the same object is obtained from pool after recycling. @Test public void testRecycleActivityConfigurationChangeItem() { - ActivityConfigurationChangeItem emptyItem = - ActivityConfigurationChangeItem.obtain(Configuration.EMPTY); - ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain(config()); + ActivityConfigurationChangeItem emptyItem = ActivityConfigurationChangeItem.obtain( + null /* activityToken */, Configuration.EMPTY); + ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain( + mActivityToken, config()); assertNotSame(item, emptyItem); - assertFalse(item.equals(emptyItem)); + assertNotEquals(item, emptyItem); item.recycle(); assertEquals(item, emptyItem); - ActivityConfigurationChangeItem item2 = ActivityConfigurationChangeItem.obtain(config()); + ActivityConfigurationChangeItem item2 = ActivityConfigurationChangeItem.obtain( + mActivityToken, config()); assertSame(item, item2); - assertFalse(item2.equals(emptyItem)); + assertNotEquals(item2, emptyItem); } @Test public void testRecycleActivityResultItem() { - ActivityResultItem emptyItem = ActivityResultItem.obtain(null); - ActivityResultItem item = ActivityResultItem.obtain(resultInfoList()); + ActivityResultItem emptyItem = ActivityResultItem.obtain( + null /* activityToken */, null /* resultInfoList */); + ActivityResultItem item = ActivityResultItem.obtain(mActivityToken, resultInfoList()); assertNotSame(item, emptyItem); - assertFalse(item.equals(emptyItem)); + assertNotEquals(item, emptyItem); item.recycle(); assertEquals(item, emptyItem); - ActivityResultItem item2 = ActivityResultItem.obtain(resultInfoList()); + ActivityResultItem item2 = ActivityResultItem.obtain(mActivityToken, resultInfoList()); assertSame(item, item2); - assertFalse(item2.equals(emptyItem)); + assertNotEquals(item2, emptyItem); } @Test @@ -101,166 +105,188 @@ public class ObjectPoolTests { ConfigurationChangeItem emptyItem = ConfigurationChangeItem.obtain(null, 0); ConfigurationChangeItem item = ConfigurationChangeItem.obtain(config(), 1); assertNotSame(item, emptyItem); - assertFalse(item.equals(emptyItem)); + assertNotEquals(item, emptyItem); item.recycle(); assertEquals(item, emptyItem); ConfigurationChangeItem item2 = ConfigurationChangeItem.obtain(config(), 1); assertSame(item, item2); - assertFalse(item2.equals(emptyItem)); + assertNotEquals(item2, emptyItem); } @Test public void testRecycleDestroyActivityItem() { - DestroyActivityItem emptyItem = DestroyActivityItem.obtain(false, 0); - DestroyActivityItem item = DestroyActivityItem.obtain(true, 117); + DestroyActivityItem emptyItem = DestroyActivityItem.obtain( + null /* activityToken */, false, 0); + DestroyActivityItem item = DestroyActivityItem.obtain(mActivityToken, true, 117); assertNotSame(item, emptyItem); - assertFalse(item.equals(emptyItem)); + assertNotEquals(item, emptyItem); item.recycle(); assertEquals(item, emptyItem); - DestroyActivityItem item2 = DestroyActivityItem.obtain(true, 14); + DestroyActivityItem item2 = DestroyActivityItem.obtain(mActivityToken, true, 14); assertSame(item, item2); - assertFalse(item2.equals(emptyItem)); + assertNotEquals(item2, emptyItem); } @Test public void testRecycleLaunchActivityItem() { - Intent intent = new Intent("action"); + final IBinder activityToken = new Binder(); + final Intent intent = new Intent("action"); int ident = 57; - ActivityInfo activityInfo = new ActivityInfo(); + final ActivityInfo activityInfo = new ActivityInfo(); activityInfo.flags = 42; activityInfo.setMaxAspectRatio(2.4f); activityInfo.launchToken = "token"; activityInfo.applicationInfo = new ApplicationInfo(); activityInfo.packageName = "packageName"; activityInfo.name = "name"; - Configuration overrideConfig = new Configuration(); + final Configuration overrideConfig = new Configuration(); overrideConfig.assetsSeq = 5; - String referrer = "referrer"; + final String referrer = "referrer"; int procState = 4; - Bundle bundle = new Bundle(); + final Bundle bundle = new Bundle(); bundle.putString("key", "value"); - PersistableBundle persistableBundle = new PersistableBundle(); + final PersistableBundle persistableBundle = new PersistableBundle(); persistableBundle.putInt("k", 4); - IBinder assistToken = new Binder(); - IBinder shareableActivityToken = new Binder(); + final IBinder assistToken = new Binder(); + final IBinder shareableActivityToken = new Binder(); int deviceId = 3; - Supplier<LaunchActivityItem> itemSupplier = () -> new LaunchActivityItemBuilder() - .setIntent(intent).setIdent(ident).setInfo(activityInfo).setCurConfig(config()) - .setOverrideConfig(overrideConfig).setReferrer(referrer) - .setProcState(procState).setState(bundle).setPersistentState(persistableBundle) - .setPendingResults(resultInfoList()).setPendingNewIntents(referrerIntentList()) - .setIsForward(true).setAssistToken(assistToken) + final Supplier<LaunchActivityItem> itemSupplier = () -> new LaunchActivityItemBuilder() + .setActivityToken(activityToken) + .setIntent(intent) + .setIdent(ident) + .setInfo(activityInfo) + .setCurConfig(config()) + .setOverrideConfig(overrideConfig) + .setReferrer(referrer) + .setProcState(procState) + .setState(bundle) + .setPersistentState(persistableBundle) + .setPendingResults(resultInfoList()) + .setPendingNewIntents(referrerIntentList()) + .setIsForward(true) + .setAssistToken(assistToken) .setShareableActivityToken(shareableActivityToken) - .setTaskFragmentToken(new Binder()).setDeviceId(deviceId).build(); + .setTaskFragmentToken(new Binder()) + .setDeviceId(deviceId) + .build(); LaunchActivityItem emptyItem = new LaunchActivityItemBuilder().build(); LaunchActivityItem item = itemSupplier.get(); assertNotSame(item, emptyItem); - assertFalse(item.equals(emptyItem)); + assertNotEquals(item, emptyItem); item.recycle(); assertEquals(item, emptyItem); LaunchActivityItem item2 = itemSupplier.get(); assertSame(item, item2); - assertFalse(item2.equals(emptyItem)); + assertNotEquals(item2, emptyItem); } @Test public void testRecycleActivityRelaunchItem() { - ActivityRelaunchItem emptyItem = ActivityRelaunchItem.obtain(null, null, 0, null, false); + ActivityRelaunchItem emptyItem = ActivityRelaunchItem.obtain( + null /* activityToken */, null, null, 0, null, false); Configuration overrideConfig = new Configuration(); overrideConfig.assetsSeq = 5; - ActivityRelaunchItem item = ActivityRelaunchItem.obtain(resultInfoList(), + ActivityRelaunchItem item = ActivityRelaunchItem.obtain(mActivityToken, resultInfoList(), referrerIntentList(), 42, mergedConfig(), true); assertNotSame(item, emptyItem); - assertFalse(item.equals(emptyItem)); + assertNotEquals(item, emptyItem); item.recycle(); assertEquals(item, emptyItem); - ActivityRelaunchItem item2 = ActivityRelaunchItem.obtain(resultInfoList(), + ActivityRelaunchItem item2 = ActivityRelaunchItem.obtain(mActivityToken, resultInfoList(), referrerIntentList(), 42, mergedConfig(), true); assertSame(item, item2); - assertFalse(item2.equals(emptyItem)); + assertNotEquals(item2, emptyItem); } @Test public void testRecycleMoveToDisplayItem() { - MoveToDisplayItem emptyItem = MoveToDisplayItem.obtain(0, Configuration.EMPTY); - MoveToDisplayItem item = MoveToDisplayItem.obtain(4, config()); + MoveToDisplayItem emptyItem = MoveToDisplayItem.obtain( + null /* activityToken */, 0, Configuration.EMPTY); + MoveToDisplayItem item = MoveToDisplayItem.obtain(mActivityToken, 4, config()); assertNotSame(item, emptyItem); - assertFalse(item.equals(emptyItem)); + assertNotEquals(item, emptyItem); item.recycle(); assertEquals(item, emptyItem); - MoveToDisplayItem item2 = MoveToDisplayItem.obtain(3, config()); + MoveToDisplayItem item2 = MoveToDisplayItem.obtain(mActivityToken, 3, config()); assertSame(item, item2); - assertFalse(item2.equals(emptyItem)); + assertNotEquals(item2, emptyItem); } @Test public void testRecycleNewIntentItem() { - NewIntentItem emptyItem = NewIntentItem.obtain(null, false); - NewIntentItem item = NewIntentItem.obtain(referrerIntentList(), false); + NewIntentItem emptyItem = NewIntentItem.obtain( + null /* activityToken */, null /* intents */, false /* resume */); + NewIntentItem item = NewIntentItem.obtain(mActivityToken, referrerIntentList(), false); assertNotSame(item, emptyItem); - assertFalse(item.equals(emptyItem)); + assertNotEquals(item, emptyItem); item.recycle(); assertEquals(item, emptyItem); - NewIntentItem item2 = NewIntentItem.obtain(referrerIntentList(), false); + NewIntentItem item2 = NewIntentItem.obtain(mActivityToken, referrerIntentList(), false); assertSame(item, item2); - assertFalse(item2.equals(emptyItem)); + assertNotEquals(item2, emptyItem); } @Test public void testRecyclePauseActivityItemItem() { - PauseActivityItem emptyItem = PauseActivityItem.obtain(false, false, 0, false, false); - PauseActivityItem item = PauseActivityItem.obtain(true, true, 5, true, true); + PauseActivityItem emptyItem = PauseActivityItem.obtain( + null /* activityToken */, false, false, 0, false, false); + PauseActivityItem item = PauseActivityItem.obtain( + mActivityToken, true, true, 5, true, true); assertNotSame(item, emptyItem); - assertFalse(item.equals(emptyItem)); + assertNotEquals(item, emptyItem); item.recycle(); assertEquals(item, emptyItem); - PauseActivityItem item2 = PauseActivityItem.obtain(true, false, 5, true, true); + PauseActivityItem item2 = PauseActivityItem.obtain( + mActivityToken, true, false, 5, true, true); assertSame(item, item2); - assertFalse(item2.equals(emptyItem)); + assertNotEquals(item2, emptyItem); } @Test public void testRecycleResumeActivityItem() { - ResumeActivityItem emptyItem = ResumeActivityItem.obtain(false, false); - ResumeActivityItem item = ResumeActivityItem.obtain(3, true, false); + ResumeActivityItem emptyItem = ResumeActivityItem.obtain( + null /* activityToken */, false, false); + ResumeActivityItem item = ResumeActivityItem.obtain(mActivityToken, 3, true, false); assertNotSame(item, emptyItem); - assertFalse(item.equals(emptyItem)); + assertNotEquals(item, emptyItem); item.recycle(); assertEquals(item, emptyItem); - ResumeActivityItem item2 = ResumeActivityItem.obtain(2, true, false); + ResumeActivityItem item2 = ResumeActivityItem.obtain(mActivityToken, 2, true, false); assertSame(item, item2); - assertFalse(item2.equals(emptyItem)); + assertNotEquals(item2, emptyItem); } @Test public void testRecycleStartActivityItem() { - StartActivityItem emptyItem = StartActivityItem.obtain(null /* activityOptions */); - StartActivityItem item = StartActivityItem.obtain(ActivityOptions.makeBasic()); + StartActivityItem emptyItem = StartActivityItem.obtain( + null /* activityToken */, null /* activityOptions */); + StartActivityItem item = StartActivityItem.obtain(mActivityToken, + ActivityOptions.makeBasic()); assertNotSame(item, emptyItem); assertNotEquals(item, emptyItem); item.recycle(); assertEquals(item, emptyItem); - StartActivityItem item2 = StartActivityItem.obtain( + StartActivityItem item2 = StartActivityItem.obtain(mActivityToken, ActivityOptions.makeBasic().setLaunchDisplayId(10)); assertSame(item, item2); assertNotEquals(item2, emptyItem); @@ -268,17 +294,17 @@ public class ObjectPoolTests { @Test public void testRecycleStopItem() { - StopActivityItem emptyItem = StopActivityItem.obtain(0); - StopActivityItem item = StopActivityItem.obtain(4); + StopActivityItem emptyItem = StopActivityItem.obtain(null /* activityToken */, 0); + StopActivityItem item = StopActivityItem.obtain(mActivityToken, 4); assertNotSame(item, emptyItem); - assertFalse(item.equals(emptyItem)); + assertNotEquals(item, emptyItem); item.recycle(); assertEquals(item, emptyItem); - StopActivityItem item2 = StopActivityItem.obtain(3); + StopActivityItem item2 = StopActivityItem.obtain(mActivityToken, 3); assertSame(item, item2); - assertFalse(item2.equals(emptyItem)); + assertNotEquals(item2, emptyItem); } @Test @@ -286,13 +312,13 @@ public class ObjectPoolTests { ClientTransaction emptyItem = ClientTransaction.obtain(null, null); ClientTransaction item = ClientTransaction.obtain(null, new Binder()); assertNotSame(item, emptyItem); - assertFalse(item.equals(emptyItem)); + assertNotEquals(item, emptyItem); item.recycle(); assertEquals(item, emptyItem); ClientTransaction item2 = ClientTransaction.obtain(null, new Binder()); assertSame(item, item2); - assertFalse(item2.equals(emptyItem)); + assertNotEquals(item2, emptyItem); } } diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java index 0ed6a29cdd9d..5a88bad37d5f 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java +++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java @@ -18,6 +18,8 @@ package android.app.servertransaction; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityOptions; import android.app.ProfilerInfo; import android.app.ResultInfo; @@ -90,129 +92,175 @@ class TestUtils { } static class LaunchActivityItemBuilder { + @Nullable + private IBinder mActivityToken; + @Nullable private Intent mIntent; private int mIdent; + @Nullable private ActivityInfo mInfo; + @Nullable private Configuration mCurConfig; + @Nullable private Configuration mOverrideConfig; private int mDeviceId; + @Nullable private String mReferrer; + @Nullable private IVoiceInteractor mVoiceInteractor; private int mProcState; + @Nullable private Bundle mState; + @Nullable private PersistableBundle mPersistentState; + @Nullable private List<ResultInfo> mPendingResults; + @Nullable private List<ReferrerIntent> mPendingNewIntents; + @Nullable private ActivityOptions mActivityOptions; private boolean mIsForward; + @Nullable private ProfilerInfo mProfilerInfo; + @Nullable private IBinder mAssistToken; + @Nullable private IBinder mShareableActivityToken; private boolean mLaunchedFromBubble; + @Nullable private IBinder mTaskFragmentToken; - LaunchActivityItemBuilder setIntent(Intent intent) { + @NonNull + LaunchActivityItemBuilder setActivityToken(@Nullable IBinder activityToken) { + mActivityToken = activityToken; + return this; + } + + @NonNull + LaunchActivityItemBuilder setIntent(@Nullable Intent intent) { mIntent = intent; return this; } + @NonNull LaunchActivityItemBuilder setIdent(int ident) { mIdent = ident; return this; } - LaunchActivityItemBuilder setInfo(ActivityInfo info) { + @NonNull + LaunchActivityItemBuilder setInfo(@Nullable ActivityInfo info) { mInfo = info; return this; } - LaunchActivityItemBuilder setCurConfig(Configuration curConfig) { + @NonNull + LaunchActivityItemBuilder setCurConfig(@Nullable Configuration curConfig) { mCurConfig = curConfig; return this; } - LaunchActivityItemBuilder setOverrideConfig(Configuration overrideConfig) { + @NonNull + LaunchActivityItemBuilder setOverrideConfig(@Nullable Configuration overrideConfig) { mOverrideConfig = overrideConfig; return this; } + @NonNull LaunchActivityItemBuilder setDeviceId(int deviceId) { mDeviceId = deviceId; return this; } - LaunchActivityItemBuilder setReferrer(String referrer) { + @NonNull + LaunchActivityItemBuilder setReferrer(@Nullable String referrer) { mReferrer = referrer; return this; } - LaunchActivityItemBuilder setVoiceInteractor(IVoiceInteractor voiceInteractor) { + @NonNull + LaunchActivityItemBuilder setVoiceInteractor(@Nullable IVoiceInteractor voiceInteractor) { mVoiceInteractor = voiceInteractor; return this; } + @NonNull LaunchActivityItemBuilder setProcState(int procState) { mProcState = procState; return this; } - LaunchActivityItemBuilder setState(Bundle state) { + @NonNull + LaunchActivityItemBuilder setState(@Nullable Bundle state) { mState = state; return this; } - LaunchActivityItemBuilder setPersistentState(PersistableBundle persistentState) { + @NonNull + LaunchActivityItemBuilder setPersistentState(@Nullable PersistableBundle persistentState) { mPersistentState = persistentState; return this; } - LaunchActivityItemBuilder setPendingResults(List<ResultInfo> pendingResults) { + @NonNull + LaunchActivityItemBuilder setPendingResults(@Nullable List<ResultInfo> pendingResults) { mPendingResults = pendingResults; return this; } - LaunchActivityItemBuilder setPendingNewIntents(List<ReferrerIntent> pendingNewIntents) { + @NonNull + LaunchActivityItemBuilder setPendingNewIntents( + @Nullable List<ReferrerIntent> pendingNewIntents) { mPendingNewIntents = pendingNewIntents; return this; } - LaunchActivityItemBuilder setActivityOptions(ActivityOptions activityOptions) { + @NonNull + LaunchActivityItemBuilder setActivityOptions(@Nullable ActivityOptions activityOptions) { mActivityOptions = activityOptions; return this; } + @NonNull LaunchActivityItemBuilder setIsForward(boolean isForward) { mIsForward = isForward; return this; } - LaunchActivityItemBuilder setProfilerInfo(ProfilerInfo profilerInfo) { + @NonNull + LaunchActivityItemBuilder setProfilerInfo(@Nullable ProfilerInfo profilerInfo) { mProfilerInfo = profilerInfo; return this; } - LaunchActivityItemBuilder setAssistToken(IBinder assistToken) { + @NonNull + LaunchActivityItemBuilder setAssistToken(@Nullable IBinder assistToken) { mAssistToken = assistToken; return this; } - LaunchActivityItemBuilder setShareableActivityToken(IBinder shareableActivityToken) { + @NonNull + LaunchActivityItemBuilder setShareableActivityToken( + @Nullable IBinder shareableActivityToken) { mShareableActivityToken = shareableActivityToken; return this; } + @NonNull LaunchActivityItemBuilder setLaunchedFromBubble(boolean launchedFromBubble) { mLaunchedFromBubble = launchedFromBubble; return this; } - LaunchActivityItemBuilder setTaskFragmentToken(IBinder taskFragmentToken) { + @NonNull + LaunchActivityItemBuilder setTaskFragmentToken(@Nullable IBinder taskFragmentToken) { mTaskFragmentToken = taskFragmentToken; return this; } + @NonNull LaunchActivityItem build() { - return LaunchActivityItem.obtain(mIntent, mIdent, mInfo, + return LaunchActivityItem.obtain(mActivityToken, mIntent, mIdent, mInfo, mCurConfig, mOverrideConfig, mDeviceId, mReferrer, mVoiceInteractor, mProcState, mState, mPersistentState, mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo, mAssistToken, diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java index 32f892924ac5..a998b26b09c1 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java @@ -227,6 +227,7 @@ public class TransactionExecutorTests { when(callback2.getPostExecutionState()).thenReturn(UNDEFINED); ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class); IBinder token = mock(IBinder.class); + when(stateRequest.getActivityToken()).thenReturn(token); when(mTransactionHandler.getActivity(token)).thenReturn(mock(Activity.class)); ClientTransaction transaction = ClientTransaction.obtain(null /* client */, @@ -256,7 +257,7 @@ public class TransactionExecutorTests { final ClientTransaction destroyTransaction = ClientTransaction.obtain(null /* client */, token /* activityToken */); destroyTransaction.setLifecycleStateRequest( - DestroyActivityItem.obtain(false /* finished */, 0 /* configChanges */)); + DestroyActivityItem.obtain(token, false /* finished */, 0 /* configChanges */)); destroyTransaction.preExecute(mTransactionHandler); // The activity should be added to to-be-destroyed container. assertEquals(1, mTransactionHandler.getActivitiesToBeDestroyed().size()); @@ -264,7 +265,8 @@ public class TransactionExecutorTests { // A previous queued launch transaction runs on main thread (execute). final ClientTransaction launchTransaction = ClientTransaction.obtain(null /* client */, token /* activityToken */); - final LaunchActivityItem launchItem = spy(new LaunchActivityItemBuilder().build()); + final LaunchActivityItem launchItem = + spy(new LaunchActivityItemBuilder().setActivityToken(token).build()); launchTransaction.addCallback(launchItem); mExecutor.execute(launchTransaction); @@ -450,9 +452,11 @@ public class TransactionExecutorTests { final ClientTransaction transaction = ClientTransaction.obtain(null /* client */, token); final ActivityTransactionItem activityItem = mock(ActivityTransactionItem.class); when(activityItem.getPostExecutionState()).thenReturn(UNDEFINED); + when(activityItem.getActivityToken()).thenReturn(token); transaction.addCallback(activityItem); final ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class); transaction.setLifecycleStateRequest(stateRequest); + when(stateRequest.getActivityToken()).thenReturn(token); when(mTransactionHandler.getActivity(token)).thenReturn(mock(Activity.class)); mExecutor.execute(transaction); diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index 48a824915015..abc5d6b35b02 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -22,7 +22,6 @@ import static android.app.servertransaction.TestUtils.referrerIntentList; import static android.app.servertransaction.TestUtils.resultInfoList; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import android.app.ActivityOptions; import android.app.servertransaction.TestUtils.LaunchActivityItemBuilder; @@ -32,6 +31,7 @@ import android.content.pm.ApplicationInfo; import android.content.res.Configuration; import android.os.Binder; import android.os.Bundle; +import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; @@ -61,10 +61,12 @@ import java.util.ArrayList; public class TransactionParcelTests { private Parcel mParcel; + private IBinder mActivityToken; @Before public void setUp() throws Exception { mParcel = Parcel.obtain(); + mActivityToken = new Binder(); } @Test @@ -77,13 +79,14 @@ public class TransactionParcelTests { ConfigurationChangeItem result = ConfigurationChangeItem.CREATOR.createFromParcel(mParcel); assertEquals(item.hashCode(), result.hashCode()); - assertTrue(item.equals(result)); + assertEquals(item, result); } @Test public void testActivityConfigChange() { // Write to parcel - ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain(config()); + ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain( + mActivityToken, config()); writeAndPrepareForReading(item); // Read from parcel and assert @@ -91,51 +94,52 @@ public class TransactionParcelTests { ActivityConfigurationChangeItem.CREATOR.createFromParcel(mParcel); assertEquals(item.hashCode(), result.hashCode()); - assertTrue(item.equals(result)); + assertEquals(item, result); } @Test public void testMoveToDisplay() { // Write to parcel - MoveToDisplayItem item = MoveToDisplayItem.obtain(4 /* targetDisplayId */, config()); + MoveToDisplayItem item = MoveToDisplayItem.obtain(mActivityToken, 4 /* targetDisplayId */, + config()); writeAndPrepareForReading(item); // Read from parcel and assert MoveToDisplayItem result = MoveToDisplayItem.CREATOR.createFromParcel(mParcel); assertEquals(item.hashCode(), result.hashCode()); - assertTrue(item.equals(result)); + assertEquals(item, result); } @Test public void testNewIntent() { // Write to parcel - NewIntentItem item = NewIntentItem.obtain(referrerIntentList(), false); + NewIntentItem item = NewIntentItem.obtain(mActivityToken, referrerIntentList(), false); writeAndPrepareForReading(item); // Read from parcel and assert NewIntentItem result = NewIntentItem.CREATOR.createFromParcel(mParcel); assertEquals(item.hashCode(), result.hashCode()); - assertTrue(item.equals(result)); + assertEquals(item, result); } @Test public void testActivityResult() { // Write to parcel - ActivityResultItem item = ActivityResultItem.obtain(resultInfoList()); + ActivityResultItem item = ActivityResultItem.obtain(mActivityToken, resultInfoList()); writeAndPrepareForReading(item); // Read from parcel and assert ActivityResultItem result = ActivityResultItem.CREATOR.createFromParcel(mParcel); assertEquals(item.hashCode(), result.hashCode()); - assertTrue(item.equals(result)); + assertEquals(item, result); } @Test public void testDestroy() { - DestroyActivityItem item = DestroyActivityItem.obtain(true /* finished */, + DestroyActivityItem item = DestroyActivityItem.obtain(mActivityToken, true /* finished */, 135 /* configChanges */); writeAndPrepareForReading(item); @@ -143,48 +147,59 @@ public class TransactionParcelTests { DestroyActivityItem result = DestroyActivityItem.CREATOR.createFromParcel(mParcel); assertEquals(item.hashCode(), result.hashCode()); - assertTrue(item.equals(result)); + assertEquals(item, result); } @Test public void testLaunch() { // Write to parcel - Intent intent = new Intent("action"); + final IBinder activityToken = new Binder(); + final Intent intent = new Intent("action"); int ident = 57; - ActivityInfo activityInfo = new ActivityInfo(); + final ActivityInfo activityInfo = new ActivityInfo(); activityInfo.flags = 42; activityInfo.setMaxAspectRatio(2.4f); activityInfo.launchToken = "token"; activityInfo.applicationInfo = new ApplicationInfo(); activityInfo.packageName = "packageName"; activityInfo.name = "name"; - Configuration overrideConfig = new Configuration(); + final Configuration overrideConfig = new Configuration(); overrideConfig.assetsSeq = 5; - String referrer = "referrer"; + final String referrer = "referrer"; int procState = 4; - Bundle bundle = new Bundle(); + final Bundle bundle = new Bundle(); bundle.putString("key", "value"); bundle.putParcelable("data", new ParcelableData(1)); - PersistableBundle persistableBundle = new PersistableBundle(); + final PersistableBundle persistableBundle = new PersistableBundle(); persistableBundle.putInt("k", 4); - LaunchActivityItem item = new LaunchActivityItemBuilder() - .setIntent(intent).setIdent(ident).setInfo(activityInfo).setCurConfig(config()) - .setOverrideConfig(overrideConfig).setReferrer(referrer) - .setProcState(procState).setState(bundle).setPersistentState(persistableBundle) - .setPendingResults(resultInfoList()).setActivityOptions(ActivityOptions.makeBasic()) - .setPendingNewIntents(referrerIntentList()).setIsForward(true) - .setAssistToken(new Binder()).setShareableActivityToken(new Binder()) + final LaunchActivityItem item = new LaunchActivityItemBuilder() + .setActivityToken(activityToken) + .setIntent(intent) + .setIdent(ident) + .setInfo(activityInfo) + .setCurConfig(config()) + .setOverrideConfig(overrideConfig) + .setReferrer(referrer) + .setProcState(procState) + .setState(bundle) + .setPersistentState(persistableBundle) + .setPendingResults(resultInfoList()) + .setActivityOptions(ActivityOptions.makeBasic()) + .setPendingNewIntents(referrerIntentList()) + .setIsForward(true) + .setAssistToken(new Binder()) + .setShareableActivityToken(new Binder()) .setTaskFragmentToken(new Binder()) .build(); writeAndPrepareForReading(item); // Read from parcel and assert - LaunchActivityItem result = LaunchActivityItem.CREATOR.createFromParcel(mParcel); + final LaunchActivityItem result = LaunchActivityItem.CREATOR.createFromParcel(mParcel); assertEquals(item.hashCode(), result.hashCode()); - assertTrue(item.equals(result)); + assertEquals(item, result); } @Test @@ -192,7 +207,7 @@ public class TransactionParcelTests { // Write to parcel Configuration overrideConfig = new Configuration(); overrideConfig.assetsSeq = 5; - ActivityRelaunchItem item = ActivityRelaunchItem.obtain(resultInfoList(), + ActivityRelaunchItem item = ActivityRelaunchItem.obtain(mActivityToken, resultInfoList(), referrerIntentList(), 35, mergedConfig(), true); writeAndPrepareForReading(item); @@ -200,13 +215,13 @@ public class TransactionParcelTests { ActivityRelaunchItem result = ActivityRelaunchItem.CREATOR.createFromParcel(mParcel); assertEquals(item.hashCode(), result.hashCode()); - assertTrue(item.equals(result)); + assertEquals(item, result); } @Test public void testPause() { // Write to parcel - PauseActivityItem item = PauseActivityItem.obtain(true /* finished */, + PauseActivityItem item = PauseActivityItem.obtain(mActivityToken, true /* finished */, true /* userLeaving */, 135 /* configChanges */, true /* dontReport */, true /* autoEnteringPip */); writeAndPrepareForReading(item); @@ -215,13 +230,13 @@ public class TransactionParcelTests { PauseActivityItem result = PauseActivityItem.CREATOR.createFromParcel(mParcel); assertEquals(item.hashCode(), result.hashCode()); - assertTrue(item.equals(result)); + assertEquals(item, result); } @Test public void testResume() { // Write to parcel - ResumeActivityItem item = ResumeActivityItem.obtain(27 /* procState */, + ResumeActivityItem item = ResumeActivityItem.obtain(mActivityToken, 27 /* procState */, true /* isForward */, false /* shouldSendCompatFakeFocus */); writeAndPrepareForReading(item); @@ -229,26 +244,27 @@ public class TransactionParcelTests { ResumeActivityItem result = ResumeActivityItem.CREATOR.createFromParcel(mParcel); assertEquals(item.hashCode(), result.hashCode()); - assertTrue(item.equals(result)); + assertEquals(item, result); } @Test public void testStop() { // Write to parcel - StopActivityItem item = StopActivityItem.obtain(14 /* configChanges */); + StopActivityItem item = StopActivityItem.obtain(mActivityToken, 14 /* configChanges */); writeAndPrepareForReading(item); // Read from parcel and assert StopActivityItem result = StopActivityItem.CREATOR.createFromParcel(mParcel); assertEquals(item.hashCode(), result.hashCode()); - assertTrue(item.equals(result)); + assertEquals(item, result); } @Test public void testStart() { // Write to parcel - StartActivityItem item = StartActivityItem.obtain(ActivityOptions.makeBasic()); + StartActivityItem item = StartActivityItem.obtain(mActivityToken, + ActivityOptions.makeBasic()); writeAndPrepareForReading(item); // Read from parcel and assert @@ -261,11 +277,12 @@ public class TransactionParcelTests { @Test public void testClientTransaction() { // Write to parcel - NewIntentItem callback1 = NewIntentItem.obtain(new ArrayList<>(), true); + NewIntentItem callback1 = NewIntentItem.obtain(mActivityToken, new ArrayList<>(), true); ActivityConfigurationChangeItem callback2 = ActivityConfigurationChangeItem.obtain( - config()); + mActivityToken, config()); - StopActivityItem lifecycleRequest = StopActivityItem.obtain(78 /* configChanges */); + StopActivityItem lifecycleRequest = StopActivityItem.obtain(mActivityToken, + 78 /* configChanges */); Binder activityToken = new Binder(); @@ -280,15 +297,15 @@ public class TransactionParcelTests { ClientTransaction result = ClientTransaction.CREATOR.createFromParcel(mParcel); assertEquals(transaction.hashCode(), result.hashCode()); - assertTrue(transaction.equals(result)); + assertEquals(transaction, result); } @Test public void testClientTransactionCallbacksOnly() { // Write to parcel - NewIntentItem callback1 = NewIntentItem.obtain(new ArrayList<>(), true); + NewIntentItem callback1 = NewIntentItem.obtain(mActivityToken, new ArrayList<>(), true); ActivityConfigurationChangeItem callback2 = ActivityConfigurationChangeItem.obtain( - config()); + mActivityToken, config()); Binder activityToken = new Binder(); @@ -302,13 +319,14 @@ public class TransactionParcelTests { ClientTransaction result = ClientTransaction.CREATOR.createFromParcel(mParcel); assertEquals(transaction.hashCode(), result.hashCode()); - assertTrue(transaction.equals(result)); + assertEquals(transaction, result); } @Test public void testClientTransactionLifecycleOnly() { // Write to parcel - StopActivityItem lifecycleRequest = StopActivityItem.obtain(78 /* configChanges */); + StopActivityItem lifecycleRequest = StopActivityItem.obtain(mActivityToken, + 78 /* configChanges */); Binder activityToken = new Binder(); @@ -321,7 +339,7 @@ public class TransactionParcelTests { ClientTransaction result = ClientTransaction.CREATOR.createFromParcel(mParcel); assertEquals(transaction.hashCode(), result.hashCode()); - assertTrue(transaction.equals(result)); + assertEquals(transaction, result); } /** Write to {@link #mParcel} and reset its position to prepare for reading from the start. */ diff --git a/libs/WindowManager/Shell/res/values-television/config.xml b/libs/WindowManager/Shell/res/values-television/config.xml index cc0333efd82b..5f9dbdb60516 100644 --- a/libs/WindowManager/Shell/res/values-television/config.xml +++ b/libs/WindowManager/Shell/res/values-television/config.xml @@ -44,12 +44,11 @@ if a custom action is present before closing it. --> <integer name="config_pipForceCloseDelay">5000</integer> - <!-- Animation duration when exit starting window: fade out icon --> - <integer name="starting_window_app_reveal_icon_fade_out_duration">0</integer> - <!-- Animation duration when exit starting window: reveal app --> - <integer name="starting_window_app_reveal_anim_delay">0</integer> + <integer name="starting_window_app_reveal_anim_duration">500</integer> - <!-- Animation duration when exit starting window: reveal app --> - <integer name="starting_window_app_reveal_anim_duration">0</integer> + <!-- Default animation type when hiding the starting window. The possible values are: + - 0 for radial vanish + slide up + - 1 for fade out --> + <integer name="starting_window_exit_animation_type">1</integer> </resources> diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml index a3916b71592b..97a9d4874455 100644 --- a/libs/WindowManager/Shell/res/values/config.xml +++ b/libs/WindowManager/Shell/res/values/config.xml @@ -83,6 +83,11 @@ <!-- Animation duration when exit starting window: reveal app --> <integer name="starting_window_app_reveal_anim_duration">266</integer> + <!-- Default animation type when hiding the starting window. The possible values are: + - 0 for radial vanish + slide up + - 1 for fade out --> + <integer name="starting_window_exit_animation_type">0</integer> + <!-- Default insets [LEFT/RIGHTxTOP/BOTTOM] from the screen edge for picture-in-picture windows. These values are in DPs and will be converted to pixel sizes internally. --> <string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets"> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt index c05af73e6765..c0fc02fadd4d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt @@ -52,8 +52,8 @@ class DesktopModeTaskRepository { private val activeTasksListeners = ArraySet<ActiveTasksListener>() // Track visible tasks separately because a task may be part of the desktop but not visible. private val visibleTasksListeners = ArrayMap<VisibleTasksListener, Executor>() - // Track corners of desktop tasks, used to determine gesture exclusion - private val desktopCorners = SparseArray<Region>() + // Track corner/caption regions of desktop tasks, used to determine gesture exclusion + private val desktopExclusionRegions = SparseArray<Region>() private var desktopGestureExclusionListener: Consumer<Region>? = null private var desktopGestureExclusionExecutor: Executor? = null @@ -96,10 +96,11 @@ class DesktopModeTaskRepository { } /** - * Add a Consumer which will inform other classes of changes to corners for all Desktop tasks. + * Add a Consumer which will inform other classes of changes to exclusion regions for all + * Desktop tasks. */ - fun setTaskCornerListener(cornersListener: Consumer<Region>, executor: Executor) { - desktopGestureExclusionListener = cornersListener + fun setExclusionRegionListener(regionListener: Consumer<Region>, executor: Executor) { + desktopGestureExclusionListener = regionListener desktopGestureExclusionExecutor = executor executor.execute { desktopGestureExclusionListener?.accept(calculateDesktopExclusionRegion()) @@ -107,14 +108,14 @@ class DesktopModeTaskRepository { } /** - * Create a new merged region representative of all corners in all desktop tasks. + * Create a new merged region representative of all exclusion regions in all desktop tasks. */ private fun calculateDesktopExclusionRegion(): Region { - val desktopCornersRegion = Region() - desktopCorners.valueIterator().forEach { taskCorners -> - desktopCornersRegion.op(taskCorners, Region.Op.UNION) + val desktopExclusionRegion = Region() + desktopExclusionRegions.valueIterator().forEach { taskExclusionRegion -> + desktopExclusionRegion.op(taskExclusionRegion, Region.Op.UNION) } - return desktopCornersRegion + return desktopExclusionRegion } /** @@ -294,22 +295,24 @@ class DesktopModeTaskRepository { } /** - * Updates the active desktop corners; if desktopCorners has been accepted by - * desktopCornersListener, it will be updated in the appropriate classes. + * Updates the active desktop gesture exclusion regions; if desktopExclusionRegions has been + * accepted by desktopGestureExclusionListener, it will be updated in the + * appropriate classes. */ - fun updateTaskCorners(taskId: Int, taskCorners: Region) { - desktopCorners.put(taskId, taskCorners) + fun updateTaskExclusionRegions(taskId: Int, taskExclusionRegions: Region) { + desktopExclusionRegions.put(taskId, taskExclusionRegions) desktopGestureExclusionExecutor?.execute { desktopGestureExclusionListener?.accept(calculateDesktopExclusionRegion()) } } /** - * Removes the active desktop corners for the specified task; if desktopCorners has been - * accepted by desktopCornersListener, it will be updated in the appropriate classes. + * Removes the desktop gesture exclusion region for the specified task; if exclusionRegion + * has been accepted by desktopGestureExclusionListener, it will be updated in the + * appropriate classes. */ - fun removeTaskCorners(taskId: Int) { - desktopCorners.delete(taskId) + fun removeExclusionRegion(taskId: Int) { + desktopExclusionRegions.delete(taskId) desktopGestureExclusionExecutor?.execute { desktopGestureExclusionListener?.accept(calculateDesktopExclusionRegion()) } 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 40c519eb0d5a..9ce01184c044 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 @@ -968,17 +968,17 @@ class DesktopTasksController( } /** - * Update the corner region for a specified task + * Update the exclusion region for a specified task */ - fun onTaskCornersChanged(taskId: Int, corner: Region) { - desktopModeTaskRepository.updateTaskCorners(taskId, corner) + fun onExclusionRegionChanged(taskId: Int, exclusionRegion: Region) { + desktopModeTaskRepository.updateTaskExclusionRegions(taskId, exclusionRegion) } /** - * Remove a previously tracked corner region for a specified task. + * Remove a previously tracked exclusion region for a specified task. */ - fun removeCornersForTask(taskId: Int) { - desktopModeTaskRepository.removeTaskCorners(taskId) + fun removeExclusionRegionForTask(taskId: Int) { + desktopModeTaskRepository.removeExclusionRegion(taskId) } /** @@ -992,16 +992,16 @@ class DesktopTasksController( } /** - * Adds a listener to track changes to desktop task corners + * Adds a listener to track changes to desktop task gesture exclusion regions * * @param listener the listener to add. * @param callbackExecutor the executor to call the listener on. */ - fun setTaskCornerListener( + fun setTaskRegionListener( listener: Consumer<Region>, callbackExecutor: Executor ) { - desktopModeTaskRepository.setTaskCornerListener(listener, callbackExecutor) + desktopModeTaskRepository.setExclusionRegionListener(listener, callbackExecutor) } private fun dump(pw: PrintWriter, prefix: String) { @@ -1027,7 +1027,7 @@ class DesktopTasksController( callbackExecutor: Executor ) { mainExecutor.execute { - this@DesktopTasksController.setTaskCornerListener(listener, callbackExecutor) + this@DesktopTasksController.setTaskRegionListener(listener, callbackExecutor) } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java index 20da8773f387..cb76044da7e5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java @@ -20,6 +20,7 @@ import static android.view.View.GONE; import static com.android.internal.jank.InteractionJankMonitor.CUJ_SPLASHSCREEN_EXIT_ANIM; import android.animation.Animator; +import android.annotation.IntDef; import android.content.Context; import android.graphics.Rect; import android.util.Slog; @@ -46,6 +47,8 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener { private final int mIconFadeOutDuration; private final int mAppRevealDelay; private final int mAppRevealDuration; + @ExitAnimationType + private final int mAnimationType; private final int mAnimationDuration; private final float mIconStartAlpha; private final float mBrandingStartAlpha; @@ -55,6 +58,24 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener { private Runnable mFinishCallback; + /** + * This splash screen exit animation type uses a radial vanish to hide + * the starting window and slides up the main window content. + */ + private static final int TYPE_RADIAL_VANISH_SLIDE_UP = 0; + + /** + * This splash screen exit animation type fades out the starting window + * to reveal the main window content. + */ + private static final int TYPE_FADE_OUT = 1; + + @IntDef(prefix = { "TYPE_" }, value = { + TYPE_RADIAL_VANISH_SLIDE_UP, + TYPE_FADE_OUT, + }) + private @interface ExitAnimationType {} + SplashScreenExitAnimation(Context context, SplashScreenView view, SurfaceControl leash, Rect frame, int mainWindowShiftLength, TransactionPool pool, Runnable handleFinish, float roundedCornerRadius) { @@ -91,6 +112,8 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener { } mAppRevealDuration = context.getResources().getInteger( R.integer.starting_window_app_reveal_anim_duration); + mAnimationType = context.getResources().getInteger( + R.integer.starting_window_exit_animation_type); mAnimationDuration = Math.max(mIconFadeOutDuration, mAppRevealDelay + mAppRevealDuration); mMainWindowShiftLength = mainWindowShiftLength; mFinishCallback = handleFinish; @@ -98,10 +121,15 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener { } void startAnimations() { - SplashScreenExitAnimationUtils.startAnimations(mSplashScreenView, mFirstWindowSurface, - mMainWindowShiftLength, mTransactionPool, mFirstWindowFrame, mAnimationDuration, - mIconFadeOutDuration, mIconStartAlpha, mBrandingStartAlpha, mAppRevealDelay, - mAppRevealDuration, this, mRoundedCornerRadius); + if (mAnimationType == TYPE_FADE_OUT) { + SplashScreenExitAnimationUtils.startFadeOutAnimation(mSplashScreenView, + mAnimationDuration, this); + } else { + SplashScreenExitAnimationUtils.startAnimations(mSplashScreenView, mFirstWindowSurface, + mMainWindowShiftLength, mTransactionPool, mFirstWindowFrame, mAnimationDuration, + mIconFadeOutDuration, mIconStartAlpha, mBrandingStartAlpha, mAppRevealDelay, + mAppRevealDuration, this, mRoundedCornerRadius); + } } private void reset() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java index a7e4385b60c8..64f09a77c839 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java @@ -71,11 +71,10 @@ public class SplashScreenExitAnimationUtils { int iconFadeOutDuration, float iconStartAlpha, float brandingStartAlpha, int appRevealDelay, int appRevealDuration, Animator.AnimatorListener animatorListener, float roundedCornerRadius) { - ValueAnimator animator = - createAnimator(splashScreenView, firstWindowSurface, mainWindowShiftLength, - transactionPool, firstWindowFrame, animationDuration, iconFadeOutDuration, - iconStartAlpha, brandingStartAlpha, appRevealDelay, appRevealDuration, - animatorListener, roundedCornerRadius); + ValueAnimator animator = createRadialVanishSlideUpAnimator(splashScreenView, + firstWindowSurface, mainWindowShiftLength, transactionPool, firstWindowFrame, + animationDuration, iconFadeOutDuration, iconStartAlpha, brandingStartAlpha, + appRevealDelay, appRevealDuration, animatorListener, roundedCornerRadius); animator.start(); } @@ -99,7 +98,7 @@ public class SplashScreenExitAnimationUtils { * Creates the animator to fade out the icon, reveal the app, and shift up main window. * @hide */ - private static ValueAnimator createAnimator(ViewGroup splashScreenView, + private static ValueAnimator createRadialVanishSlideUpAnimator(ViewGroup splashScreenView, SurfaceControl firstWindowSurface, int mMainWindowShiftLength, TransactionPool transactionPool, Rect firstWindowFrame, int animationDuration, int iconFadeOutDuration, float iconStartAlpha, float brandingStartAlpha, @@ -210,6 +209,20 @@ public class SplashScreenExitAnimationUtils { return nightMode == Configuration.UI_MODE_NIGHT_YES; } + static void startFadeOutAnimation(ViewGroup splashScreenView, + int animationDuration, Animator.AnimatorListener animatorListener) { + final ValueAnimator animator = ValueAnimator.ofFloat(1f, 0f); + animator.setDuration(animationDuration); + animator.setInterpolator(Interpolators.LINEAR); + animator.addUpdateListener(animation -> { + splashScreenView.setAlpha((float) animation.getAnimatedValue()); + }); + if (animatorListener != null) { + animator.addListener(animatorListener); + } + animator.start(); + } + /** * View which creates a circular reveal of the underlying view. * @hide diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index abd2ad49317b..026d0cdd7c52 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -21,7 +21,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; - import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE; @@ -79,7 +78,7 @@ import com.android.wm.shell.sysui.KeyguardChangeListener; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; -import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.TaskCornersListener; +import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.ExclusionRegionListener; import java.util.Optional; import java.util.function.Supplier; @@ -106,7 +105,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private SparseArray<EventReceiver> mEventReceiversByDisplay = new SparseArray<>(); - private final TaskCornersListener mCornersListener = new TaskCornersListenerImpl(); + private final ExclusionRegionListener mExclusionRegionListener = + new ExclusionRegionListenerImpl(); private final SparseArray<DesktopModeWindowDecoration> mWindowDecorByTaskId = new SparseArray<>(); @@ -920,7 +920,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { windowDecoration.setCaptionListeners( touchEventListener, touchEventListener, touchEventListener); - windowDecoration.setCornersListener(mCornersListener); + windowDecoration.setExclusionRegionListener(mExclusionRegionListener); windowDecoration.setDragPositioningCallback(dragPositioningCallback); windowDecoration.setDragDetector(touchEventListener.mDragDetector); windowDecoration.relayout(taskInfo, startT, finishT, @@ -958,17 +958,17 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } } - private class TaskCornersListenerImpl - implements DesktopModeWindowDecoration.TaskCornersListener { + private class ExclusionRegionListenerImpl + implements ExclusionRegionListener { @Override - public void onTaskCornersChanged(int taskId, Region corner) { - mDesktopTasksController.ifPresent(d -> d.onTaskCornersChanged(taskId, corner)); + public void onExclusionRegionChanged(int taskId, Region region) { + mDesktopTasksController.ifPresent(d -> d.onExclusionRegionChanged(taskId, region)); } @Override - public void onTaskCornersRemoved(int taskId) { - mDesktopTasksController.ifPresent(d -> d.removeCornersForTask(taskId)); + public void onExclusionRegionDismissed(int taskId) { + mDesktopTasksController.ifPresent(d -> d.removeExclusionRegionForTask(taskId)); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index e954f3b4a1d5..dbff20e6026a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -92,7 +92,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private Drawable mAppIcon; private CharSequence mAppName; - private TaskCornersListener mCornersListener; + private ExclusionRegionListener mExclusionRegionListener; private final Set<IBinder> mTransitionsPausingRelayout = new HashSet<>(); private int mRelayoutBlock; @@ -128,8 +128,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mOnCaptionLongClickListener = onLongClickListener; } - void setCornersListener(TaskCornersListener cornersListener) { - mCornersListener = cornersListener; + void setExclusionRegionListener(ExclusionRegionListener exclusionRegionListener) { + mExclusionRegionListener = exclusionRegionListener; } void setDragPositioningCallback(DragPositioningCallback dragPositioningCallback) { @@ -229,6 +229,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } if (!isDragResizeable) { + if (!mTaskInfo.positionInParent.equals(mPositionInParent)) { + // We still want to track caption bar's exclusion region on a non-resizeable task. + updateExclusionRegion(); + } closeDragResizeListener(); return; } @@ -256,13 +260,13 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final int resize_corner = mResult.mRootView.getResources() .getDimensionPixelSize(R.dimen.freeform_resize_corner); - // If either task geometry or position have changed, update this task's cornersListener + // If either task geometry or position have changed, update this task's + // exclusion region listener if (mDragResizeListener.setGeometry( mResult.mWidth, mResult.mHeight, resize_handle, resize_corner, touchSlop) || !mTaskInfo.positionInParent.equals(mPositionInParent)) { - mCornersListener.onTaskCornersChanged(mTaskInfo.taskId, getGlobalCornersRegion()); + updateExclusionRegion(); } - mPositionInParent.set(mTaskInfo.positionInParent); if (isMaximizeMenuActive()) { if (!mTaskInfo.isVisible()) { @@ -282,8 +286,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final int displayWidth = displayLayout.width(); final int displayHeight = displayLayout.height(); - final int captionHeight = loadDimensionPixelSize( - resources, R.dimen.freeform_decor_caption_height); + final int captionHeight = getCaptionHeight(); final ImageButton maximizeWindowButton = mResult.mRootView.findViewById(R.id.maximize_window); @@ -537,7 +540,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin public void close() { closeDragResizeListener(); closeHandleMenu(); - mCornersListener.onTaskCornersRemoved(mTaskInfo.taskId); + mExclusionRegionListener.onExclusionRegionDismissed(mTaskInfo.taskId); disposeResizeVeil(); super.close(); } @@ -548,13 +551,32 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin : R.layout.desktop_mode_focused_window_decor; } + private void updatePositionInParent() { + mPositionInParent.set(mTaskInfo.positionInParent); + } + + private void updateExclusionRegion() { + // An outdated position in parent is one reason for this to be called; update it here. + updatePositionInParent(); + mExclusionRegionListener + .onExclusionRegionChanged(mTaskInfo.taskId, getGlobalExclusionRegion()); + } + /** - * Create a new region out of the corner rects of this task. + * Create a new exclusion region from the corner rects (if resizeable) and caption bounds + * of this task. */ - Region getGlobalCornersRegion() { - Region cornersRegion = mDragResizeListener.getCornersRegion(); - cornersRegion.translate(mPositionInParent.x, mPositionInParent.y); - return cornersRegion; + private Region getGlobalExclusionRegion() { + Region exclusionRegion; + if (mTaskInfo.isResizeable) { + exclusionRegion = mDragResizeListener.getCornersRegion(); + } else { + exclusionRegion = new Region(); + } + exclusionRegion.union(new Rect(0, 0, mResult.mWidth, + getCaptionHeight())); + exclusionRegion.translate(mPositionInParent.x, mPositionInParent.y); + return exclusionRegion; } /** @@ -572,6 +594,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin return R.dimen.freeform_decor_caption_height; } + private int getCaptionHeight() { + return loadDimensionPixelSize(mContext.getResources(), getCaptionHeightId()); + } + /** * Add transition to mTransitionsPausingRelayout */ @@ -626,12 +652,14 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } } - interface TaskCornersListener { - /** Inform the implementing class of this task's change in corner resize handles */ - void onTaskCornersChanged(int taskId, Region corner); + interface ExclusionRegionListener { + /** Inform the implementing class of this task's change in region resize handles */ + void onExclusionRegionChanged(int taskId, Region region); - /** Inform the implementing class that this task no longer needs its corners tracked, - * likely due to it closing. */ - void onTaskCornersRemoved(int taskId); + /** + * Inform the implementing class that this task no longer needs an exclusion region, + * likely due to it closing. + */ + void onExclusionRegionDismissed(int taskId); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java index bfce72bcadf0..09fc3dacf6f3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java @@ -49,11 +49,13 @@ public class ResizeVeil { private final Supplier<SurfaceControl.Builder> mSurfaceControlBuilderSupplier; private final Supplier<SurfaceControl.Transaction> mSurfaceControlTransactionSupplier; private final Drawable mAppIcon; + private ImageView mIconView; private SurfaceControl mParentSurface; private SurfaceControl mVeilSurface; private final RunningTaskInfo mTaskInfo; private SurfaceControlViewHost mViewHost; private final Display mDisplay; + private ValueAnimator mVeilAnimator; public ResizeVeil(Context context, Drawable appIcon, RunningTaskInfo taskInfo, Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier, Display display, @@ -97,8 +99,8 @@ public class ResizeVeil { mViewHost = new SurfaceControlViewHost(mContext, mDisplay, windowManager, "ResizeVeil"); mViewHost.setView(v, lp); - final ImageView appIcon = mViewHost.getView().findViewById(R.id.veil_application_icon); - appIcon.setImageDrawable(mAppIcon); + mIconView = mViewHost.getView().findViewById(R.id.veil_application_icon); + mIconView.setImageDrawable(mAppIcon); } /** @@ -123,17 +125,27 @@ public class ResizeVeil { relayout(taskBounds, t); if (fadeIn) { - final ValueAnimator animator = new ValueAnimator(); - animator.setFloatValues(0f, 1f); - animator.setDuration(RESIZE_ALPHA_DURATION); - animator.addUpdateListener(animation -> { - t.setAlpha(mVeilSurface, animator.getAnimatedFraction()); + mVeilAnimator = new ValueAnimator(); + mVeilAnimator.setFloatValues(0f, 1f); + mVeilAnimator.setDuration(RESIZE_ALPHA_DURATION); + mVeilAnimator.addUpdateListener(animation -> { + t.setAlpha(mVeilSurface, mVeilAnimator.getAnimatedFraction()); t.apply(); }); + final ValueAnimator iconAnimator = new ValueAnimator(); + iconAnimator.setFloatValues(0f, 1f); + iconAnimator.setDuration(RESIZE_ALPHA_DURATION); + iconAnimator.addUpdateListener(animation -> { + mIconView.setAlpha(animation.getAnimatedFraction()); + }); + t.show(mVeilSurface) .addTransactionCommittedListener( - mContext.getMainExecutor(), () -> animator.start()) + mContext.getMainExecutor(), () -> { + mVeilAnimator.start(); + iconAnimator.start(); + }) .setAlpha(mVeilSurface, 0); } else { // Show the veil immediately at full opacity. @@ -172,11 +184,17 @@ public class ResizeVeil { /** * Calls relayout to update task and veil bounds. + * Finishes veil fade in if animation is currently running; this is to prevent empty space + * being visible behind the transparent veil during a fast resize. * * @param t a transaction to be applied in sync with the veil draw. * @param newBounds bounds to update veil to. */ public void updateResizeVeil(SurfaceControl.Transaction t, Rect newBounds) { + if (mVeilAnimator != null && mVeilAnimator.isStarted()) { + // TODO(b/300145351): Investigate why ValueAnimator#end does not work here. + mVeilAnimator.setCurrentPlayTime(RESIZE_ALPHA_DURATION); + } relayout(newBounds, t); mViewHost.getView().getViewRootImpl().applyTransactionOnDraw(t); } diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp index eb650caf04e2..6fd3354700f7 100644 --- a/libs/WindowManager/Shell/tests/flicker/Android.bp +++ b/libs/WindowManager/Shell/tests/flicker/Android.bp @@ -44,6 +44,16 @@ filegroup { } filegroup { + name: "WMShellFlickerTestsPipCommon-src", + srcs: ["src/com/android/wm/shell/flicker/pip/common/*.kt"], +} + +filegroup { + name: "WMShellFlickerTestsPipApps-src", + srcs: ["src/com/android/wm/shell/flicker/pip/apps/*.kt"], +} + +filegroup { name: "WMShellFlickerTestsSplitScreenBase-src", srcs: [ "src/com/android/wm/shell/flicker/splitscreen/benchmark/*.kt", @@ -152,6 +162,8 @@ android_test { exclude_srcs: [ ":WMShellFlickerTestsBubbles-src", ":WMShellFlickerTestsPip-src", + ":WMShellFlickerTestsPipCommon-src", + ":WMShellFlickerTestsPipApps-src", ":WMShellFlickerTestsSplitScreenGroup1-src", ":WMShellFlickerTestsSplitScreenGroup2-src", ":WMShellFlickerTestsSplitScreenBase-src", @@ -181,6 +193,20 @@ android_test { srcs: [ ":WMShellFlickerTestsBase-src", ":WMShellFlickerTestsPip-src", + ":WMShellFlickerTestsPipCommon-src", + ], +} + +android_test { + name: "WMShellFlickerTestsPipApps", + defaults: ["WMShellFlickerTestsDefault"], + additional_manifests: ["manifests/AndroidManifestPip.xml"], + package_name: "com.android.wm.shell.flicker.pip.apps", + instrumentation_target_package: "com.android.wm.shell.flicker.pip.apps", + srcs: [ + ":WMShellFlickerTestsBase-src", + ":WMShellFlickerTestsPipApps-src", + ":WMShellFlickerTestsPipCommon-src", ], } diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml index 57df4e8bedb2..b13e9a248575 100644 --- a/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml +++ b/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml @@ -60,9 +60,9 @@ <!-- Enable mocking GPS location by the test app --> <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> <option name="run-command" - value="appops set com.android.wm.shell.flicker.pip android:mock_location allow"/> + value="appops set com.android.wm.shell.flicker.pip.apps android:mock_location allow"/> <option name="teardown-command" - value="appops set com.android.wm.shell.flicker.pip android:mock_location deny"/> + value="appops set com.android.wm.shell.flicker.pip.apps android:mock_location deny"/> </target_preparer> <!-- Needed for pushing the trace config file --> diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt index ca28f5210f6b..9256725c6180 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt @@ -21,6 +21,7 @@ import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.LegacyFlickerTest +import com.android.wm.shell.flicker.pip.common.ClosePipTransition import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt index 4da628cfd90c..002c019eff93 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt @@ -20,6 +20,7 @@ import android.platform.test.annotations.Presubmit import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.LegacyFlickerTest +import com.android.wm.shell.flicker.pip.common.ClosePipTransition import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt index e0b18dea971d..6dd68b0d029d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt @@ -20,6 +20,7 @@ import android.platform.test.annotations.Presubmit import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.LegacyFlickerTest +import com.android.wm.shell.flicker.pip.common.EnterPipTransition import org.junit.Assume import org.junit.FixMethodOrder import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt index b4cedd995169..8207b85c3e0c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt @@ -32,8 +32,9 @@ import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper import com.android.server.wm.flicker.testapp.ActivityOptions.Pip.ACTION_ENTER_PIP import com.android.server.wm.flicker.testapp.ActivityOptions.PortraitOnlyActivity.EXTRA_FIXED_ORIENTATION -import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE -import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT +import com.android.wm.shell.flicker.pip.common.PipTransition +import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE +import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT import org.junit.Assume import org.junit.Before import org.junit.FixMethodOrder diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt index f9efffe8f5cd..cc943678d492 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt @@ -19,6 +19,7 @@ package com.android.wm.shell.flicker.pip import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.LegacyFlickerTest +import com.android.wm.shell.flicker.pip.common.EnterPipTransition import org.junit.FixMethodOrder import org.junit.runner.RunWith import org.junit.runners.MethodSorters diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt index c4e63c3fc408..7da442901e40 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt @@ -19,6 +19,7 @@ package com.android.wm.shell.flicker.pip import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.LegacyFlickerTest +import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition import org.junit.FixMethodOrder import org.junit.runner.RunWith import org.junit.runners.MethodSorters diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt index 839bbd4673a5..0ad9e4c61d83 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt @@ -19,6 +19,7 @@ package com.android.wm.shell.flicker.pip import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.LegacyFlickerTest +import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition import org.junit.FixMethodOrder import org.junit.runner.RunWith import org.junit.runners.MethodSorters diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt index ea67e3ddae69..89a6c93e478c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt @@ -23,6 +23,7 @@ import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.LegacyFlickerTest import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt index 0f30cef3fda5..8978af0088b8 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt @@ -22,6 +22,7 @@ import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.LegacyFlickerTest import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt index 421ad757f76a..4776206724cc 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt @@ -21,6 +21,7 @@ import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.LegacyFlickerTest import androidx.test.filters.RequiresDevice +import com.android.wm.shell.flicker.pip.common.MovePipShelfHeightTransition import com.android.wm.shell.flicker.utils.Direction import org.junit.FixMethodOrder import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt index c10860a5396f..425cbfaffedd 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt @@ -27,6 +27,7 @@ import android.tools.device.flicker.legacy.LegacyFlickerTestFactory import android.tools.device.helpers.WindowUtils import com.android.server.wm.flicker.helpers.ImeAppHelper import com.android.server.wm.flicker.helpers.setRotation +import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt index 992f1bc4ace3..18f30d96938b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt @@ -21,6 +21,7 @@ import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.LegacyFlickerTest import androidx.test.filters.RequiresDevice +import com.android.wm.shell.flicker.pip.common.MovePipShelfHeightTransition import com.android.wm.shell.flicker.utils.Direction import org.junit.FixMethodOrder import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt index 0c6fc5636a5b..c7f2786debd0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt @@ -23,6 +23,7 @@ import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.LegacyFlickerTest import android.tools.device.flicker.legacy.LegacyFlickerTestFactory import com.android.server.wm.flicker.testapp.ActivityOptions +import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt index 43e7696ffa93..cabc1cc0b023 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt @@ -27,6 +27,7 @@ import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.testapp.ActivityOptions +import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt index 0295741bc441..6748626d4e46 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt @@ -23,6 +23,7 @@ import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.LegacyFlickerTest import android.tools.device.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice +import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt index a236126415f3..1f69847e5481 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt @@ -30,7 +30,8 @@ import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.testapp.ActivityOptions import com.android.server.wm.flicker.testapp.ActivityOptions.PortraitOnlyActivity.EXTRA_FIXED_ORIENTATION -import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE +import com.android.wm.shell.flicker.pip.common.PipTransition +import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE import org.junit.Assume import org.junit.Before import org.junit.FixMethodOrder diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt index e588f8793b82..308ece40402f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt @@ -25,6 +25,7 @@ import android.tools.device.flicker.legacy.LegacyFlickerTestFactory import android.tools.device.helpers.WindowUtils import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.helpers.setRotation +import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppsEnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt index 9a28439e112e..fb6c09381d3b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppsEnterPipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.wm.shell.flicker.pip +package com.android.wm.shell.flicker.pip.apps import android.platform.test.annotations.Postsubmit import android.tools.common.Rotation @@ -22,6 +22,7 @@ import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper import android.tools.device.flicker.legacy.LegacyFlickerTest import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import com.android.wm.shell.flicker.pip.common.EnterPipTransition import org.junit.Test import org.junit.runners.Parameterized diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MapsEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt index 258c0588378e..54b3e2a8c8c0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MapsEnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.wm.shell.flicker.pip +package com.android.wm.shell.flicker.pip.apps import android.os.Handler import android.os.Looper diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt index a17144b7cef3..751f2bc0807f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.wm.shell.flicker.pip +package com.android.wm.shell.flicker.pip.common import android.platform.test.annotations.Presubmit import android.tools.common.Rotation diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt index d547b9cc1dc2..9c129e47efba 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.wm.shell.flicker.pip +package com.android.wm.shell.flicker.pip.common import android.platform.test.annotations.Presubmit import android.tools.common.Rotation diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt index dfffba831dc3..9450bdd2d894 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.wm.shell.flicker.pip +package com.android.wm.shell.flicker.pip.common import android.platform.test.annotations.Presubmit import android.tools.common.Rotation diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt index a8fb63de244b..7e42bc11a9c1 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.wm.shell.flicker.pip +package com.android.wm.shell.flicker.pip.common import android.platform.test.annotations.Presubmit import android.tools.common.Rotation diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt index 2008d019d2c4..7b7f1d7b5a82 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.wm.shell.flicker.pip +package com.android.wm.shell.flicker.pip.common import android.app.Instrumentation import android.content.Intent diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp index 19a1dfa91539..16de21def0e3 100644 --- a/libs/hwui/HardwareBitmapUploader.cpp +++ b/libs/hwui/HardwareBitmapUploader.cpp @@ -22,6 +22,7 @@ #include <GLES2/gl2ext.h> #include <GLES3/gl3.h> #include <GrDirectContext.h> +#include <GrTypes.h> #include <SkBitmap.h> #include <SkCanvas.h> #include <SkImage.h> @@ -265,7 +266,7 @@ private: sk_sp<SkImage> image = SkImages::TextureFromAHardwareBufferWithData(mGrContext.get(), bitmap.pixmap(), ahb); - mGrContext->submit(true); + mGrContext->submit(GrSyncCpu::kYes); uploadSucceeded = (image.get() != nullptr); }); diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp index 8f81dbad2320..735fc074435d 100644 --- a/libs/hwui/renderthread/CacheManager.cpp +++ b/libs/hwui/renderthread/CacheManager.cpp @@ -17,6 +17,7 @@ #include "CacheManager.h" #include <GrContextOptions.h> +#include <GrTypes.h> #include <SkExecutor.h> #include <SkGraphics.h> #include <math.h> @@ -110,13 +111,18 @@ void CacheManager::configureContext(GrContextOptions* contextOptions, const void contextOptions->fPersistentCache = &cache; } +static GrPurgeResourceOptions toSkiaEnum(bool scratchOnly) { + return scratchOnly ? GrPurgeResourceOptions::kScratchResourcesOnly : + GrPurgeResourceOptions::kAllResources; +} + void CacheManager::trimMemory(TrimLevel mode) { if (!mGrContext) { return; } // flush and submit all work to the gpu and wait for it to finish - mGrContext->flushAndSubmit(/*syncCpu=*/true); + mGrContext->flushAndSubmit(GrSyncCpu::kYes); switch (mode) { case TrimLevel::BACKGROUND: @@ -130,7 +136,7 @@ void CacheManager::trimMemory(TrimLevel mode) { // that have persistent data to be purged in LRU order. mGrContext->setResourceCacheLimit(mBackgroundResourceBytes); SkGraphics::SetFontCacheLimit(mBackgroundCpuFontCacheBytes); - mGrContext->purgeUnlockedResources(mMemoryPolicy.purgeScratchOnly); + mGrContext->purgeUnlockedResources(toSkiaEnum(mMemoryPolicy.purgeScratchOnly)); mGrContext->setResourceCacheLimit(mMaxResourceBytes); SkGraphics::SetFontCacheLimit(mMaxCpuFontCacheBytes); break; @@ -150,7 +156,7 @@ void CacheManager::trimCaches(CacheTrimLevel mode) { case CacheTrimLevel::ALL_CACHES: SkGraphics::PurgeAllCaches(); if (mGrContext) { - mGrContext->purgeUnlockedResources(false); + mGrContext->purgeUnlockedResources(GrPurgeResourceOptions::kAllResources); } break; default: @@ -285,7 +291,7 @@ void CacheManager::onThreadIdle() { ns2ms(std::clamp(frameDiffNanos, mMemoryPolicy.minimumResourceRetention, mMemoryPolicy.maximumResourceRetention)); mGrContext->performDeferredCleanup(std::chrono::milliseconds(cleanupMillis), - mMemoryPolicy.purgeScratchOnly); + toSkiaEnum(mMemoryPolicy.purgeScratchOnly)); } } diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index ee3b2e48fe4b..90850d36b612 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -515,7 +515,7 @@ Frame VulkanManager::dequeueNextBuffer(VulkanSurface* surface) { // The following flush blocks the GPU immediately instead of waiting for // other drawing ops. It seems dequeue_fence is not respected otherwise. // TODO: remove the flush after finding why backendSemaphore is not working. - skgpu::ganesh::FlushAndSubmit(bufferInfo->skSurface); + skgpu::ganesh::FlushAndSubmit(bufferInfo->skSurface.get()); } } } diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig index 17962ee10161..86e53f5bb2e2 100644 --- a/media/java/android/media/flags/media_better_together.aconfig +++ b/media/java/android/media/flags/media_better_together.aconfig @@ -1,8 +1,15 @@ package: "com.android.media.flags" flag { - namespace: "media_solutions" - name: "enable_rlp_callbacks_in_media_router2" - description: "Make RouteListingPreference getter and callbacks public in MediaRouter2." - bug: "281067101" + name: "enable_rlp_callbacks_in_media_router2" + namespace: "media_solutions" + description: "Make RouteListingPreference getter and callbacks public in MediaRouter2." + bug: "281067101" +} + +flag { + name: "adjust_volume_for_foreground_app_playing_audio_without_media_session" + namespace: "media_solutions" + description: "Gates whether to adjust local stream volume when the app in the foreground is the last app to play audio or adjust the volume of the last active media session that the user interacted with." + bug: "275185436" } diff --git a/packages/CredentialManager/horologist/OWNERS b/packages/CredentialManager/horologist/OWNERS new file mode 100644 index 000000000000..b67932835b4a --- /dev/null +++ b/packages/CredentialManager/horologist/OWNERS @@ -0,0 +1,4 @@ +include /core/java/android/credentials/OWNERS + +shuanghao@google.com +gustavopagani@google.com diff --git a/packages/CredentialManager/shared/OWNERS b/packages/CredentialManager/shared/OWNERS new file mode 100644 index 000000000000..b67932835b4a --- /dev/null +++ b/packages/CredentialManager/shared/OWNERS @@ -0,0 +1,4 @@ +include /core/java/android/credentials/OWNERS + +shuanghao@google.com +gustavopagani@google.com diff --git a/packages/CredentialManager/wear/OWNERS b/packages/CredentialManager/wear/OWNERS new file mode 100644 index 000000000000..b67932835b4a --- /dev/null +++ b/packages/CredentialManager/wear/OWNERS @@ -0,0 +1,4 @@ +include /core/java/android/credentials/OWNERS + +shuanghao@google.com +gustavopagani@google.com diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java index 1e4eae51e7cd..03d1cda9c071 100644 --- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java +++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java @@ -20,6 +20,8 @@ import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NO import static android.app.admin.DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY; import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER; +import static com.android.settingslib.Utils.getColorAttrDefaultColor; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; @@ -639,7 +641,8 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils { removeExistingRestrictedSpans(sb); if (admin != null) { - final int disabledColor = context.getColor(R.color.disabled_text_color); + final int disabledColor = getColorAttrDefaultColor(context, + android.R.attr.textColorHint); sb.setSpan(new ForegroundColorSpan(disabledColor), 0, sb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); ImageSpan image = new RestrictedLockImageSpan(context); diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt index a3a1fa58e88e..0c076169eb57 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt @@ -24,6 +24,7 @@ import android.graphics.Matrix import android.graphics.Path import android.graphics.Rect import android.graphics.RectF +import android.os.Build import android.os.Looper import android.os.RemoteException import android.util.Log @@ -88,6 +89,9 @@ class ActivityLaunchAnimator( contentAfterFadeInInterpolator = PathInterpolator(0f, 0f, 0.6f, 1f) ) + // TODO(b/288507023): Remove this flag. + @JvmField val DEBUG_LAUNCH_ANIMATION = Build.IS_DEBUGGABLE + private val DEFAULT_LAUNCH_ANIMATOR = LaunchAnimator(TIMINGS, INTERPOLATORS) private val DEFAULT_DIALOG_TO_APP_ANIMATOR = LaunchAnimator(DIALOG_TIMINGS, INTERPOLATORS) @@ -244,11 +248,13 @@ class ActivityLaunchAnimator( callOnIntentStartedOnMainThread(willAnimate) } } else { - // TODO(b/288507023): Remove this log. - Log.d( - TAG, - "Calling controller.onIntentStarted(willAnimate=$willAnimate) [controller=$this]" - ) + if (DEBUG_LAUNCH_ANIMATION) { + Log.d( + TAG, + "Calling controller.onIntentStarted(willAnimate=$willAnimate) " + + "[controller=$this]" + ) + } this.onIntentStarted(willAnimate) } } @@ -549,8 +555,12 @@ class ActivityLaunchAnimator( removeTimeout() iCallback?.invoke() - // TODO(b/288507023): Remove this log. - Log.d(TAG, "Calling controller.onLaunchAnimationCancelled() [no window opening]") + if (DEBUG_LAUNCH_ANIMATION) { + Log.d( + TAG, + "Calling controller.onLaunchAnimationCancelled() [no window opening]" + ) + } controller.onLaunchAnimationCancelled() return } @@ -769,8 +779,9 @@ class ActivityLaunchAnimator( Log.i(TAG, "Remote animation timed out") timedOut = true - // TODO(b/288507023): Remove this log. - Log.d(TAG, "Calling controller.onLaunchAnimationCancelled() [animation timed out]") + if (DEBUG_LAUNCH_ANIMATION) { + Log.d(TAG, "Calling controller.onLaunchAnimationCancelled() [animation timed out]") + } controller.onLaunchAnimationCancelled() } @@ -786,11 +797,12 @@ class ActivityLaunchAnimator( animation?.cancel() - // TODO(b/288507023): Remove this log. - Log.d( - TAG, - "Calling controller.onLaunchAnimationCancelled() [remote animation cancelled]", - ) + if (DEBUG_LAUNCH_ANIMATION) { + Log.d( + TAG, + "Calling controller.onLaunchAnimationCancelled() [remote animation cancelled]", + ) + } controller.onLaunchAnimationCancelled() } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt index 81b9eb067e7f..e06a69bfaa63 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt @@ -55,6 +55,7 @@ import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel import com.android.systemui.bouncer.ui.viewmodel.PatternBouncerViewModel import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.scene.shared.model.Direction import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.scene.shared.model.UserAction @@ -82,9 +83,10 @@ constructor( override val key = SceneKey.Bouncer override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> = - MutableStateFlow<Map<UserAction, SceneModel>>( + MutableStateFlow( mapOf( UserAction.Back to SceneModel(SceneKey.Lockscreen), + UserAction.Swipe(Direction.DOWN) to SceneModel(SceneKey.Lockscreen), ) ) .asStateFlow() diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java index 77f6d03a03fb..eb2066936088 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java @@ -61,8 +61,6 @@ public final class InteractionJankMonitorWrapper { InteractionJankMonitor.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS; public static final int CUJ_OPEN_SEARCH_RESULT = InteractionJankMonitor.CUJ_LAUNCHER_OPEN_SEARCH_RESULT; - public static final int CUJ_SHADE_EXPAND_FROM_STATUS_BAR = - InteractionJankMonitor.CUJ_SHADE_EXPAND_FROM_STATUS_BAR; @IntDef({ CUJ_APP_LAUNCH_FROM_RECENTS, @@ -79,7 +77,6 @@ public final class InteractionJankMonitorWrapper { CUJ_CLOSE_ALL_APPS_SWIPE, CUJ_CLOSE_ALL_APPS_TO_HOME, CUJ_OPEN_SEARCH_RESULT, - CUJ_SHADE_EXPAND_FROM_STATUS_BAR, }) @Retention(RetentionPolicy.SOURCE) public @interface CujType { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt index a8070c25fe72..3dd3e0762c7c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt @@ -18,11 +18,13 @@ package com.android.systemui.keyguard.ui.binder import android.os.Trace +import android.transition.TransitionManager import android.util.Log import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle +import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.BaseBlueprintTransition import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel import com.android.systemui.lifecycle.repeatWhenAttached import kotlinx.coroutines.launch @@ -40,17 +42,29 @@ class KeyguardBlueprintViewBinder { Trace.beginSection("KeyguardBlueprint#applyBlueprint") Log.d(TAG, "applying blueprint: $blueprint") - ConstraintSet().apply { - clone(constraintLayout) - val emptyLayout = ConstraintSet.Layout() - knownIds.forEach { getConstraint(it).layout.copyFrom(emptyLayout) } - blueprint.applyConstraints(this) - // Add and remove views of sections that are not contained by the - // other. - blueprint?.replaceViews(prevBluePrint, constraintLayout) - applyTo(constraintLayout) + val cs = + ConstraintSet().apply { + clone(constraintLayout) + val emptyLayout = ConstraintSet.Layout() + knownIds.forEach { + getConstraint(it).layout.copyFrom(emptyLayout) + } + blueprint.applyConstraints(this) + } + + // Apply transition. + if (prevBluePrint != null && prevBluePrint != blueprint) { + TransitionManager.beginDelayedTransition( + constraintLayout, + BaseBlueprintTransition() + ) } + // Add and remove views of sections that are not contained by the + // other. + blueprint.replaceViews(prevBluePrint, constraintLayout) + cs.applyTo(constraintLayout) + viewModel.currentBluePrint = blueprint Trace.endSection() } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/BaseBlueprintTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/BaseBlueprintTransition.kt new file mode 100644 index 000000000000..42b1c1044cda --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/BaseBlueprintTransition.kt @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.view.layout.blueprints.transitions + +import android.animation.Animator +import android.animation.ObjectAnimator +import android.transition.ChangeBounds +import android.transition.TransitionSet +import android.transition.TransitionValues +import android.transition.Visibility +import android.view.View +import android.view.ViewGroup + +class BaseBlueprintTransition : TransitionSet() { + init { + ordering = ORDERING_SEQUENTIAL + addTransition(AlphaOutVisibility()) + .addTransition(ChangeBounds()) + .addTransition(AlphaInVisibility()) + } + class AlphaOutVisibility : Visibility() { + override fun onDisappear( + sceneRoot: ViewGroup?, + view: View, + startValues: TransitionValues?, + endValues: TransitionValues? + ): Animator { + return ObjectAnimator.ofFloat(view, "alpha", 0f).apply { + addUpdateListener { view.alpha = it.animatedValue as Float } + start() + } + } + } + + class AlphaInVisibility : Visibility() { + override fun onAppear( + sceneRoot: ViewGroup?, + view: View, + startValues: TransitionValues?, + endValues: TransitionValues? + ): Animator { + return ObjectAnimator.ofFloat(view, "alpha", 1f).apply { + addUpdateListener { view.alpha = it.animatedValue as Float } + start() + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 246ea0ed1e13..49ce832c1e8c 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -97,6 +97,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.policy.SystemBarUtils; +import com.android.internal.statusbar.IStatusBarService; import com.android.internal.util.LatencyTracker; import com.android.keyguard.ActiveUnlockConfig; import com.android.keyguard.FaceAuthApiRequestReason; @@ -165,7 +166,6 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.shade.data.repository.ShadeRepository; import com.android.systemui.shade.transition.ShadeTransitionController; -import com.android.systemui.shared.system.InteractionJankMonitorWrapper; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.GestureRecorder; @@ -336,6 +336,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private final KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory; private final KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory; private final FragmentService mFragmentService; + private final IStatusBarService mStatusBarService; private final ScrimController mScrimController; private final LockscreenShadeTransitionController mLockscreenShadeTransitionController; private final TapAgainViewController mTapAgainViewController; @@ -370,7 +371,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump /** The current squish amount for the predictive back animation */ private float mCurrentBackProgress = 0.0f; private boolean mTracking; - private boolean mIsTrackingExpansionFromStatusBar; private boolean mHintAnimationRunning; @Deprecated private KeyguardBottomAreaView mKeyguardBottomArea; @@ -744,6 +744,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump NavigationBarController navigationBarController, QuickSettingsController quickSettingsController, FragmentService fragmentService, + IStatusBarService statusBarService, ContentResolver contentResolver, ShadeHeaderController shadeHeaderController, ScreenOffAnimationController screenOffAnimationController, @@ -874,6 +875,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory; mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory; mFragmentService = fragmentService; + mStatusBarService = statusBarService; mSettingsChangeObserver = new SettingsChangeObserver(handler); mSplitShadeEnabled = LargeScreenUtils.shouldUseSplitNotificationShade(mResources); @@ -2845,7 +2847,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private void onTrackingStopped(boolean expand) { mTracking = false; - maybeStopTrackingExpansionFromStatusBar(expand); updateExpansionAndVisibility(); if (expand) { @@ -3036,7 +3037,9 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) { mHeadsUpManager = headsUpManager; mHeadsUpManager.addListener(mOnHeadsUpChangedListener); - mHeadsUpTouchHelper = new HeadsUpTouchHelper(headsUpManager, + mHeadsUpTouchHelper = new HeadsUpTouchHelper( + headsUpManager, + mStatusBarService, mNotificationStackScrollLayoutController.getHeadsUpCallback(), new HeadsUpNotificationViewControllerImpl()); } @@ -4244,42 +4247,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump } @Override - public void startTrackingExpansionFromStatusBar() { - mIsTrackingExpansionFromStatusBar = true; - InteractionJankMonitorWrapper.begin( - mView, InteractionJankMonitorWrapper.CUJ_SHADE_EXPAND_FROM_STATUS_BAR); - } - - /** - * Stops tracking an expansion that originated from the status bar (if we had started tracking - * it). - * - * @param expand the expand boolean passed to {@link #onTrackingStopped(boolean)}. - */ - private void maybeStopTrackingExpansionFromStatusBar(boolean expand) { - if (!mIsTrackingExpansionFromStatusBar) { - return; - } - mIsTrackingExpansionFromStatusBar = false; - - // Determine whether the shade actually expanded due to the status bar touch: - // - If the user just taps on the status bar, then #isExpanded is false but - // #onTrackingStopped is called with `true`. - // - If the user drags down on the status bar but doesn't drag down far enough, then - // #onTrackingStopped is called with `false` but #isExpanded is true. - // So, we need *both* #onTrackingStopped called with `true` *and* #isExpanded to be true in - // order to confirm that the shade successfully opened. - boolean shadeExpansionFromStatusBarSucceeded = expand && isExpanded(); - if (shadeExpansionFromStatusBarSucceeded) { - InteractionJankMonitorWrapper.end( - InteractionJankMonitorWrapper.CUJ_SHADE_EXPAND_FROM_STATUS_BAR); - } else { - InteractionJankMonitorWrapper.cancel( - InteractionJankMonitorWrapper.CUJ_SHADE_EXPAND_FROM_STATUS_BAR); - } - } - - @Override public void updateTouchableRegion() { //A layout will ensure that onComputeInternalInsets will be called and after that we can // resize the layout. Make sure that the window stays small for one frame until the @@ -5318,11 +5285,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump public void startExpand(float x, float y, boolean startTracking, float expandedHeight) { startExpandMotion(x, y, startTracking, expandedHeight); } - - @Override - public void clearNotificationEffects() { - mCentralSurfaces.clearNotificationEffects(); - } } private final class ShadeAccessibilityDelegate extends AccessibilityDelegate { diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index 0f85c7616071..880ba92123c6 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -37,6 +37,7 @@ import com.android.keyguard.LockIconViewController; import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.systemui.Dumpable; import com.android.systemui.R; +import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.back.domain.interactor.BackActionInteractor; import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor; import com.android.systemui.bouncer.ui.binder.KeyguardBouncerViewBinder; @@ -560,7 +561,9 @@ public class NotificationShadeWindowViewController implements Dumpable { void setExpandAnimationRunning(boolean running) { if (mExpandAnimationRunning != running) { // TODO(b/288507023): Remove this log. - Log.d(TAG, "Setting mExpandAnimationRunning=" + running); + if (ActivityLaunchAnimator.DEBUG_LAUNCH_ANIMATION) { + Log.d(TAG, "Setting mExpandAnimationRunning=" + running); + } if (running) { mLaunchAnimationTimeout = mClock.uptimeMillis() + 5000; } diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt index 1121834f196d..cdbea8185edd 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt @@ -248,9 +248,6 @@ interface ShadeViewController { /** Sends an external (e.g. Status Bar) touch event to the Shade touch handler. */ fun handleExternalTouch(event: MotionEvent): Boolean - /** Starts tracking a shade expansion gesture that originated from the status bar. */ - fun startTrackingExpansionFromStatusBar() - /** * Performs haptic feedback from a view with a haptic feedback constant. * diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt index 6a2bef296b6b..189375620285 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt @@ -86,7 +86,6 @@ class ShadeViewControllerEmptyImpl @Inject constructor() : ShadeViewController { override fun handleExternalTouch(event: MotionEvent): Boolean { return false } - override fun startTrackingExpansionFromStatusBar() {} override fun performHapticFeedback(constant: Int) {} override val shadeHeadsUpTracker = ShadeHeadsUpTrackerEmptyImpl() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt index 0aedbf36563a..c62546f67f8d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt @@ -140,8 +140,9 @@ class NotificationLaunchAnimatorController( } override fun onIntentStarted(willAnimate: Boolean) { - // TODO(b/288507023): Remove this log. - Log.d(TAG, "onIntentStarted(willAnimate=$willAnimate)") + if (ActivityLaunchAnimator.DEBUG_LAUNCH_ANIMATION) { + Log.d(TAG, "onIntentStarted(willAnimate=$willAnimate)") + } notificationExpansionRepository.setIsExpandAnimationRunning(willAnimate) notificationEntry.isExpandAnimationRunning = willAnimate @@ -172,8 +173,9 @@ class NotificationLaunchAnimatorController( } override fun onLaunchAnimationCancelled(newKeyguardOccludedState: Boolean?) { - // TODO(b/288507023): Remove this log. - Log.d(TAG, "onLaunchAnimationCancelled()") + if (ActivityLaunchAnimator.DEBUG_LAUNCH_ANIMATION) { + Log.d(TAG, "onLaunchAnimationCancelled()") + } // TODO(b/184121838): Should we call InteractionJankMonitor.cancel if the animation started // here? @@ -191,8 +193,9 @@ class NotificationLaunchAnimatorController( } override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) { - // TODO(b/288507023): Remove this log. - Log.d(TAG, "onLaunchAnimationEnd()") + if (ActivityLaunchAnimator.DEBUG_LAUNCH_ANIMATION) { + Log.d(TAG, "onLaunchAnimationEnd()") + } jankMonitor.end(InteractionJankMonitor.CUJ_NOTIFICATION_APP_START) notification.isExpandAnimationRunning = false diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepository.kt index 8754c4a0d7c3..6f0a97adb311 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepository.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.data.repository import android.util.Log +import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.dagger.SysUISingleton import javax.inject.Inject import kotlinx.coroutines.flow.Flow @@ -40,8 +41,9 @@ class NotificationExpansionRepository @Inject constructor() { /** Sets whether the notification expansion animation is currently running. */ fun setIsExpandAnimationRunning(running: Boolean) { - // TODO(b/288507023): Remove this log. - Log.d(TAG, "setIsExpandAnimationRunning(running=$running)") + if (ActivityLaunchAnimator.DEBUG_LAUNCH_ANIMATION) { + Log.d(TAG, "setIsExpandAnimationRunning(running=$running)") + } _isExpandAnimationRunning.value = running } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java index b59e3e9182b8..e914de8de45a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java @@ -301,8 +301,6 @@ public interface CentralSurfaces extends Dumpable, LifecycleOwner { void awakenDreams(); - void clearNotificationEffects(); - boolean isBouncerShowing(); boolean isBouncerShowingScrimmed(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt index ba32fd3012be..15176d66c7be 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt @@ -84,7 +84,6 @@ abstract class CentralSurfacesEmptyImpl : CentralSurfaces { override fun shouldIgnoreTouch() = false override fun isDeviceInteractive() = false override fun awakenDreams() {} - override fun clearNotificationEffects() {} override fun isBouncerShowing() = false override fun isBouncerShowingScrimmed() = false override fun isBouncerShowingOverDream() = false diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 30e139f5fad6..d3a4034bbd47 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -3146,11 +3146,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } } - /** - * Clear Buzz/Beep/Blink. - */ - @Override - public void clearNotificationEffects() { + private void clearNotificationEffects() { try { mBarService.clearNotificationEffects(); } catch (RemoteException e) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java index 16c2e36af6b8..dcbaac20eacc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java @@ -17,9 +17,11 @@ package com.android.systemui.statusbar.phone; import android.content.Context; +import android.os.RemoteException; import android.view.MotionEvent; import android.view.ViewConfiguration; +import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.Gefingerpoken; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -31,6 +33,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableView; public class HeadsUpTouchHelper implements Gefingerpoken { private final HeadsUpManagerPhone mHeadsUpManager; + private final IStatusBarService mStatusBarService; private final Callback mCallback; private int mTrackingPointer; private final float mTouchSlop; @@ -43,9 +46,11 @@ public class HeadsUpTouchHelper implements Gefingerpoken { private ExpandableNotificationRow mPickedChild; public HeadsUpTouchHelper(HeadsUpManagerPhone headsUpManager, + IStatusBarService statusBarService, Callback callback, HeadsUpNotificationViewController notificationPanelView) { mHeadsUpManager = headsUpManager; + mStatusBarService = statusBarService; mCallback = callback; mPanel = notificationPanelView; Context context = mCallback.getContext(); @@ -119,7 +124,7 @@ public class HeadsUpTouchHelper implements Gefingerpoken { // This call needs to be after the expansion start otherwise we will get a // flicker of one frame as it's not expanded yet. mHeadsUpManager.unpinAll(true); - mPanel.clearNotificationEffects(); + clearNotificationEffects(); endMotion(); return true; } @@ -175,6 +180,14 @@ public class HeadsUpTouchHelper implements Gefingerpoken { mTouchingHeadsUpView = false; } + private void clearNotificationEffects() { + try { + mStatusBarService.clearNotificationEffects(); + } catch (RemoteException e) { + // Won't fail unless the world has ended. + } + } + public interface Callback { ExpandableView getChildAtRawPosition(float touchX, float touchY); boolean isExpanded(); @@ -191,8 +204,5 @@ public class HeadsUpTouchHelper implements Gefingerpoken { /** Called when a MotionEvent is about to trigger expansion. */ void startExpand(float newX, float newY, boolean startTracking, float expandedHeight); - - /** Clear any effects that were added for the expansion. */ - void clearNotificationEffects(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt index 23b0ee0ec9bc..dd471aa042fa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt @@ -206,7 +206,6 @@ private constructor( shadeLogger.logMotionEvent(event, "top edge touch ignored") return true } - shadeViewController.startTrackingExpansionFromStatusBar() } return shadeViewController.handleExternalTouch(event) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java index 1c9ec27c6a1b..4f57fd0d0a92 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -65,6 +65,7 @@ import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.testing.UiEventLoggerFake; +import com.android.internal.statusbar.IStatusBarService; import com.android.internal.util.LatencyTracker; import com.android.keyguard.KeyguardClockSwitch; import com.android.keyguard.KeyguardClockSwitchController; @@ -271,6 +272,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { @Mock protected KeyguardIndicationController mKeyguardIndicationController; @Mock protected FragmentService mFragmentService; @Mock protected FragmentHostManager mFragmentHostManager; + @Mock protected IStatusBarService mStatusBarService; @Mock protected NotificationRemoteInputManager mNotificationRemoteInputManager; @Mock protected RecordingController mRecordingController; @Mock protected LockscreenGestureLogger mLockscreenGestureLogger; @@ -621,6 +623,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { mNavigationBarController, mQsController, mFragmentService, + mStatusBarService, mContentResolver, mShadeHeaderController, mScreenOffAnimationController, diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index 1ce7d9691fb5..330e35b5aeca 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -74,6 +74,7 @@ import android.companion.IOnAssociationsChangedListener; import android.companion.IOnMessageReceivedListener; import android.companion.IOnTransportsChangedListener; import android.companion.ISystemDataTransferCallback; +import android.companion.datatransfer.PermissionSyncRequest; import android.companion.utils.FeatureUtils; import android.content.ComponentName; import android.content.Context; @@ -873,6 +874,24 @@ public class CompanionDeviceManagerService extends SystemService { } @Override + public void enablePermissionsSync(int associationId) { + getAssociationWithCallerChecks(associationId); + mSystemDataTransferProcessor.enablePermissionsSync(associationId); + } + + @Override + public void disablePermissionsSync(int associationId) { + getAssociationWithCallerChecks(associationId); + mSystemDataTransferProcessor.disablePermissionsSync(associationId); + } + + @Override + public PermissionSyncRequest getPermissionSyncRequest(int associationId) { + getAssociationWithCallerChecks(associationId); + return mSystemDataTransferProcessor.getPermissionSyncRequest(associationId); + } + + @Override @EnforcePermission(MANAGE_COMPANION_DEVICES) public void enableSecureTransport(boolean enabled) { enableSecureTransport_enforcePermission(); @@ -1041,7 +1060,7 @@ public class CompanionDeviceManagerService extends SystemService { String[] args, ShellCallback callback, ResultReceiver resultReceiver) throws RemoteException { new CompanionDeviceShellCommand(CompanionDeviceManagerService.this, mAssociationStore, - mDevicePresenceMonitor, mTransportManager, mSystemDataTransferRequestStore, + mDevicePresenceMonitor, mTransportManager, mSystemDataTransferProcessor, mAssociationRequestsProcessor) .exec(this, in, out, err, args, callback, resultReceiver); } diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java index d368b8626e2e..1f6261383961 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java @@ -27,7 +27,7 @@ import android.os.Binder; import android.os.ShellCommand; import android.util.proto.ProtoOutputStream; -import com.android.server.companion.datatransfer.SystemDataTransferRequestStore; +import com.android.server.companion.datatransfer.SystemDataTransferProcessor; import com.android.server.companion.datatransfer.contextsync.BitmapUtils; import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncController; import com.android.server.companion.presence.CompanionDevicePresenceMonitor; @@ -44,20 +44,20 @@ class CompanionDeviceShellCommand extends ShellCommand { private final CompanionDevicePresenceMonitor mDevicePresenceMonitor; private final CompanionTransportManager mTransportManager; - private final SystemDataTransferRequestStore mSystemDataTransferRequestStore; + private final SystemDataTransferProcessor mSystemDataTransferProcessor; private final AssociationRequestsProcessor mAssociationRequestsProcessor; CompanionDeviceShellCommand(CompanionDeviceManagerService service, AssociationStoreImpl associationStore, CompanionDevicePresenceMonitor devicePresenceMonitor, CompanionTransportManager transportManager, - SystemDataTransferRequestStore systemDataTransferRequestStore, + SystemDataTransferProcessor systemDataTransferProcessor, AssociationRequestsProcessor associationRequestsProcessor) { mService = service; mAssociationStore = associationStore; mDevicePresenceMonitor = devicePresenceMonitor; mTransportManager = transportManager; - mSystemDataTransferRequestStore = systemDataTransferRequestStore; + mSystemDataTransferProcessor = systemDataTransferProcessor; mAssociationRequestsProcessor = associationRequestsProcessor; } @@ -261,16 +261,47 @@ class CompanionDeviceShellCommand extends ShellCommand { break; } - case "allow-permission-sync": { - int userId = getNextIntArgRequired(); + case "get-perm-sync-state": { associationId = getNextIntArgRequired(); - boolean enabled = getNextBooleanArgRequired(); - PermissionSyncRequest request = new PermissionSyncRequest(associationId); - request.setUserId(userId); - request.setUserConsented(enabled); - mSystemDataTransferRequestStore.writeRequest(userId, request); + PermissionSyncRequest request = + mSystemDataTransferProcessor.getPermissionSyncRequest(associationId); + out.println((request == null ? "null" : request.isUserConsented())); + break; + } + + case "remove-perm-sync-state": { + associationId = getNextIntArgRequired(); + PermissionSyncRequest request = + mSystemDataTransferProcessor.getPermissionSyncRequest(associationId); + out.print((request == null ? "null" : request.isUserConsented())); + mSystemDataTransferProcessor.removePermissionSyncRequest(associationId); + request = mSystemDataTransferProcessor.getPermissionSyncRequest(associationId); + // should print " -> null" + out.println(" -> " + (request == null ? "null" : request.isUserConsented())); + break; + } + + case "enable-perm-sync": { + associationId = getNextIntArgRequired(); + PermissionSyncRequest request = + mSystemDataTransferProcessor.getPermissionSyncRequest(associationId); + out.print((request == null ? "null" : request.isUserConsented())); + mSystemDataTransferProcessor.enablePermissionsSync(associationId); + request = mSystemDataTransferProcessor.getPermissionSyncRequest(associationId); + out.println(" -> " + request.isUserConsented()); // should print " -> true" + break; + } + + case "disable-perm-sync": { + associationId = getNextIntArgRequired(); + PermissionSyncRequest request = + mSystemDataTransferProcessor.getPermissionSyncRequest(associationId); + out.print((request == null ? "null" : request.isUserConsented())); + mSystemDataTransferProcessor.disablePermissionsSync(associationId); + request = mSystemDataTransferProcessor.getPermissionSyncRequest(associationId); + out.println(" -> " + request.isUserConsented()); // should print " -> false" + break; } - break; default: return handleDefaultCommands(cmd); @@ -346,5 +377,14 @@ class CompanionDeviceShellCommand extends ShellCommand { pw.println(" create-emulated-transport <ASSOCIATION_ID>"); pw.println(" Create an EmulatedTransport for testing purposes only"); + + pw.println(" enable-perm-sync <ASSOCIATION_ID>"); + pw.println(" Enable perm sync for the association."); + pw.println(" disable-perm-sync <ASSOCIATION_ID>"); + pw.println(" Disable perm sync for the association."); + pw.println(" get-perm-sync-state <ASSOCIATION_ID>"); + pw.println(" Get perm sync state for the association."); + pw.println(" remove-perm-sync-state <ASSOCIATION_ID>"); + pw.println(" Remove perm sync state for the association."); } } diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java index 13f41ed2ebb1..42b5a8ba8a4d 100644 --- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java +++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java @@ -139,6 +139,13 @@ public class SystemDataTransferProcessor { @UserIdInt int userId, int associationId) { if (PackageUtils.isPackageAllowlisted(mContext, mPackageManager, packageName)) { Slog.i(LOG_TAG, "User consent Intent should be skipped. Returning null."); + // Auto enable perm sync for the whitelisted packages, but don't override user decision + PermissionSyncRequest request = getPermissionSyncRequest(associationId); + if (request == null) { + PermissionSyncRequest newRequest = new PermissionSyncRequest(associationId); + newRequest.setUserConsented(true); + mSystemDataTransferRequestStore.writeRequest(userId, newRequest); + } return null; } @@ -185,29 +192,17 @@ public class SystemDataTransferProcessor { final AssociationInfo association = resolveAssociation(packageName, userId, associationId); // Check if the request has been consented by the user. - if (PackageUtils.isPackageAllowlisted(mContext, mPackageManager, packageName)) { - Slog.i(LOG_TAG, "Skip user consent check due to the same OEM package."); - } else { - List<SystemDataTransferRequest> storedRequests = - mSystemDataTransferRequestStore.readRequestsByAssociationId(userId, - associationId); - boolean hasConsented = false; - for (SystemDataTransferRequest storedRequest : storedRequests) { - if (storedRequest instanceof PermissionSyncRequest - && storedRequest.isUserConsented()) { - hasConsented = true; - break; - } - } - if (!hasConsented) { - String message = "User " + userId + " hasn't consented permission sync."; - Slog.e(LOG_TAG, message); - try { - callback.onError(message); - } catch (RemoteException ignored) { - } - return; + PermissionSyncRequest request = getPermissionSyncRequest(associationId); + if (request == null || !request.isUserConsented()) { + String message = + "User " + userId + " hasn't consented permission sync for associationId [" + + associationId + "."; + Slog.e(LOG_TAG, message); + try { + callback.onError(message); + } catch (RemoteException ignored) { } + return; } // Start permission sync @@ -225,6 +220,50 @@ public class SystemDataTransferProcessor { } } + /** + * Enable perm sync for the association + */ + public void enablePermissionsSync(int associationId) { + int userId = mAssociationStore.getAssociationById(associationId).getUserId(); + PermissionSyncRequest request = new PermissionSyncRequest(associationId); + request.setUserConsented(true); + mSystemDataTransferRequestStore.writeRequest(userId, request); + } + + /** + * Disable perm sync for the association + */ + public void disablePermissionsSync(int associationId) { + int userId = mAssociationStore.getAssociationById(associationId).getUserId(); + PermissionSyncRequest request = new PermissionSyncRequest(associationId); + request.setUserConsented(false); + mSystemDataTransferRequestStore.writeRequest(userId, request); + } + + /** + * Get perm sync request for the association. + */ + @Nullable + public PermissionSyncRequest getPermissionSyncRequest(int associationId) { + int userId = mAssociationStore.getAssociationById(associationId).getUserId(); + List<SystemDataTransferRequest> requests = + mSystemDataTransferRequestStore.readRequestsByAssociationId(userId, associationId); + for (SystemDataTransferRequest request : requests) { + if (request instanceof PermissionSyncRequest) { + return (PermissionSyncRequest) request; + } + } + return null; + } + + /** + * Remove perm sync request for the association. + */ + public void removePermissionSyncRequest(int associationId) { + int userId = mAssociationStore.getAssociationById(associationId).getUserId(); + mSystemDataTransferRequestStore.removeRequestsByAssociationId(userId, associationId); + } + private void onReceivePermissionRestore(byte[] message) { Slog.i(LOG_TAG, "Applying permissions."); // Start applying permissions diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java index 720cefa11d7c..9f489e8d613a 100644 --- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java +++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java @@ -104,7 +104,7 @@ public class SystemDataTransferRequestStore { } @NonNull - List<SystemDataTransferRequest> readRequestsByAssociationId(@UserIdInt int userId, + public List<SystemDataTransferRequest> readRequestsByAssociationId(@UserIdInt int userId, int associationId) { List<SystemDataTransferRequest> cachedRequests; synchronized (mLock) { diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index 10a1b9e6c095..6d2fc0dc21f6 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -119,7 +119,9 @@ public class SettingsToPropertiesMapper { @VisibleForTesting static final String[] sDeviceConfigAconfigScopes = new String[] { "android_core_networking", + "angle", "arc_next", + "bluetooth", "biometrics_framework", "biometrics_integration", "camera_platform", @@ -128,19 +130,26 @@ public class SettingsToPropertiesMapper { "car_security", "car_telemetry", "codec_fwk", + "companion", + "context_hub", "core_experiments_team_internal", "haptics", "hardware_backed_security_mainline", + "media_audio", "media_solutions", "nfc", "pixel_system_sw_touch", "pixel_watch", + "platform_security", "power", + "preload_safety", "responsible_apis", "rust", + "system_performance", "test_suites", "text", "threadnetwork", + "tv_system_ui", "vibrator", "wear_frameworks", "wear_system_health", diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 27708330efd3..de4ad20bdccc 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -2212,6 +2212,7 @@ class UserController implements Handler.Callback { final IRemoteCallback callback = new IRemoteCallback.Stub() { @Override public void sendResult(Bundle data) throws RemoteException { + asyncTraceEnd("onUserSwitching-" + name, newUserId); synchronized (mLock) { long delayForObserver = SystemClock.elapsedRealtime() - dispatchStartedTimeForObserver; @@ -2229,8 +2230,6 @@ class UserController implements Handler.Callback { + " ms after dispatchUserSwitch."); } - TimingsTraceAndSlog t2 = new TimingsTraceAndSlog(TAG); - t2.traceBegin("onUserSwitchingReply-" + name); curWaitingUserSwitchCallbacks.remove(name); // Continue switching if all callbacks have been notified and // user switching session is still valid @@ -2239,13 +2238,11 @@ class UserController implements Handler.Callback { == mCurWaitingUserSwitchCallbacks)) { sendContinueUserSwitchLU(uss, oldUserId, newUserId); } - t2.traceEnd(); } } }; - t.traceBegin("onUserSwitching-" + name); + asyncTraceBegin("onUserSwitching-" + name, newUserId); mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(newUserId, callback); - t.traceEnd(); } catch (RemoteException e) { // Ignore } diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java index d88fe8a6c201..d2aff254890d 100644 --- a/services/core/java/com/android/server/dreams/DreamManagerService.java +++ b/services/core/java/com/android/server/dreams/DreamManagerService.java @@ -324,7 +324,8 @@ public final class DreamManagerService extends SystemService { pw.println("mWhenToDream=" + mWhenToDream); pw.println("mKeepDreamingWhenUnpluggingDefault=" + mKeepDreamingWhenUnpluggingDefault); pw.println("getDozeComponent()=" + getDozeComponent()); - pw.println("mDreamOverlayServiceName=" + mDreamOverlayServiceName.flattenToString()); + pw.println("mDreamOverlayServiceName=" + + ComponentName.flattenToShortString(mDreamOverlayServiceName)); pw.println(); DumpUtils.dumpAsync(mHandler, (pw1, prefix) -> mController.dump(pw1), pw, "", 200); diff --git a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java index 2ede56dcecd9..a2c8748a9142 100644 --- a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java +++ b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java @@ -62,10 +62,10 @@ class GestureMonitorSpyWindow { mWindowHandle.ownerUid = uid; mWindowHandle.scaleFactor = 1.0f; mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */); - mWindowHandle.inputConfig = - InputConfig.NOT_FOCUSABLE | InputConfig.SPY | InputConfig.TRUSTED_OVERLAY; + mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.SPY; final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + mWindowHandle.setTrustedOverlay(t, mInputSurface, true); t.setInputWindowInfo(mInputSurface, mWindowHandle); t.setLayer(mInputSurface, InputManagerService.INPUT_OVERLAY_LAYER_GESTURE_MONITOR); t.setPosition(mInputSurface, 0, 0); diff --git a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java index 7726f40fa2ae..dbbbed31df76 100644 --- a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java +++ b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java @@ -57,13 +57,13 @@ final class HandwritingEventReceiverSurface { InputConfig.NOT_FOCUSABLE | InputConfig.NOT_TOUCHABLE | InputConfig.SPY - | InputConfig.INTERCEPTS_STYLUS - | InputConfig.TRUSTED_OVERLAY; + | InputConfig.INTERCEPTS_STYLUS; // Configure the surface to receive stylus events across the entire display. mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */); final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + mWindowHandle.setTrustedOverlay(t, mInputSurface, true); t.setInputWindowInfo(mInputSurface, mWindowHandle); t.setLayer(mInputSurface, InputManagerService.INPUT_OVERLAY_LAYER_HANDWRITING_SURFACE); t.setPosition(mInputSurface, 0, 0); diff --git a/services/core/java/com/android/server/inputmethod/ImeTrackerService.java b/services/core/java/com/android/server/inputmethod/ImeTrackerService.java index 2efb0beaa567..b090334db352 100644 --- a/services/core/java/com/android/server/inputmethod/ImeTrackerService.java +++ b/services/core/java/com/android/server/inputmethod/ImeTrackerService.java @@ -259,19 +259,16 @@ public final class ImeTrackerService extends IImeTracker.Stub { .withZone(ZoneId.systemDefault()); pw.print(prefix); - pw.println("ImeTrackerService#History.mLiveEntries: " - + mLiveEntries.size() + " elements"); + pw.println("mLiveEntries: " + mLiveEntries.size() + " elements"); for (final var entry: mLiveEntries.values()) { - dumpEntry(entry, pw, prefix, formatter); + dumpEntry(entry, pw, prefix + " ", formatter); } - pw.print(prefix); - pw.println("ImeTrackerService#History.mEntries: " - + mEntries.size() + " elements"); + pw.println("mEntries: " + mEntries.size() + " elements"); for (final var entry: mEntries) { - dumpEntry(entry, pw, prefix, formatter); + dumpEntry(entry, pw, prefix + " ", formatter); } } @@ -279,22 +276,22 @@ public final class ImeTrackerService extends IImeTracker.Stub { private void dumpEntry(@NonNull Entry entry, @NonNull PrintWriter pw, @NonNull String prefix, @NonNull DateTimeFormatter formatter) { pw.print(prefix); - pw.print(" #" + entry.mSequenceNumber); + pw.print("#" + entry.mSequenceNumber); pw.print(" " + ImeTracker.Debug.typeToString(entry.mType)); pw.print(" - " + ImeTracker.Debug.statusToString(entry.mStatus)); pw.print(" - " + entry.mTag); pw.println(" (" + entry.mDuration + "ms):"); pw.print(prefix); - pw.print(" startTime=" + formatter.format(Instant.ofEpochMilli(entry.mStartTime))); + pw.print(" startTime=" + formatter.format(Instant.ofEpochMilli(entry.mStartTime))); pw.println(" " + ImeTracker.Debug.originToString(entry.mOrigin)); pw.print(prefix); - pw.print(" reason=" + InputMethodDebug.softInputDisplayReasonToString(entry.mReason)); + pw.print(" reason=" + InputMethodDebug.softInputDisplayReasonToString(entry.mReason)); pw.println(" " + ImeTracker.Debug.phaseToString(entry.mPhase)); pw.print(prefix); - pw.println(" requestWindowName=" + entry.mRequestWindowName); + pw.println(" requestWindowName=" + entry.mRequestWindowName); } /** A history entry. */ diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java index 2e0274b79d1f..0dd48ae6c9e1 100644 --- a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java +++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java @@ -588,12 +588,12 @@ public final class ImeVisibilityStateComputer { proto.write(INPUT_SHOWN, mInputShown); } - void dump(PrintWriter pw) { + void dump(@NonNull PrintWriter pw, @NonNull String prefix) { final Printer p = new PrintWriterPrinter(pw); - p.println(" mRequestedShowExplicitly=" + mRequestedShowExplicitly + p.println(prefix + "mRequestedShowExplicitly=" + mRequestedShowExplicitly + " mShowForced=" + mShowForced); - p.println(" mImeHiddenByDisplayPolicy=" + mPolicy.isImeHiddenByDisplayPolicy()); - p.println(" mInputShown=" + mInputShown); + p.println(prefix + "mImeHiddenByDisplayPolicy=" + mPolicy.isImeHiddenByDisplayPolicy()); + p.println(prefix + "mInputShown=" + mInputShown); } /** diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 177a81f47a92..699e9c8bcfe0 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -358,12 +358,12 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @Override public String toString() { - return "SessionState{uid " + mClient.mUid + " pid " + mClient.mPid - + " method " + Integer.toHexString( + return "SessionState{uid=" + mClient.mUid + " pid=" + mClient.mPid + + " method=" + Integer.toHexString( IInputMethodInvoker.getBinderIdentityHashCode(mMethod)) - + " session " + Integer.toHexString( + + " session=" + Integer.toHexString( System.identityHashCode(mSession)) - + " channel " + mChannel + + " channel=" + mChannel + "}"; } @@ -388,9 +388,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @Override public String toString() { - return "AccessibilitySessionState{uid " + mClient.mUid + " pid " + mClient.mPid - + " id " + Integer.toHexString(mId) - + " session " + Integer.toHexString( + return "AccessibilitySessionState{uid=" + mClient.mUid + " pid=" + mClient.mPid + + " id=" + Integer.toHexString(mId) + + " session=" + Integer.toHexString( System.identityHashCode(mSession)) + "}"; } @@ -884,47 +884,47 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub continue; } pw.print(prefix); - pw.println("SoftInputShowHideHistory #" + entry.mSequenceNumber + ":"); + pw.println("SoftInputShowHide #" + entry.mSequenceNumber + ":"); pw.print(prefix); - pw.println(" time=" + formatter.format(Instant.ofEpochMilli(entry.mWallTime)) + pw.println(" time=" + formatter.format(Instant.ofEpochMilli(entry.mWallTime)) + " (timestamp=" + entry.mTimestamp + ")"); pw.print(prefix); - pw.print(" reason=" + InputMethodDebug.softInputDisplayReasonToString( + pw.print(" reason=" + InputMethodDebug.softInputDisplayReasonToString( entry.mReason)); pw.println(" inFullscreenMode=" + entry.mInFullscreenMode); pw.print(prefix); - pw.println(" requestClient=" + entry.mClientState); + pw.println(" requestClient=" + entry.mClientState); pw.print(prefix); - pw.println(" focusedWindowName=" + entry.mFocusedWindowName); + pw.println(" focusedWindowName=" + entry.mFocusedWindowName); pw.print(prefix); - pw.println(" requestWindowName=" + entry.mRequestWindowName); + pw.println(" requestWindowName=" + entry.mRequestWindowName); pw.print(prefix); - pw.println(" imeControlTargetName=" + entry.mImeControlTargetName); + pw.println(" imeControlTargetName=" + entry.mImeControlTargetName); pw.print(prefix); - pw.println(" imeTargetNameFromWm=" + entry.mImeTargetNameFromWm); + pw.println(" imeTargetNameFromWm=" + entry.mImeTargetNameFromWm); pw.print(prefix); - pw.println(" imeSurfaceParentName=" + entry.mImeSurfaceParentName); + pw.println(" imeSurfaceParentName=" + entry.mImeSurfaceParentName); pw.print(prefix); - pw.print(" editorInfo: "); + pw.print(" editorInfo:"); if (entry.mEditorInfo != null) { pw.print(" inputType=" + entry.mEditorInfo.inputType); pw.print(" privateImeOptions=" + entry.mEditorInfo.privateImeOptions); pw.println(" fieldId (viewId)=" + entry.mEditorInfo.fieldId); } else { - pw.println("null"); + pw.println(" null"); } pw.print(prefix); - pw.println(" focusedWindowSoftInputMode=" + InputMethodDebug.softInputModeToString( + pw.println(" focusedWindowSoftInputMode=" + InputMethodDebug.softInputModeToString( entry.mFocusedWindowSoftInputMode)); } } @@ -1052,30 +1052,30 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub pw.println("StartInput #" + entry.mSequenceNumber + ":"); pw.print(prefix); - pw.println(" time=" + formatter.format(Instant.ofEpochMilli(entry.mWallTime)) + pw.println(" time=" + formatter.format(Instant.ofEpochMilli(entry.mWallTime)) + " (timestamp=" + entry.mTimestamp + ")" + " reason=" + InputMethodDebug.startInputReasonToString(entry.mStartInputReason) + " restarting=" + entry.mRestarting); pw.print(prefix); - pw.print(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]"); + pw.print(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]"); pw.print(" imeUserId=" + entry.mImeUserId); pw.println(" imeDisplayId=" + entry.mImeDisplayId); pw.print(prefix); - pw.println(" targetWin=" + entry.mTargetWindowString + pw.println(" targetWin=" + entry.mTargetWindowString + " [" + entry.mEditorInfo.packageName + "]" + " targetUserId=" + entry.mTargetUserId + " targetDisplayId=" + entry.mTargetDisplayId + " clientBindSeq=" + entry.mClientBindSequenceNumber); pw.print(prefix); - pw.println(" softInputMode=" + InputMethodDebug.softInputModeToString( + pw.println(" softInputMode=" + InputMethodDebug.softInputModeToString( entry.mTargetWindowSoftInputMode)); pw.print(prefix); - pw.println(" inputType=0x" + Integer.toHexString(entry.mEditorInfo.inputType) + pw.println(" inputType=0x" + Integer.toHexString(entry.mEditorInfo.inputType) + " imeOptions=0x" + Integer.toHexString(entry.mEditorInfo.imeOptions) + " fieldId=0x" + Integer.toHexString(entry.mEditorInfo.fieldId) + " fieldName=" + entry.mEditorInfo.fieldName @@ -5952,11 +5952,11 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub p.println(" InputMethod #" + i + ":"); info.dump(p, " "); } - p.println(" Clients:"); + p.println(" ClientStates:"); final int numClients = mClients.size(); for (int i = 0; i < numClients; ++i) { final ClientState ci = mClients.valueAt(i); - p.println(" Client " + ci + ":"); + p.println(" " + ci + ":"); p.println(" client=" + ci.mClient); p.println(" fallbackInputConnection=" + ci.mFallbackInputConnection); p.println(" sessionRequested=" + ci.mSessionRequested); @@ -5983,7 +5983,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub method = getCurMethodLocked(); p.println(" mCurMethod=" + getCurMethodLocked()); p.println(" mEnabledSession=" + mEnabledSession); - mVisibilityStateComputer.dump(pw); + mVisibilityStateComputer.dump(pw, " "); p.println(" mInFullscreenMode=" + mInFullscreenMode); p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive); p.println(" ENABLE_HIDE_IME_CAPTION_BAR=" @@ -5997,13 +5997,13 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub mSettings.dumpLocked(p, " "); p.println(" mStartInputHistory:"); - mStartInputHistory.dump(pw, " "); + mStartInputHistory.dump(pw, " "); p.println(" mSoftInputShowHideHistory:"); - mSoftInputShowHideHistory.dump(pw, " "); + mSoftInputShowHideHistory.dump(pw, " "); p.println(" mImeTrackerService#History:"); - mImeTrackerService.dump(pw, " "); + mImeTrackerService.dump(pw, " "); } // Exit here for critical dump, as remaining sections require IPCs to other processes. diff --git a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java index 487346763f0f..7cf6eae892ed 100644 --- a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java +++ b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java @@ -154,6 +154,23 @@ class AudioPlayerStateMonitor { } /** + * Returns whether the given uid corresponds to the last process to audio or not. + * + * <p> This is useful for handling the cases where the foreground app is playing media without + * a media session. Then, volume events should affect the local music stream rather than other + * media sessions. + * + * @return {@code true} if the given uid corresponds to the last process to audio or + * {@code false} otherwise. + */ + public boolean hasUidPlayedAudioLast(int uid) { + synchronized (mLock) { + return !mSortedAudioPlaybackClientUids.isEmpty() + && uid == mSortedAudioPlaybackClientUids.get(0); + } + } + + /** * Returns if the audio playback is active for the uid. */ public boolean isPlaybackActive(int uid) { @@ -234,7 +251,7 @@ class AudioPlayerStateMonitor { } } - // Update mSortedAuioPlaybackClientUids. + // Update mSortedAudioPlaybackClientUids. for (int i = 0; i < activeAudioPlaybackConfigs.size(); ++i) { AudioPlaybackConfiguration config = activeAudioPlaybackConfigs.valueAt(i); final int uid = config.getClientUid(); diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index f4c95185210a..803ab28f2a65 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -19,7 +19,6 @@ package com.android.server.media; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.os.UserHandle.ALL; import static android.os.UserHandle.CURRENT; - import static com.android.server.media.MediaKeyDispatcher.KEY_EVENT_LONG_PRESS; import static com.android.server.media.MediaKeyDispatcher.isDoubleTapOverridden; import static com.android.server.media.MediaKeyDispatcher.isLongPressOverridden; @@ -85,6 +84,7 @@ import android.view.ViewConfiguration; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; +import com.android.media.flags.Flags; import com.android.server.LocalManagerRegistry; import com.android.server.LocalServices; import com.android.server.SystemService; @@ -2192,6 +2192,21 @@ public class MediaSessionService extends SystemService implements Monitor { isValidLocalStreamType(suggestedStream) && AudioSystem.isStreamActive(suggestedStream, 0); + if (session != null && session.getUid() != uid + && mAudioPlayerStateMonitor.hasUidPlayedAudioLast(uid)) { + if (Flags.adjustVolumeForForegroundAppPlayingAudioWithoutMediaSession()) { + // The app in the foreground has been the last app to play media locally. + // Therefore, We ignore the chosen session so that volume events affect the + // local music stream instead. See b/275185436 for details. + Log.d(TAG, "Ignoring session=" + session + " and adjusting suggestedStream=" + + suggestedStream + " instead"); + session = null; + } else { + Log.d(TAG, "Session=" + session + " will not be not ignored and will receive" + + " the volume adjustment event"); + } + } + if (session == null || preferSuggestedStream) { if (DEBUG_KEY_EVENT) { Log.d(TAG, "Adjusting suggestedStream=" + suggestedStream + " by " + direction diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java index 74d341719603..4c9ec9d863bb 100644 --- a/services/core/java/com/android/server/wm/ActivityClientController.java +++ b/services/core/java/com/android/server/wm/ActivityClientController.java @@ -1020,7 +1020,7 @@ class ActivityClientController extends IActivityClientController.Stub { try { final ClientTransaction transaction = ClientTransaction.obtain( r.app.getThread(), r.token); - transaction.addCallback(EnterPipRequestedItem.obtain()); + transaction.addCallback(EnterPipRequestedItem.obtain(r.token)); mService.getLifecycleManager().scheduleTransaction(transaction); return true; } catch (Exception e) { @@ -1042,7 +1042,7 @@ class ActivityClientController extends IActivityClientController.Stub { try { final ClientTransaction transaction = ClientTransaction.obtain( r.app.getThread(), r.token); - transaction.addCallback(PipStateTransactionItem.obtain(pipState)); + transaction.addCallback(PipStateTransactionItem.obtain(r.token, pipState)); mService.getLifecycleManager().scheduleTransaction(transaction); } catch (Exception e) { Slog.w(TAG, "Failed to send pip state transaction item: " diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index b2eb3830b02e..dca2b6f8f2af 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1443,7 +1443,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A config); mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token, - MoveToDisplayItem.obtain(displayId, config)); + MoveToDisplayItem.obtain(token, displayId, config)); } catch (RemoteException e) { // If process died, whatever. } @@ -1460,7 +1460,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A + "config: %s", this, config); mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token, - ActivityConfigurationChangeItem.obtain(config)); + ActivityConfigurationChangeItem.obtain(token, config)); } catch (RemoteException e) { // If process died, whatever. } @@ -1481,7 +1481,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A this, onTop); mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token, - TopResumedActivityChangeItem.obtain(onTop)); + TopResumedActivityChangeItem.obtain(token, onTop)); } catch (RemoteException e) { // If process died, whatever. Slog.w(TAG, "Failed to send top-resumed=" + onTop + " to " + this, e); @@ -2728,7 +2728,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A try { mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_ATTACH_TO_CLIENT; mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token, - TransferSplashScreenViewStateItem.obtain(parcelable, + TransferSplashScreenViewStateItem.obtain(token, parcelable, windowAnimationLeash)); scheduleTransferSplashScreenTimeout(); } catch (Exception e) { @@ -3895,7 +3895,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A try { if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + this); mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token, - DestroyActivityItem.obtain(finishing, configChangeFlags)); + DestroyActivityItem.obtain(token, finishing, configChangeFlags)); } catch (Exception e) { // We can just ignore exceptions here... if the process has crashed, our death // notification will clean things up. @@ -4803,7 +4803,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final ArrayList<ResultInfo> list = new ArrayList<ResultInfo>(); list.add(new ResultInfo(resultWho, requestCode, resultCode, data)); mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token, - ActivityResultItem.obtain(list)); + ActivityResultItem.obtain(token, list)); return; } catch (Exception e) { Slog.w(TAG, "Exception thrown sending result to " + this, e); @@ -4816,7 +4816,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final ClientTransaction transaction = ClientTransaction.obtain(app.getThread(), token); // Build result to be returned immediately. transaction.addCallback(ActivityResultItem.obtain( - List.of(new ResultInfo(resultWho, requestCode, resultCode, data)))); + token, List.of(new ResultInfo(resultWho, requestCode, resultCode, data)))); // When the activity result is delivered, the activity will transition to RESUMED. // Since the activity is only resumed so the result can be immediately delivered, // return it to its original lifecycle state. @@ -4857,13 +4857,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private ActivityLifecycleItem getLifecycleItemForCurrentStateForResult() { switch (mState) { case STARTED: - return StartActivityItem.obtain(null); + return StartActivityItem.obtain(token, null); case PAUSING: case PAUSED: - return PauseActivityItem.obtain(); + return PauseActivityItem.obtain(token); case STOPPING: case STOPPED: - return StopActivityItem.obtain(configChangeFlags); + return StopActivityItem.obtain(token, configChangeFlags); default: // Do not send a result immediately if the activity is in state INITIALIZING, // RESTARTING_PROCESS, FINISHING, DESTROYING, or DESTROYED. @@ -4909,7 +4909,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // so only if activity is currently RESUMED. Otherwise, client may have extra // life-cycle calls to RESUMED (and PAUSED later). mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token, - NewIntentItem.obtain(ar, mState == RESUMED)); + NewIntentItem.obtain(token, ar, mState == RESUMED)); unsent = false; } catch (RemoteException e) { Slog.w(TAG, "Exception thrown sending new intent to " + this, e); @@ -6144,7 +6144,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A shortComponentName, "userLeaving=false", "make-active"); try { mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token, - PauseActivityItem.obtain(finishing, false /* userLeaving */, + PauseActivityItem.obtain(token, finishing, false /* userLeaving */, configChangeFlags, false /* dontReport */, mAutoEnteringPip)); } catch (Exception e) { Slog.w(TAG, "Exception thrown sending pause: " + intent.getComponent(), e); @@ -6157,7 +6157,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A try { mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token, - StartActivityItem.obtain(takeOptions())); + StartActivityItem.obtain(token, takeOptions())); } catch (Exception e) { Slog.w(TAG, "Exception thrown sending start: " + intent.getComponent(), e); } @@ -6455,7 +6455,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A EventLogTags.writeWmStopActivity( mUserId, System.identityHashCode(this), shortComponentName); mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token, - StopActivityItem.obtain(configChangeFlags)); + StopActivityItem.obtain(token, configChangeFlags)); mAtmService.mH.postDelayed(mStopTimeoutRunnable, STOP_TIMEOUT); } catch (Exception e) { @@ -9870,17 +9870,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A (andResume ? "RESUMED" : "PAUSED"), this, Debug.getCallers(6)); forceNewConfig = false; startRelaunching(); - final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(pendingResults, - pendingNewIntents, configChangeFlags, + final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(token, + pendingResults, pendingNewIntents, configChangeFlags, new MergedConfiguration(getProcessGlobalConfiguration(), getMergedOverrideConfiguration()), preserveWindow); final ActivityLifecycleItem lifecycleItem; if (andResume) { - lifecycleItem = ResumeActivityItem.obtain(isTransitionForward(), + lifecycleItem = ResumeActivityItem.obtain(token, isTransitionForward(), shouldSendCompatFakeFocus()); } else { - lifecycleItem = PauseActivityItem.obtain(); + lifecycleItem = PauseActivityItem.obtain(token); } final ClientTransaction transaction = ClientTransaction.obtain(app.getThread(), token); transaction.addCallback(callbackItem); @@ -9977,7 +9977,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // {@link ActivityTaskManagerService.activityStopped}). try { mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token, - StopActivityItem.obtain(0 /* configChanges */)); + StopActivityItem.obtain(token, 0 /* configChanges */)); } catch (RemoteException e) { Slog.w(TAG, "Exception thrown during restart " + this, e); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 69e679d71669..e523119ee9a0 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -929,8 +929,8 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { final IBinder fragmentToken = r.getTaskFragment().getFragmentToken(); final int deviceId = getDeviceIdForDisplayId(r.getDisplayId()); - clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent), - System.identityHashCode(r), r.info, + clientTransaction.addCallback(LaunchActivityItem.obtain(r.token, + new Intent(r.intent), System.identityHashCode(r), r.info, // TODO: Have this take the merged configuration instead of separate global // and override configs. mergedConfiguration.getGlobalConfiguration(), @@ -944,10 +944,10 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { // Set desired final state. final ActivityLifecycleItem lifecycleItem; if (andResume) { - lifecycleItem = ResumeActivityItem.obtain(isTransitionForward, + lifecycleItem = ResumeActivityItem.obtain(r.token, isTransitionForward, r.shouldSendCompatFakeFocus()); } else { - lifecycleItem = PauseActivityItem.obtain(); + lifecycleItem = PauseActivityItem.obtain(r.token); } clientTransaction.setLifecycleStateRequest(lifecycleItem); diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java index f96f99d50053..c4ed0dd9d606 100644 --- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java @@ -228,9 +228,9 @@ final class DisplayRotationCompatPolicy { + "activityRecord=%s", activity); final ClientTransaction transaction = ClientTransaction.obtain( activity.app.getThread(), activity.token); - transaction.addCallback( - RefreshCallbackItem.obtain(cycleThroughStop ? ON_STOP : ON_PAUSE)); - transaction.setLifecycleStateRequest(ResumeActivityItem.obtain( + transaction.addCallback(RefreshCallbackItem.obtain(activity.token, + cycleThroughStop ? ON_STOP : ON_PAUSE)); + transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(activity.token, /* isForward */ false, /* shouldSendCompatFakeFocus */ false)); activity.mAtmService.getLifecycleManager().scheduleTransaction(transaction); mHandler.postDelayed( diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 0f1a1053716e..8519e4d3e53a 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -21,7 +21,6 @@ import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT; import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK; import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP; - import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.DragDropController.MSG_ANIMATION_END; @@ -33,7 +32,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACT import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.MY_PID; import static com.android.server.wm.WindowManagerService.MY_UID; - import static java.util.concurrent.CompletableFuture.completedFuture; import android.animation.Animator; @@ -48,7 +46,6 @@ import android.hardware.input.InputManagerGlobal; import android.os.Binder; import android.os.Build; import android.os.IBinder; -import android.os.InputConfig; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; @@ -186,8 +183,13 @@ class DragState { // Crop the input surface to the display size. mTmpClipRect.set(0, 0, mDisplaySize.x, mDisplaySize.y); + // Make trusted overlay to not block any touches while D&D ongoing and allowing + // touches to pass through to windows underneath. This allows user to interact with the + // UI to navigate while dragging. + h.setTrustedOverlay(mTransaction, mInputSurface, true); mTransaction.show(mInputSurface) .setInputWindowInfo(mInputSurface, h) + .setTrustedOverlay(mInputSurface, true) .setLayer(mInputSurface, Integer.MAX_VALUE) .setCrop(mInputSurface, mTmpClipRect); @@ -377,11 +379,6 @@ class DragState { mDragWindowHandle.ownerUid = MY_UID; mDragWindowHandle.scaleFactor = 1.0f; - // InputConfig.TRUSTED_OVERLAY: To not block any touches while D&D ongoing and allowing - // touches to pass through to windows underneath. This allows user to interact with the - // UI to navigate while dragging. - mDragWindowHandle.inputConfig = InputConfig.TRUSTED_OVERLAY; - // The drag window cannot receive new touches. mDragWindowHandle.touchableRegion.setEmpty(); diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java index 39622c1c5aaf..c21930dab5eb 100644 --- a/services/core/java/com/android/server/wm/InputConsumerImpl.java +++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java @@ -74,7 +74,7 @@ class InputConsumerImpl implements IBinder.DeathRecipient { mWindowHandle.ownerPid = WindowManagerService.MY_PID; mWindowHandle.ownerUid = WindowManagerService.MY_UID; mWindowHandle.scaleFactor = 1.0f; - mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.TRUSTED_OVERLAY; + mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE; mInputSurface = mService.makeSurfaceBuilder( mService.mRoot.getDisplayContent(displayId).getSession()) @@ -129,12 +129,14 @@ class InputConsumerImpl implements IBinder.DeathRecipient { void show(SurfaceControl.Transaction t, WindowContainer w) { t.show(mInputSurface); + mWindowHandle.setTrustedOverlay(t, mInputSurface, true); t.setInputWindowInfo(mInputSurface, mWindowHandle); t.setRelativeLayer(mInputSurface, w.getSurfaceControl(), 1); } void show(SurfaceControl.Transaction t, int layer) { t.show(mInputSurface); + mWindowHandle.setTrustedOverlay(t, mInputSurface, true); t.setInputWindowInfo(mInputSurface, mWindowHandle); t.setLayer(mInputSurface, layer); } diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 825d38b3eed7..f77da6287176 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -40,12 +40,10 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; - import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.LOGTAG_INPUT_FOCUS; - import static java.lang.Integer.MAX_VALUE; import android.annotation.Nullable; @@ -732,7 +730,7 @@ final class InputMonitor { new InputWindowHandle(null /* inputApplicationHandle */, displayId)); inputWindowHandle.setName(name); inputWindowHandle.setLayoutParamsType(TYPE_SECURE_SYSTEM_OVERLAY); - inputWindowHandle.setTrustedOverlay(true); + inputWindowHandle.setTrustedOverlay(t, sc, true); populateOverlayInputInfo(inputWindowHandle); setInputWindowInfoIfNeeded(t, sc, inputWindowHandle); } diff --git a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java index 64b7a6064e45..90d81bd82087 100644 --- a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java +++ b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java @@ -195,6 +195,11 @@ class InputWindowHandleWrapper { mChanged = true; } + void setTrustedOverlay(SurfaceControl.Transaction t, SurfaceControl sc, + boolean trustedOverlay) { + mHandle.setTrustedOverlay(t, sc, trustedOverlay); + } + void setOwnerPid(int pid) { if (mHandle.ownerPid == pid) { return; diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java index 45cf10bd3f5e..579fd14f8fab 100644 --- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java +++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java @@ -29,6 +29,7 @@ import android.util.Slog; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.window.flags.FeatureFlags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -90,13 +91,6 @@ final class LetterboxConfiguration { "enable_app_compat_user_aspect_ratio_fullscreen"; private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_FULLSCREEN = true; - // Whether the letterbox wallpaper style is enabled by default - private static final String KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER = - "enable_letterbox_background_wallpaper"; - - // TODO(b/290048978): Enable wallpaper as default letterbox background. - private static final boolean DEFAULT_VALUE_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER = false; - /** * Override of aspect ratio for fixed orientation letterboxing that is set via ADB with * set-fixed-orientation-letterbox-aspect-ratio or via {@link @@ -185,6 +179,9 @@ final class LetterboxConfiguration { @NonNull private final LetterboxConfigurationPersister mLetterboxConfigurationPersister; + @NonNull + private final FeatureFlags mFeatureFlags; + // Aspect ratio of letterbox for fixed orientation, values <= // MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO will be ignored. private float mFixedOrientationLetterboxAspectRatio; @@ -301,7 +298,8 @@ final class LetterboxConfiguration { // Flags dynamically updated with {@link android.provider.DeviceConfig}. @NonNull private final SynchedDeviceConfig mDeviceConfig; - LetterboxConfiguration(@NonNull final Context systemUiContext) { + LetterboxConfiguration(@NonNull final Context systemUiContext, + @NonNull FeatureFlags featureFags) { this(systemUiContext, new LetterboxConfigurationPersister( () -> readLetterboxHorizontalReachabilityPositionFromConfig( systemUiContext, /* forBookMode */ false), @@ -310,14 +308,16 @@ final class LetterboxConfiguration { () -> readLetterboxHorizontalReachabilityPositionFromConfig( systemUiContext, /* forBookMode */ true), () -> readLetterboxVerticalReachabilityPositionFromConfig( - systemUiContext, /* forTabletopMode */ true))); + systemUiContext, /* forTabletopMode */ true)), + featureFags); } @VisibleForTesting LetterboxConfiguration(@NonNull final Context systemUiContext, - @NonNull final LetterboxConfigurationPersister letterboxConfigurationPersister) { + @NonNull final LetterboxConfigurationPersister letterboxConfigurationPersister, + @NonNull FeatureFlags featureFags) { mContext = systemUiContext; - + mFeatureFlags = featureFags; mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat( R.dimen.config_fixedOrientationLetterboxAspectRatio); mLetterboxBackgroundType = readLetterboxBackgroundTypeFromConfig(mContext); @@ -385,8 +385,6 @@ final class LetterboxConfiguration { DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS, mContext.getResources().getBoolean( R.bool.config_appCompatUserAppAspectRatioSettingsIsEnabled)) - .addDeviceConfigEntry(KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER, - DEFAULT_VALUE_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER, /* enabled */ true) .addDeviceConfigEntry(KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN, DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_FULLSCREEN, mContext.getResources().getBoolean( @@ -544,8 +542,7 @@ final class LetterboxConfiguration { } /** - * Resets letterbox background type value depending on the - * {@link #KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER} built time and runtime flags. + * Resets letterbox background type value depending on the built time and runtime flags. * * <p>If enabled, the letterbox background type value is set toZ * {@link #LETTERBOX_BACKGROUND_WALLPAPER}. When disabled the letterbox background type value @@ -555,12 +552,11 @@ final class LetterboxConfiguration { mLetterboxBackgroundTypeOverride = LETTERBOX_BACKGROUND_OVERRIDE_UNSET; } - // Returns KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER if the DeviceConfig flag is enabled - // or the value in com.android.internal.R.integer.config_letterboxBackgroundType if the flag - // is disabled. + // Returns LETTERBOX_BACKGROUND_WALLPAPER if the flag is enabled or the value in + // com.android.internal.R.integer.config_letterboxBackgroundType if the flag is disabled. @LetterboxBackgroundType private int getDefaultLetterboxBackgroundType() { - return mDeviceConfig.getFlagValue(KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER) + return mFeatureFlags.letterboxBackgroundWallpaperFlag() ? LETTERBOX_BACKGROUND_WALLPAPER : mLetterboxBackgroundType; } diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 6dc896a92e52..57f44cb599fe 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -1466,13 +1466,13 @@ class TaskFragment extends WindowContainer<WindowContainer> { if (DEBUG_RESULTS) { Slog.v(TAG_RESULTS, "Delivering results to " + next + ": " + a); } - transaction.addCallback(ActivityResultItem.obtain(a)); + transaction.addCallback(ActivityResultItem.obtain(next.token, a)); } } if (next.newIntents != null) { transaction.addCallback( - NewIntentItem.obtain(next.newIntents, true /* resume */)); + NewIntentItem.obtain(next.token, next.newIntents, true /* resume */)); } // Well the app will no longer be stopped. @@ -1486,7 +1486,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState); next.abortAndClearOptionsAnimation(); transaction.setLifecycleStateRequest( - ResumeActivityItem.obtain(next.app.getReportedProcState(), + ResumeActivityItem.obtain(next.token, next.app.getReportedProcState(), dc.isNextTransitionForward(), next.shouldSendCompatFakeFocus())); mAtmService.getLifecycleManager().scheduleTransaction(transaction); @@ -1726,7 +1726,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { prev.shortComponentName, "userLeaving=" + userLeaving, reason); mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(), - prev.token, PauseActivityItem.obtain(prev.finishing, userLeaving, + prev.token, PauseActivityItem.obtain(prev.token, prev.finishing, userLeaving, prev.configChangeFlags, pauseImmediately, autoEnteringPip)); } catch (Exception e) { // Ignore exception, if process died other code will cleanup. diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 439b7193dd4b..e720446d7bad 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -97,7 +97,6 @@ import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER; import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW; import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN; import static android.window.WindowProviderService.isWindowProviderService; - import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BOOT; @@ -334,6 +333,7 @@ import com.android.server.policy.WindowManagerPolicy; import com.android.server.policy.WindowManagerPolicy.ScreenOffListener; import com.android.server.power.ShutdownThread; import com.android.server.utils.PriorityDump; +import com.android.window.flags.FeatureFlagsImpl; import dalvik.annotation.optimization.NeverCompile; @@ -1175,7 +1175,8 @@ public class WindowManagerService extends IWindowManager.Stub mLetterboxConfiguration = new LetterboxConfiguration( // Using SysUI context to have access to Material colors extracted from Wallpaper. - ActivityThread.currentActivityThread().getSystemUiContext()); + ActivityThread.currentActivityThread().getSystemUiContext(), + new FeatureFlagsImpl()); mInputManager = inputManager; // Must be before createDisplayContentLocked. mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); @@ -8868,11 +8869,6 @@ public class WindowManagerService extends IWindowManager.Stub h.inputConfig |= InputConfig.NOT_FOCUSABLE; } - // Check private trusted overlay flag to set trustedOverlay field of input window handle. - if ((privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) { - h.inputConfig |= InputConfig.TRUSTED_OVERLAY; - } - h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS; h.ownerUid = callingUid; h.ownerPid = callingPid; @@ -8892,6 +8888,8 @@ public class WindowManagerService extends IWindowManager.Stub } final SurfaceControl.Transaction t = mTransactionFactory.get(); + // Check private trusted overlay flag to set trustedOverlay field of input window handle. + h.setTrustedOverlay(t, surface, (privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0); t.setInputWindowInfo(surface, h); t.apply(); t.close(); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index b12cc0b30f53..822082ba4c70 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -28,6 +28,7 @@ import static android.graphics.GraphicsProtos.dumpPointProto; import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import static android.os.PowerManager.DRAW_WAKE_LOCK; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; +import static android.view.InputWindowHandle.USE_SURFACE_TRUSTED_OVERLAY; import static android.view.SurfaceControl.Transaction; import static android.view.SurfaceControl.getGlobalTransaction; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT; @@ -98,7 +99,6 @@ import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType; import static android.view.WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME; import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER; import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET; - import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; @@ -1112,7 +1112,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mInputWindowHandle.setName(getName()); mInputWindowHandle.setPackageName(mAttrs.packageName); mInputWindowHandle.setLayoutParamsType(mAttrs.type); - mInputWindowHandle.setTrustedOverlay(shouldWindowHandleBeTrusted(s)); + if (!USE_SURFACE_TRUSTED_OVERLAY) { + mInputWindowHandle.setTrustedOverlay(isWindowTrustedOverlay()); + } if (DEBUG) { Slog.v(TAG, "Window " + this + " client=" + c.asBinder() + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a); @@ -1193,12 +1195,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP : service.mAtmService.getProcessController(s.mPid, s.mUid); } - boolean shouldWindowHandleBeTrusted(Session s) { + private boolean isWindowTrustedOverlay() { return InputMonitor.isTrustedOverlay(mAttrs.type) || ((mAttrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0 - && s.mCanAddInternalSystemWindow) + && mSession.mCanAddInternalSystemWindow) || ((mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY) != 0 - && s.mCanCreateSystemApplicationOverlay); + && mSession.mCanCreateSystemApplicationOverlay); } int getTouchOcclusionMode() { @@ -5192,6 +5194,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP updateFrameRateSelectionPriorityIfNeeded(); updateScaleIfNeeded(); mWinAnimator.prepareSurfaceLocked(getSyncTransaction()); + if (USE_SURFACE_TRUSTED_OVERLAY) { + getSyncTransaction().setTrustedOverlay(mSurfaceControl, isWindowTrustedOverlay()); + } } super.prepareSurfaces(); } @@ -5944,7 +5949,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } boolean isTrustedOverlay() { - return mInputWindowHandle.isTrustedOverlay(); + if (USE_SURFACE_TRUSTED_OVERLAY) { + WindowState parentWindow = getParentWindow(); + return isWindowTrustedOverlay() || (parentWindow != null + && parentWindow.isWindowTrustedOverlay()); + } else { + return mInputWindowHandle.isTrustedOverlay(); + } } public boolean receiveFocusFromTapOutside() { diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml index 42e3383987d6..d6a38773bf6b 100644 --- a/services/tests/wmtests/AndroidManifest.xml +++ b/services/tests/wmtests/AndroidManifest.xml @@ -47,6 +47,8 @@ <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION"/> + <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/> + <!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) --> <application android:debuggable="true" @@ -104,6 +106,11 @@ android:showWhenLocked="true" android:turnScreenOn="true" /> + <activity android:name="android.app.Activity" + android:exported="true" + android:showWhenLocked="true" + android:turnScreenOn="true" /> + <activity android:name="androidx.test.core.app.InstrumentationActivityInvoker$EmptyActivity" android:exported="true"> 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 31682bc9e879..ae587003c1c2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -517,7 +517,7 @@ public class ActivityRecordTests extends WindowTestsBase { // The configuration change is still sent to the activity, even if it doesn't relaunch. final ActivityConfigurationChangeItem expected = - ActivityConfigurationChangeItem.obtain(newConfig); + ActivityConfigurationChangeItem.obtain(activity.token, newConfig); verify(mAtm.getLifecycleManager()).scheduleTransaction( eq(activity.app.getThread()), eq(activity.token), eq(expected)); } @@ -597,7 +597,7 @@ public class ActivityRecordTests extends WindowTestsBase { activity.setRequestedOrientation(requestedOrientation); final ActivityConfigurationChangeItem expected = - ActivityConfigurationChangeItem.obtain(newConfig); + ActivityConfigurationChangeItem.obtain(activity.token, newConfig); verify(mAtm.getLifecycleManager()).scheduleTransaction(eq(activity.app.getThread()), eq(activity.token), eq(expected)); @@ -815,7 +815,7 @@ public class ActivityRecordTests extends WindowTestsBase { false /* preserveWindow */, true /* ignoreStopState */); final ActivityConfigurationChangeItem expected = - ActivityConfigurationChangeItem.obtain(newConfig); + ActivityConfigurationChangeItem.obtain(activity.token, newConfig); verify(mAtm.getLifecycleManager()).scheduleTransaction( eq(activity.app.getThread()), eq(activity.token), eq(expected)); } finally { diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java index 769a309cf5a7..1b44c01bfab5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java @@ -573,8 +573,9 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase { final ClientTransaction transaction = ClientTransaction.obtain( mActivity.app.getThread(), mActivity.token); - transaction.addCallback(RefreshCallbackItem.obtain(cycleThroughStop ? ON_STOP : ON_PAUSE)); - transaction.setLifecycleStateRequest(ResumeActivityItem.obtain( + transaction.addCallback(RefreshCallbackItem.obtain(mActivity.token, + cycleThroughStop ? ON_STOP : ON_PAUSE)); + transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(mActivity.token, /* isForward */ false, /* shouldSendCompatFakeFocus */ false)); verify(mActivity.mAtmService.getLifecycleManager(), times(refreshRequested ? 1 : 0)) diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java index 80e169d8d579..be3f01ec7dbf 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java @@ -17,14 +17,15 @@ package com.android.server.wm; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; - +import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_SOLID_COLOR; +import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_WALLPAPER; import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER; import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT; import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT; import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM; import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER; import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP; - +import static junit.framework.Assert.assertEquals; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -37,6 +38,8 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.android.window.flags.FakeFeatureFlagsImpl; + import org.junit.Before; import org.junit.Test; @@ -57,12 +60,16 @@ public class LetterboxConfigurationTest { private LetterboxConfiguration mLetterboxConfiguration; private LetterboxConfigurationPersister mLetterboxConfigurationPersister; + private MutableFakeFeatureFlagsImpl mMutableFakeFeatureFlags; + + @Before public void setUp() throws Exception { mContext = getInstrumentation().getTargetContext(); + mMutableFakeFeatureFlags = new MutableFakeFeatureFlagsImpl(); mLetterboxConfigurationPersister = mock(LetterboxConfigurationPersister.class); mLetterboxConfiguration = new LetterboxConfiguration(mContext, - mLetterboxConfigurationPersister); + mLetterboxConfigurationPersister, mMutableFakeFeatureFlags); } @Test @@ -92,6 +99,22 @@ public class LetterboxConfigurationTest { } @Test + public void test_whenFlagEnabled_wallpaperIsDefaultBackground() { + mMutableFakeFeatureFlags.setLetterboxBackgroundWallpaperFlag(true); + assertEquals(LETTERBOX_BACKGROUND_WALLPAPER, + mLetterboxConfiguration.getLetterboxBackgroundType()); + assertEquals(1, mMutableFakeFeatureFlags.getInvocationCount()); + } + + @Test + public void test_whenFlagDisabled_solidColorIsDefaultBackground() { + mMutableFakeFeatureFlags.setLetterboxBackgroundWallpaperFlag(false); + assertEquals(LETTERBOX_BACKGROUND_SOLID_COLOR, + mLetterboxConfiguration.getLetterboxBackgroundType()); + assertEquals(1, mMutableFakeFeatureFlags.getInvocationCount()); + } + + @Test public void test_whenMovedHorizontally_updatePositionAccordingly() { // Starting from center assertForHorizontalMove( @@ -288,4 +311,23 @@ public class LetterboxConfigurationTest { false /* forTabletopMode */, LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP); } + + private static class MutableFakeFeatureFlagsImpl extends FakeFeatureFlagsImpl { + private boolean mLetterboxBackgroundWallpaperFlag; + private int mInvocationCount; + + public void setLetterboxBackgroundWallpaperFlag(boolean letterboxBackgroundWallpaperFlag) { + mLetterboxBackgroundWallpaperFlag = letterboxBackgroundWallpaperFlag; + } + + @Override + public boolean letterboxBackgroundWallpaperFlag() { + mInvocationCount++; + return mLetterboxBackgroundWallpaperFlag; + } + + int getInvocationCount() { + return mInvocationCount; + } + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java b/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java new file mode 100644 index 000000000000..e8a847c5d8a4 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java @@ -0,0 +1,149 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static android.view.InputWindowHandle.USE_SURFACE_TRUSTED_OVERLAY; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; + +import android.app.Activity; +import android.app.Instrumentation; +import android.os.IBinder; +import android.platform.test.annotations.Presubmit; +import android.server.wm.BuildUtils; +import android.server.wm.CtsWindowInfoUtils; +import android.view.View; +import android.view.ViewTreeObserver; +import android.view.WindowManager; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.rule.ActivityTestRule; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +@Presubmit +public class TrustedOverlayTests { + private static final String TAG = "TrustedOverlayTests"; + private static final long TIMEOUT_S = 5L * BuildUtils.HW_TIMEOUT_MULTIPLIER; + + @Rule + public TestName mName = new TestName(); + + private final ActivityTestRule<Activity> mActivityRule = new ActivityTestRule<>( + Activity.class); + + private Instrumentation mInstrumentation; + private Activity mActivity; + + @Before + public void setup() { + mInstrumentation = InstrumentationRegistry.getInstrumentation(); + mActivity = mActivityRule.launchActivity(null); + } + + @Test + public void setTrustedOverlayInputWindow() throws InterruptedException { + assumeFalse(USE_SURFACE_TRUSTED_OVERLAY); + testTrustedOverlayChildHelper(false); + } + + @Test + public void setTrustedOverlayChildLayer() throws InterruptedException { + assumeTrue(USE_SURFACE_TRUSTED_OVERLAY); + testTrustedOverlayChildHelper(true); + } + + private void testTrustedOverlayChildHelper(boolean expectTrusted) throws InterruptedException { + IBinder[] tokens = new IBinder[2]; + CountDownLatch hostTokenReady = new CountDownLatch(1); + mInstrumentation.runOnMainSync(() -> { + mActivity.getWindow().addPrivateFlags(PRIVATE_FLAG_TRUSTED_OVERLAY); + View rootView = mActivity.getWindow().getDecorView(); + if (rootView.isAttachedToWindow()) { + tokens[0] = rootView.getWindowToken(); + hostTokenReady.countDown(); + } else { + rootView.getViewTreeObserver().addOnWindowAttachListener( + new ViewTreeObserver.OnWindowAttachListener() { + @Override + public void onWindowAttached() { + tokens[0] = rootView.getWindowToken(); + hostTokenReady.countDown(); + } + + @Override + public void onWindowDetached() { + } + }); + } + }); + + assertTrue("Failed to wait for host to get added", + hostTokenReady.await(TIMEOUT_S, TimeUnit.SECONDS)); + + mInstrumentation.runOnMainSync(() -> { + WindowManager wm = mActivity.getSystemService(WindowManager.class); + + View childView = new View(mActivity) { + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + tokens[1] = getWindowToken(); + } + }; + WindowManager.LayoutParams params = new WindowManager.LayoutParams(); + params.token = tokens[0]; + params.type = TYPE_APPLICATION_PANEL; + wm.addView(childView, params); + }); + + boolean[] foundTrusted = new boolean[2]; + + CtsWindowInfoUtils.waitForWindowInfos( + windowInfos -> { + for (var windowInfo : windowInfos) { + if (windowInfo.windowToken == tokens[0] + && windowInfo.isTrustedOverlay) { + foundTrusted[0] = true; + } else if (windowInfo.windowToken == tokens[1] + && windowInfo.isTrustedOverlay) { + foundTrusted[1] = true; + } + } + return foundTrusted[0] && foundTrusted[1]; + }, TIMEOUT_S, TimeUnit.SECONDS); + + if (!foundTrusted[0] || !foundTrusted[1]) { + CtsWindowInfoUtils.dumpWindowsOnScreen(TAG, mName.getMethodName()); + } + + assertEquals("Failed to find parent window or was not marked trusted", expectTrusted, + foundTrusted[0]); + assertEquals("Failed to find child window or was not marked trusted", expectTrusted, + foundTrusted[1]); + } +} |