diff options
10 files changed, 119 insertions, 18 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index ae556c91ab6d..22b8d92b507c 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -211,6 +211,7 @@ import android.view.contentcapture.IContentCaptureOptionsCallback; import android.view.translation.TranslationSpec; import android.view.translation.UiTranslationSpec; import android.webkit.WebView; +import android.window.ActivityWindowInfo; import android.window.ITaskFragmentOrganizer; import android.window.SizeConfigurationBuckets; import android.window.SplashScreen; @@ -603,6 +604,9 @@ public final class ActivityThread extends ClientTransactionHandler boolean hideForNow; Configuration createdConfig; Configuration overrideConfig; + @NonNull + private ActivityWindowInfo mActivityWindowInfo; + // Used for consolidating configs before sending on to Activity. private final Configuration tmpConfig = new Configuration(); // Callback used for updating activity override config and camera compat control state. @@ -670,7 +674,8 @@ public final class ActivityThread extends ClientTransactionHandler List<ReferrerIntent> pendingNewIntents, SceneTransitionInfo sceneTransitionInfo, boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client, IBinder assistToken, IBinder shareableActivityToken, boolean launchedFromBubble, - IBinder taskFragmentToken, IBinder initialCallerInfoAccessToken) { + IBinder taskFragmentToken, IBinder initialCallerInfoAccessToken, + ActivityWindowInfo activityWindowInfo) { this.token = token; this.assistToken = assistToken; this.shareableActivityToken = shareableActivityToken; @@ -691,6 +696,7 @@ public final class ActivityThread extends ClientTransactionHandler mSceneTransitionInfo = sceneTransitionInfo; mLaunchedFromBubble = launchedFromBubble; mTaskFragmentToken = taskFragmentToken; + mActivityWindowInfo = activityWindowInfo; init(); } @@ -779,6 +785,11 @@ public final class ActivityThread extends ClientTransactionHandler return activity != null && activity.mVisibleFromServer; } + @NonNull + public ActivityWindowInfo getActivityWindowInfo() { + return mActivityWindowInfo; + } + public String toString() { ComponentName componentName = intent != null ? intent.getComponent() : null; return "ActivityRecord{" diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java index 95f5ad0bd38f..f02cb212276b 100644 --- a/core/java/android/app/servertransaction/LaunchActivityItem.java +++ b/core/java/android/app/servertransaction/LaunchActivityItem.java @@ -42,6 +42,7 @@ import android.os.IBinder; import android.os.Parcel; import android.os.PersistableBundle; import android.os.Trace; +import android.window.ActivityWindowInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; @@ -81,6 +82,8 @@ public class LaunchActivityItem extends ClientTransactionItem { private boolean mLaunchedFromBubble; private IBinder mTaskFragmentToken; private IBinder mInitialCallerInfoAccessToken; + private ActivityWindowInfo mActivityWindowInfo; + /** * It is only non-null if the process is the first time to launch activity. It is only an * optimization for quick look up of the interface so the field is ignored for comparison. @@ -107,7 +110,7 @@ public class LaunchActivityItem extends ClientTransactionItem { mOverrideConfig, mReferrer, mVoiceInteractor, mState, mPersistentState, mPendingResults, mPendingNewIntents, mSceneTransitionInfo, mIsForward, mProfilerInfo, client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble, - mTaskFragmentToken, mInitialCallerInfoAccessToken); + mTaskFragmentToken, mInitialCallerInfoAccessToken, mActivityWindowInfo); client.handleLaunchActivity(r, pendingActions, mDeviceId, null /* customIntent */); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -141,7 +144,8 @@ public class LaunchActivityItem extends ClientTransactionItem { boolean isForward, @Nullable ProfilerInfo profilerInfo, @NonNull IBinder assistToken, @Nullable IActivityClientController activityClientController, @NonNull IBinder shareableActivityToken, boolean launchedFromBubble, - @Nullable IBinder taskFragmentToken, @NonNull IBinder initialCallerInfoAccessToken) { + @Nullable IBinder taskFragmentToken, @NonNull IBinder initialCallerInfoAccessToken, + @NonNull ActivityWindowInfo activityWindowInfo) { LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class); if (instance == null) { instance = new LaunchActivityItem(); @@ -156,7 +160,8 @@ public class LaunchActivityItem extends ClientTransactionItem { sceneTransitionInfo, isForward, profilerInfo != null ? new ProfilerInfo(profilerInfo) : null, assistToken, activityClientController, shareableActivityToken, - launchedFromBubble, taskFragmentToken, initialCallerInfoAccessToken); + launchedFromBubble, taskFragmentToken, initialCallerInfoAccessToken, + new ActivityWindowInfo(activityWindowInfo)); return instance; } @@ -171,7 +176,7 @@ public class LaunchActivityItem extends ClientTransactionItem { @Override public void recycle() { setValues(this, null, null, 0, null, null, null, 0, null, null, 0, null, null, null, null, - null, false, null, null, null, null, false, null, null); + null, false, null, null, null, null, false, null, null, null); ObjectPool.recycle(this); } @@ -203,6 +208,7 @@ public class LaunchActivityItem extends ClientTransactionItem { dest.writeBoolean(mLaunchedFromBubble); dest.writeStrongBinder(mTaskFragmentToken); dest.writeStrongBinder(mInitialCallerInfoAccessToken); + dest.writeTypedObject(mActivityWindowInfo, flags); } /** Read from Parcel. */ @@ -223,7 +229,8 @@ public class LaunchActivityItem extends ClientTransactionItem { in.readStrongBinder(), in.readBoolean(), in.readStrongBinder(), - in.readStrongBinder()); + in.readStrongBinder(), + in.readTypedObject(ActivityWindowInfo.CREATOR)); } public static final @NonNull Creator<LaunchActivityItem> CREATOR = new Creator<>() { @@ -264,7 +271,8 @@ public class LaunchActivityItem extends ClientTransactionItem { && Objects.equals(mShareableActivityToken, other.mShareableActivityToken) && Objects.equals(mTaskFragmentToken, other.mTaskFragmentToken) && Objects.equals(mInitialCallerInfoAccessToken, - other.mInitialCallerInfoAccessToken); + other.mInitialCallerInfoAccessToken) + && Objects.equals(mActivityWindowInfo, other.mActivityWindowInfo); } @Override @@ -289,6 +297,7 @@ public class LaunchActivityItem extends ClientTransactionItem { result = 31 * result + Objects.hashCode(mShareableActivityToken); result = 31 * result + Objects.hashCode(mTaskFragmentToken); result = 31 * result + Objects.hashCode(mInitialCallerInfoAccessToken); + result = 31 * result + Objects.hashCode(mActivityWindowInfo); return result; } @@ -335,7 +344,9 @@ public class LaunchActivityItem extends ClientTransactionItem { + ",sceneTransitionInfo=" + mSceneTransitionInfo + ",profilerInfo=" + mProfilerInfo + ",assistToken=" + mAssistToken - + ",shareableActivityToken=" + mShareableActivityToken + "}"; + + ",shareableActivityToken=" + mShareableActivityToken + + ",activityWindowInfo=" + mActivityWindowInfo + + "}"; } // Using the same method to set and clear values to make sure we don't forget anything @@ -351,7 +362,8 @@ public class LaunchActivityItem extends ClientTransactionItem { @Nullable ProfilerInfo profilerInfo, @Nullable IBinder assistToken, @Nullable IActivityClientController activityClientController, @Nullable IBinder shareableActivityToken, boolean launchedFromBubble, - @Nullable IBinder taskFragmentToken, @Nullable IBinder initialCallerInfoAccessToken) { + @Nullable IBinder taskFragmentToken, @Nullable IBinder initialCallerInfoAccessToken, + @Nullable ActivityWindowInfo activityWindowInfo) { instance.mActivityToken = activityToken; instance.mIntent = intent; instance.mIdent = ident; @@ -375,5 +387,6 @@ public class LaunchActivityItem extends ClientTransactionItem { instance.mLaunchedFromBubble = launchedFromBubble; instance.mTaskFragmentToken = taskFragmentToken; instance.mInitialCallerInfoAccessToken = initialCallerInfoAccessToken; + instance.mActivityWindowInfo = activityWindowInfo; } } diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java index c6447be71855..207fe730aac2 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java @@ -39,6 +39,7 @@ import android.os.Bundle; import android.os.IBinder; import android.os.PersistableBundle; import android.platform.test.annotations.Presubmit; +import android.window.ActivityWindowInfo; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -124,6 +125,7 @@ public class ObjectPoolTests { final int deviceId = 3; final IBinder taskFragmentToken = new Binder(); final IBinder initialCallerInfoAccessToken = new Binder(); + final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo(); testRecycle(() -> new LaunchActivityItemBuilder( activityToken, intent, activityInfo) @@ -142,6 +144,7 @@ public class ObjectPoolTests { .setTaskFragmentToken(taskFragmentToken) .setDeviceId(deviceId) .setInitialCallerInfoAccessToken(initialCallerInfoAccessToken) + .setActivityWindowInfo(activityWindowInfo) .build()); } diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java index d641659e6a5f..c1b9efda4652 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java +++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java @@ -32,6 +32,7 @@ import android.os.Bundle; import android.os.IBinder; import android.os.PersistableBundle; import android.util.MergedConfiguration; +import android.window.ActivityWindowInfo; import com.android.internal.app.IVoiceInteractor; import com.android.internal.content.ReferrerIntent; @@ -134,6 +135,8 @@ class TestUtils { private IBinder mTaskFragmentToken; @Nullable private IBinder mInitialCallerInfoAccessToken; + @NonNull + private ActivityWindowInfo mActivityWindowInfo = new ActivityWindowInfo(); LaunchActivityItemBuilder(@NonNull IBinder activityToken, @NonNull Intent intent, @NonNull ActivityInfo info) { @@ -260,6 +263,13 @@ class TestUtils { } @NonNull + LaunchActivityItemBuilder setActivityWindowInfo( + @NonNull ActivityWindowInfo activityWindowInfo) { + mActivityWindowInfo.set(activityWindowInfo); + return this; + } + + @NonNull LaunchActivityItem build() { return LaunchActivityItem.obtain(mActivityToken, mIntent, mIdent, mInfo, mCurConfig, mOverrideConfig, mDeviceId, mReferrer, mVoiceInteractor, @@ -267,7 +277,7 @@ class TestUtils { mActivityOptions != null ? mActivityOptions.getSceneTransitionInfo() : null, mIsForward, mProfilerInfo, mAssistToken, null /* activityClientController */, mShareableActivityToken, mLaunchedFromBubble, mTaskFragmentToken, - mInitialCallerInfoAccessToken); + mInitialCallerInfoAccessToken, mActivityWindowInfo); } } } diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index aa8001310008..03b85dc8b4e2 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -32,6 +32,7 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.res.Configuration; +import android.graphics.Rect; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; @@ -40,6 +41,7 @@ import android.os.Parcelable; import android.os.PersistableBundle; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; +import android.window.ActivityWindowInfo; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -180,6 +182,9 @@ public class TransactionParcelTests { bundle.putParcelable("data", new ParcelableData(1)); final PersistableBundle persistableBundle = new PersistableBundle(); persistableBundle.putInt("k", 4); + final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo(); + activityWindowInfo.set(true /* isEmbedded */, new Rect(0, 0, 500, 1000), + new Rect(0, 0, 500, 500)); final LaunchActivityItem item = new LaunchActivityItemBuilder( activityToken, intent, activityInfo) @@ -198,6 +203,7 @@ public class TransactionParcelTests { .setShareableActivityToken(new Binder()) .setTaskFragmentToken(new Binder()) .setInitialCallerInfoAccessToken(new Binder()) + .setActivityWindowInfo(activityWindowInfo) .build(); writeAndPrepareForReading(item); diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java index 39cb616b1ed9..66be05ff233c 100644 --- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java +++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java @@ -61,6 +61,7 @@ import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.testing.PollingCheck; import android.view.WindowManagerGlobal; +import android.window.ActivityWindowInfo; import android.window.SizeConfigurationBuckets; import androidx.test.annotation.UiThreadTest; @@ -354,7 +355,7 @@ public class ActivityThreadClientTest { null /* activityOptions */, true /* isForward */, null /* profilerInfo */, mThread /* client */, null /* asssitToken */, null /* shareableActivityToken */, false /* launchedFromBubble */, null /* taskfragmentToken */, - null /* initialCallerInfoAccessToken */); + null /* initialCallerInfoAccessToken */, new ActivityWindowInfo()); } @Override diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index b2e5b75cf0b5..ae3a854baf9f 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -72,6 +72,7 @@ import android.util.Pair; import android.util.Size; import android.util.SparseArray; import android.view.WindowMetrics; +import android.window.ActivityWindowInfo; import android.window.TaskFragmentAnimationParams; import android.window.TaskFragmentInfo; import android.window.TaskFragmentOperation; @@ -2864,11 +2865,27 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen */ @Override public boolean isActivityEmbedded(@NonNull Activity activity) { + Objects.requireNonNull(activity); synchronized (mLock) { + if (Flags.activityWindowInfoFlag()) { + final ActivityWindowInfo activityWindowInfo = getActivityWindowInfo(activity); + return activityWindowInfo != null && activityWindowInfo.isEmbedded(); + } return mPresenter.isActivityEmbedded(activity.getActivityToken()); } } + @Nullable + private static ActivityWindowInfo getActivityWindowInfo(@NonNull Activity activity) { + if (activity.isFinishing()) { + return null; + } + final ActivityThread.ActivityClientRecord record = + ActivityThread.currentActivityThread() + .getActivityClient(activity.getActivityToken()); + return record != null ? record.getActivityWindowInfo() : null; + } + /** * If the two rules have the same presentation, and the calculated {@link SplitAttributes} * matches the {@link SplitAttributes} of {@link SplitContainer}, we can reuse the same diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index bc6f93fd64ac..d60fe4b7d7e1 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -353,6 +353,7 @@ import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.view.WindowManager.TransitionOldType; import android.view.animation.Animation; +import android.window.ActivityWindowInfo; import android.window.ITaskFragmentOrganizer; import android.window.RemoteTransition; import android.window.SizeConfigurationBuckets; @@ -519,6 +520,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private int mLastReportedDisplayId; boolean mLastReportedMultiWindowMode; boolean mLastReportedPictureInPictureMode; + private final ActivityWindowInfo mLastReportedActivityWindowInfo = new ActivityWindowInfo(); ActivityRecord resultTo; // who started this entry, so will get our reply final String resultWho; // additional identifier for use by resultTo. final int requestCode; // code given by requester (resultTo) @@ -958,6 +960,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A */ private final Configuration mTmpConfig = new Configuration(); private final Rect mTmpBounds = new Rect(); + private final ActivityWindowInfo mTmpActivityWindowInfo = new ActivityWindowInfo(); // Token for targeting this activity for assist purposes. final Binder assistToken = new Binder(); @@ -1096,6 +1099,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.println(prefix + "mLastReportedConfigurations:"); mLastReportedConfiguration.dump(pw, prefix + " "); + if (Flags.activityWindowInfoFlag()) { + pw.print(prefix); + pw.print("mLastReportedActivityWindowInfo="); + pw.println(mLastReportedActivityWindowInfo); + } + pw.print(prefix); pw.print("CurrentConfiguration="); pw.println(getConfiguration()); if (!getRequestedOverrideConfiguration().equals(EMPTY)) { pw.println(prefix + "RequestedOverrideConfiguration=" @@ -3150,6 +3159,30 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + /** + * This is different from {@link #isEmbedded()}. + * {@link #isEmbedded()} is {@code true} when any of the parent {@link TaskFragment} is created + * by a {@link android.window.TaskFragmentOrganizer}, while this method is {@code true} when + * the parent {@link TaskFragment} is embedded and has bounds override that does not fill the + * leaf {@link Task}. + */ + boolean isEmbeddedInHostContainer() { + final TaskFragment taskFragment = getOrganizedTaskFragment(); + return taskFragment != null && taskFragment.isEmbeddedWithBoundsOverride(); + } + + @NonNull + ActivityWindowInfo getActivityWindowInfo() { + if (!Flags.activityWindowInfoFlag() || !isAttached()) { + return mTmpActivityWindowInfo; + } + mTmpActivityWindowInfo.set( + isEmbeddedInHostContainer(), + getTask().getBounds(), + getTaskFragment().getBounds()); + return mTmpActivityWindowInfo; + } + @Override @Nullable TaskDisplayArea getDisplayArea() { @@ -8213,6 +8246,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mLastReportedConfiguration.setConfiguration(global, override); } + void setLastReportedActivityWindowInfo(@NonNull ActivityWindowInfo activityWindowInfo) { + if (Flags.activityWindowInfoFlag()) { + mLastReportedActivityWindowInfo.set(activityWindowInfo); + } + } + @Nullable CompatDisplayInsets getCompatDisplayInsets() { if (mLetterboxUiController.hasInheritedLetterboxBehavior()) { diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 09f5eda5b571..e0faddf171ca 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -138,6 +138,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import android.view.Display; +import android.window.ActivityWindowInfo; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; @@ -909,6 +910,9 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { final Configuration overrideConfig = r.getMergedOverrideConfiguration(); r.setLastReportedConfiguration(procConfig, overrideConfig); + final ActivityWindowInfo activityWindowInfo = r.getActivityWindowInfo(); + r.setLastReportedActivityWindowInfo(activityWindowInfo); + logIfTransactionTooLarge(r.intent, r.getSavedState()); final TaskFragment organizedTaskFragment = r.getOrganizedTaskFragment(); @@ -931,7 +935,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { results, newIntents, r.takeSceneTransitionInfo(), isTransitionForward, proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController, r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken, - r.initialCallerInfoAccessToken); + r.initialCallerInfoAccessToken, activityWindowInfo); // Set desired final state. final ActivityLifecycleItem lifecycleItem; diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java index 8d054db8994a..24b533a23af6 100644 --- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java @@ -1197,16 +1197,13 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } } - // TODO(b/204399167): change to push the embedded state to the client side @Override public boolean isActivityEmbedded(IBinder activityToken) { synchronized (mGlobalLock) { final ActivityRecord activity = ActivityRecord.forTokenLocked(activityToken); - if (activity == null) { - return false; - } - final TaskFragment taskFragment = activity.getOrganizedTaskFragment(); - return taskFragment != null && taskFragment.isEmbeddedWithBoundsOverride(); + return activity != null + ? activity.isEmbeddedInHostContainer() + : false; } } |