Loading core/java/android/window/TaskFragmentInfo.java +22 −8 Original line number Diff line number Diff line Loading @@ -18,9 +18,12 @@ package android.window; import static android.app.WindowConfiguration.WindowingMode; import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.Configuration; import android.graphics.Point; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; Loading @@ -35,7 +38,7 @@ import java.util.List; public final class TaskFragmentInfo implements Parcelable { /** * Client assigned unique token in {@link TaskFragmentCreationParams#fragmentToken} to create * Client assigned unique token in {@link TaskFragmentCreationParams#mFragmentToken} to create * this TaskFragment with. */ @NonNull Loading @@ -59,19 +62,20 @@ public final class TaskFragmentInfo implements Parcelable { */ private final List<IBinder> mActivities = new ArrayList<>(); /** Relative position of the fragment's top left corner in the parent container. */ private final Point mPositionInParent; public TaskFragmentInfo( @NonNull IBinder fragmentToken, @NonNull WindowContainerToken token, @NonNull Configuration configuration, boolean isEmpty, boolean isVisible, List<IBinder> activities) { if (fragmentToken == null) { throw new IllegalArgumentException("Invalid TaskFragmentInfo."); } mFragmentToken = fragmentToken; mToken = token; List<IBinder> activities, @NonNull Point positionInParent) { mFragmentToken = requireNonNull(fragmentToken); mToken = requireNonNull(token); mConfiguration.setTo(configuration); mIsEmpty = isEmpty; mIsVisible = isVisible; mActivities.addAll(activities); mPositionInParent = requireNonNull(positionInParent); } public IBinder getFragmentToken() { Loading @@ -98,6 +102,12 @@ public final class TaskFragmentInfo implements Parcelable { return mActivities; } /** Returns the relative position of the fragment's top left corner in the parent container. */ @NonNull public Point getPositionInParent() { return mPositionInParent; } @WindowingMode public int getWindowingMode() { return mConfiguration.windowConfiguration.getWindowingMode(); Loading @@ -117,7 +127,8 @@ public final class TaskFragmentInfo implements Parcelable { && mIsEmpty == that.mIsEmpty && mIsVisible == that.mIsVisible && getWindowingMode() == that.getWindowingMode() && mActivities.equals(that.mActivities); && mActivities.equals(that.mActivities) && mPositionInParent.equals(that.mPositionInParent); } private TaskFragmentInfo(Parcel in) { Loading @@ -127,6 +138,7 @@ public final class TaskFragmentInfo implements Parcelable { mIsEmpty = in.readBoolean(); mIsVisible = in.readBoolean(); in.readBinderList(mActivities); mPositionInParent = requireNonNull(in.readTypedObject(Point.CREATOR)); } @Override Loading @@ -137,6 +149,7 @@ public final class TaskFragmentInfo implements Parcelable { dest.writeBoolean(mIsEmpty); dest.writeBoolean(mIsVisible); dest.writeBinderList(mActivities); dest.writeTypedObject(mPositionInParent, flags); } @NonNull Loading @@ -160,6 +173,7 @@ public final class TaskFragmentInfo implements Parcelable { + " token=" + mToken + " isEmpty=" + mIsEmpty + " isVisible=" + mIsVisible + " positionInParent=" + mPositionInParent + "}"; } Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java 0 → 100644 +260 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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 androidx.window.extensions.organizer; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import android.app.Activity; import android.app.WindowConfiguration.WindowingMode; import android.content.Intent; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; import android.util.ArrayMap; import android.view.SurfaceControl; import android.window.TaskFragmentAppearedInfo; import android.window.TaskFragmentCreationParams; import android.window.TaskFragmentInfo; import android.window.TaskFragmentOrganizer; import android.window.WindowContainerTransaction; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.util.Map; import java.util.concurrent.Executor; /** * Platform default Extensions implementation of {@link TaskFragmentOrganizer} to organize * task fragments. * * All calls into methods of this class are expected to be on the UI thread. */ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { /** Mapping from the client assigned unique token to the {@link TaskFragmentInfo}. */ private final Map<IBinder, TaskFragmentInfo> mFragmentInfos = new ArrayMap<>(); /** Mapping from the client assigned unique token to the TaskFragment {@link SurfaceControl}. */ private final Map<IBinder, SurfaceControl> mFragmentLeashes = new ArrayMap<>(); /** * Mapping from the client assigned unique token to the TaskFragment parent * {@link Configuration}. */ final Map<IBinder, Configuration> mFragmentParentConfigs = new ArrayMap<>(); private final TaskFragmentCallback mCallback; /** * Callback that notifies the controller about changes to task fragments. */ interface TaskFragmentCallback { void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo); void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo); void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo); void onTaskFragmentParentInfoChanged(@NonNull IBinder fragmentToken, @NonNull Configuration parentConfig); } /** * @param executor callbacks from WM Core are posted on this executor. It should be tied to the * UI thread that all other calls into methods of this class are also on. */ JetpackTaskFragmentOrganizer(@NonNull Executor executor, TaskFragmentCallback callback) { super(executor); mCallback = callback; } /** * Starts a new Activity and puts it into split with an existing Activity side-by-side. * @param launchingFragmentToken token for the launching TaskFragment. If it exists, it will * be resized based on {@param launchingFragmentBounds}. * Otherwise, we will create a new TaskFragment with the given * token for the {@param launchingActivity}. * @param launchingFragmentBounds the initial bounds for the launching TaskFragment. * @param launchingActivity the Activity to put on the left hand side of the split as the * primary. * @param secondaryFragmentToken token to create the secondary TaskFragment with. * @param secondaryFragmentBounds the initial bounds for the secondary TaskFragment * @param activityIntent Intent to start the secondary Activity with. * @param activityOptions ActivityOptions to start the secondary Activity with. */ void startActivityToSide(IBinder launchingFragmentToken, Rect launchingFragmentBounds, Activity launchingActivity, IBinder secondaryFragmentToken, Rect secondaryFragmentBounds, Intent activityIntent, @Nullable Bundle activityOptions) { final WindowContainerTransaction wct = new WindowContainerTransaction(); final IBinder ownerToken = launchingActivity.getActivityToken(); // Create or resize the launching TaskFragment. if (mFragmentInfos.containsKey(launchingFragmentToken)) { resizeTaskFragment(wct, launchingFragmentToken, launchingFragmentBounds); } else { createTaskFragmentAndReparentActivity(wct, launchingFragmentToken, ownerToken, launchingFragmentBounds, WINDOWING_MODE_MULTI_WINDOW, launchingActivity); } // Create a TaskFragment for the secondary activity. createTaskFragmentAndStartActivity(wct, secondaryFragmentToken, ownerToken, secondaryFragmentBounds, WINDOWING_MODE_MULTI_WINDOW, activityIntent, activityOptions); applyTransaction(wct); } /** * Expands an existing TaskFragment to fill parent. * @param wct WindowContainerTransaction in which the task fragment should be resized. * @param fragmentToken token of an existing TaskFragment. */ void expandTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) { resizeTaskFragment(wct, fragmentToken, new Rect()); } /** * Expands an existing TaskFragment to fill parent. * @param fragmentToken token of an existing TaskFragment. */ void expandTaskFragment(IBinder fragmentToken) { WindowContainerTransaction wct = new WindowContainerTransaction(); expandTaskFragment(wct, fragmentToken); applyTransaction(wct); } /** * Expands an Activity to fill parent by moving it to a new TaskFragment. * @param fragmentToken token to create new TaskFragment with. * @param activity activity to move to the fill-parent TaskFragment. */ void expandActivity(IBinder fragmentToken, Activity activity) { final WindowContainerTransaction wct = new WindowContainerTransaction(); createTaskFragmentAndReparentActivity( wct, fragmentToken, activity.getActivityToken(), new Rect(), WINDOWING_MODE_UNDEFINED, activity); applyTransaction(wct); } /** * @param ownerToken The token of the activity that creates this task fragment. It does not * have to be a child of this task fragment, but must belong to the same task. */ private void createTaskFragmentAndReparentActivity( WindowContainerTransaction wct, IBinder fragmentToken, IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode, Activity activity) { final TaskFragmentCreationParams fragmentOptions = createFragmentOptions(fragmentToken, ownerToken, bounds, windowingMode); wct.createTaskFragment(fragmentOptions) .reparentActivityToTaskFragment(fragmentToken, activity.getActivityToken()); } /** * @param ownerToken The token of the activity that creates this task fragment. It does not * have to be a child of this task fragment, but must belong to the same task. */ private void createTaskFragmentAndStartActivity( WindowContainerTransaction wct, IBinder fragmentToken, IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode, Intent activityIntent, @Nullable Bundle activityOptions) { final TaskFragmentCreationParams fragmentOptions = createFragmentOptions(fragmentToken, ownerToken, bounds, windowingMode); wct.createTaskFragment(fragmentOptions) .startActivityInTaskFragment(fragmentToken, activityIntent, activityOptions); } TaskFragmentCreationParams createFragmentOptions(IBinder fragmentToken, IBinder ownerToken, Rect bounds, @WindowingMode int windowingMode) { if (mFragmentInfos.containsKey(fragmentToken)) { throw new IllegalArgumentException( "There is an existing TaskFragment with fragmentToken=" + fragmentToken); } return new TaskFragmentCreationParams.Builder( getIOrganizer(), fragmentToken, ownerToken) .setInitialBounds(bounds) .setWindowingMode(windowingMode) .build(); } void resizeTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken, @Nullable Rect bounds) { if (!mFragmentInfos.containsKey(fragmentToken)) { throw new IllegalArgumentException( "Can't find an existing TaskFragment with fragmentToken=" + fragmentToken); } if (bounds == null) { bounds = new Rect(); } wct.setBounds(mFragmentInfos.get(fragmentToken).getToken(), bounds); } void deleteTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) { if (!mFragmentInfos.containsKey(fragmentToken)) { throw new IllegalArgumentException( "Can't find an existing TaskFragment with fragmentToken=" + fragmentToken); } wct.deleteTaskFragment(mFragmentInfos.get(fragmentToken).getToken()); } @Override public void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) { final TaskFragmentInfo info = taskFragmentAppearedInfo.getTaskFragmentInfo(); final IBinder fragmentToken = info.getFragmentToken(); final SurfaceControl leash = taskFragmentAppearedInfo.getLeash(); mFragmentInfos.put(fragmentToken, info); mFragmentLeashes.put(fragmentToken, leash); if (mCallback != null) { mCallback.onTaskFragmentAppeared(taskFragmentAppearedInfo); } } @Override public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) { final IBinder fragmentToken = taskFragmentInfo.getFragmentToken(); mFragmentInfos.put(fragmentToken, taskFragmentInfo); if (mCallback != null) { mCallback.onTaskFragmentInfoChanged(taskFragmentInfo); } } @Override public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) { mFragmentInfos.remove(taskFragmentInfo.getFragmentToken()); mFragmentLeashes.remove(taskFragmentInfo.getFragmentToken()); mFragmentParentConfigs.remove(taskFragmentInfo.getFragmentToken()); if (mCallback != null) { mCallback.onTaskFragmentVanished(taskFragmentInfo); } } @Override public void onTaskFragmentParentInfoChanged( @NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) { mFragmentParentConfigs.put(fragmentToken, parentConfig); if (mCallback != null) { mCallback.onTaskFragmentParentInfoChanged(fragmentToken, parentConfig); } } } services/core/java/com/android/server/wm/ActivityRecord.java +7 −0 Original line number Diff line number Diff line Loading @@ -1885,6 +1885,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A task.setRootProcess(proc); } proc.addActivityIfNeeded(this); // Update the associated task fragment after setting the process, since it's required for // filtering to only report activities that belong to the same process. final TaskFragment tf = getTaskFragment(); if (tf != null) { tf.sendTaskFragmentInfoChanged(); } } boolean hasProcess() { Loading services/core/java/com/android/server/wm/TaskFragment.java +11 −1 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ import android.app.servertransaction.NewIntentItem; import android.app.servertransaction.PauseActivityItem; import android.app.servertransaction.ResumeActivityItem; import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; import android.os.IBinder; import android.os.RemoteException; Loading Loading @@ -1475,6 +1476,12 @@ class TaskFragment extends WindowContainer<WindowContainer> { } } void onChildPositionChanged(WindowContainer child) { super.onChildPositionChanged(child); sendTaskFragmentInfoChanged(); } void executeAppTransition(ActivityOptions options) { // No app transition applied to the task fragment. } Loading Loading @@ -2027,13 +2034,16 @@ class TaskFragment extends WindowContainer<WindowContainer> { childActivities.add(wc.asActivityRecord().appToken); } } final Point positionInParent = new Point(); getRelativePosition(positionInParent); return new TaskFragmentInfo( mFragmentToken, mRemoteToken.toWindowContainerToken(), getConfiguration(), getChildCount() == 0, isVisible(), childActivities); childActivities, positionInParent); } @Nullable Loading services/core/java/com/android/server/wm/WindowOrganizerController.java +2 −2 Original line number Diff line number Diff line Loading @@ -878,8 +878,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } private void sanitizeWindowContainer(WindowContainer wc) { if (!(wc instanceof Task) && !(wc instanceof DisplayArea)) { throw new RuntimeException("Invalid token in task or displayArea transaction"); if (!(wc instanceof TaskFragment) && !(wc instanceof DisplayArea)) { throw new RuntimeException("Invalid token in task fragment or displayArea transaction"); } } Loading Loading
core/java/android/window/TaskFragmentInfo.java +22 −8 Original line number Diff line number Diff line Loading @@ -18,9 +18,12 @@ package android.window; import static android.app.WindowConfiguration.WindowingMode; import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.Configuration; import android.graphics.Point; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; Loading @@ -35,7 +38,7 @@ import java.util.List; public final class TaskFragmentInfo implements Parcelable { /** * Client assigned unique token in {@link TaskFragmentCreationParams#fragmentToken} to create * Client assigned unique token in {@link TaskFragmentCreationParams#mFragmentToken} to create * this TaskFragment with. */ @NonNull Loading @@ -59,19 +62,20 @@ public final class TaskFragmentInfo implements Parcelable { */ private final List<IBinder> mActivities = new ArrayList<>(); /** Relative position of the fragment's top left corner in the parent container. */ private final Point mPositionInParent; public TaskFragmentInfo( @NonNull IBinder fragmentToken, @NonNull WindowContainerToken token, @NonNull Configuration configuration, boolean isEmpty, boolean isVisible, List<IBinder> activities) { if (fragmentToken == null) { throw new IllegalArgumentException("Invalid TaskFragmentInfo."); } mFragmentToken = fragmentToken; mToken = token; List<IBinder> activities, @NonNull Point positionInParent) { mFragmentToken = requireNonNull(fragmentToken); mToken = requireNonNull(token); mConfiguration.setTo(configuration); mIsEmpty = isEmpty; mIsVisible = isVisible; mActivities.addAll(activities); mPositionInParent = requireNonNull(positionInParent); } public IBinder getFragmentToken() { Loading @@ -98,6 +102,12 @@ public final class TaskFragmentInfo implements Parcelable { return mActivities; } /** Returns the relative position of the fragment's top left corner in the parent container. */ @NonNull public Point getPositionInParent() { return mPositionInParent; } @WindowingMode public int getWindowingMode() { return mConfiguration.windowConfiguration.getWindowingMode(); Loading @@ -117,7 +127,8 @@ public final class TaskFragmentInfo implements Parcelable { && mIsEmpty == that.mIsEmpty && mIsVisible == that.mIsVisible && getWindowingMode() == that.getWindowingMode() && mActivities.equals(that.mActivities); && mActivities.equals(that.mActivities) && mPositionInParent.equals(that.mPositionInParent); } private TaskFragmentInfo(Parcel in) { Loading @@ -127,6 +138,7 @@ public final class TaskFragmentInfo implements Parcelable { mIsEmpty = in.readBoolean(); mIsVisible = in.readBoolean(); in.readBinderList(mActivities); mPositionInParent = requireNonNull(in.readTypedObject(Point.CREATOR)); } @Override Loading @@ -137,6 +149,7 @@ public final class TaskFragmentInfo implements Parcelable { dest.writeBoolean(mIsEmpty); dest.writeBoolean(mIsVisible); dest.writeBinderList(mActivities); dest.writeTypedObject(mPositionInParent, flags); } @NonNull Loading @@ -160,6 +173,7 @@ public final class TaskFragmentInfo implements Parcelable { + " token=" + mToken + " isEmpty=" + mIsEmpty + " isVisible=" + mIsVisible + " positionInParent=" + mPositionInParent + "}"; } Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java 0 → 100644 +260 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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 androidx.window.extensions.organizer; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import android.app.Activity; import android.app.WindowConfiguration.WindowingMode; import android.content.Intent; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; import android.util.ArrayMap; import android.view.SurfaceControl; import android.window.TaskFragmentAppearedInfo; import android.window.TaskFragmentCreationParams; import android.window.TaskFragmentInfo; import android.window.TaskFragmentOrganizer; import android.window.WindowContainerTransaction; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.util.Map; import java.util.concurrent.Executor; /** * Platform default Extensions implementation of {@link TaskFragmentOrganizer} to organize * task fragments. * * All calls into methods of this class are expected to be on the UI thread. */ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { /** Mapping from the client assigned unique token to the {@link TaskFragmentInfo}. */ private final Map<IBinder, TaskFragmentInfo> mFragmentInfos = new ArrayMap<>(); /** Mapping from the client assigned unique token to the TaskFragment {@link SurfaceControl}. */ private final Map<IBinder, SurfaceControl> mFragmentLeashes = new ArrayMap<>(); /** * Mapping from the client assigned unique token to the TaskFragment parent * {@link Configuration}. */ final Map<IBinder, Configuration> mFragmentParentConfigs = new ArrayMap<>(); private final TaskFragmentCallback mCallback; /** * Callback that notifies the controller about changes to task fragments. */ interface TaskFragmentCallback { void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo); void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo); void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo); void onTaskFragmentParentInfoChanged(@NonNull IBinder fragmentToken, @NonNull Configuration parentConfig); } /** * @param executor callbacks from WM Core are posted on this executor. It should be tied to the * UI thread that all other calls into methods of this class are also on. */ JetpackTaskFragmentOrganizer(@NonNull Executor executor, TaskFragmentCallback callback) { super(executor); mCallback = callback; } /** * Starts a new Activity and puts it into split with an existing Activity side-by-side. * @param launchingFragmentToken token for the launching TaskFragment. If it exists, it will * be resized based on {@param launchingFragmentBounds}. * Otherwise, we will create a new TaskFragment with the given * token for the {@param launchingActivity}. * @param launchingFragmentBounds the initial bounds for the launching TaskFragment. * @param launchingActivity the Activity to put on the left hand side of the split as the * primary. * @param secondaryFragmentToken token to create the secondary TaskFragment with. * @param secondaryFragmentBounds the initial bounds for the secondary TaskFragment * @param activityIntent Intent to start the secondary Activity with. * @param activityOptions ActivityOptions to start the secondary Activity with. */ void startActivityToSide(IBinder launchingFragmentToken, Rect launchingFragmentBounds, Activity launchingActivity, IBinder secondaryFragmentToken, Rect secondaryFragmentBounds, Intent activityIntent, @Nullable Bundle activityOptions) { final WindowContainerTransaction wct = new WindowContainerTransaction(); final IBinder ownerToken = launchingActivity.getActivityToken(); // Create or resize the launching TaskFragment. if (mFragmentInfos.containsKey(launchingFragmentToken)) { resizeTaskFragment(wct, launchingFragmentToken, launchingFragmentBounds); } else { createTaskFragmentAndReparentActivity(wct, launchingFragmentToken, ownerToken, launchingFragmentBounds, WINDOWING_MODE_MULTI_WINDOW, launchingActivity); } // Create a TaskFragment for the secondary activity. createTaskFragmentAndStartActivity(wct, secondaryFragmentToken, ownerToken, secondaryFragmentBounds, WINDOWING_MODE_MULTI_WINDOW, activityIntent, activityOptions); applyTransaction(wct); } /** * Expands an existing TaskFragment to fill parent. * @param wct WindowContainerTransaction in which the task fragment should be resized. * @param fragmentToken token of an existing TaskFragment. */ void expandTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) { resizeTaskFragment(wct, fragmentToken, new Rect()); } /** * Expands an existing TaskFragment to fill parent. * @param fragmentToken token of an existing TaskFragment. */ void expandTaskFragment(IBinder fragmentToken) { WindowContainerTransaction wct = new WindowContainerTransaction(); expandTaskFragment(wct, fragmentToken); applyTransaction(wct); } /** * Expands an Activity to fill parent by moving it to a new TaskFragment. * @param fragmentToken token to create new TaskFragment with. * @param activity activity to move to the fill-parent TaskFragment. */ void expandActivity(IBinder fragmentToken, Activity activity) { final WindowContainerTransaction wct = new WindowContainerTransaction(); createTaskFragmentAndReparentActivity( wct, fragmentToken, activity.getActivityToken(), new Rect(), WINDOWING_MODE_UNDEFINED, activity); applyTransaction(wct); } /** * @param ownerToken The token of the activity that creates this task fragment. It does not * have to be a child of this task fragment, but must belong to the same task. */ private void createTaskFragmentAndReparentActivity( WindowContainerTransaction wct, IBinder fragmentToken, IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode, Activity activity) { final TaskFragmentCreationParams fragmentOptions = createFragmentOptions(fragmentToken, ownerToken, bounds, windowingMode); wct.createTaskFragment(fragmentOptions) .reparentActivityToTaskFragment(fragmentToken, activity.getActivityToken()); } /** * @param ownerToken The token of the activity that creates this task fragment. It does not * have to be a child of this task fragment, but must belong to the same task. */ private void createTaskFragmentAndStartActivity( WindowContainerTransaction wct, IBinder fragmentToken, IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode, Intent activityIntent, @Nullable Bundle activityOptions) { final TaskFragmentCreationParams fragmentOptions = createFragmentOptions(fragmentToken, ownerToken, bounds, windowingMode); wct.createTaskFragment(fragmentOptions) .startActivityInTaskFragment(fragmentToken, activityIntent, activityOptions); } TaskFragmentCreationParams createFragmentOptions(IBinder fragmentToken, IBinder ownerToken, Rect bounds, @WindowingMode int windowingMode) { if (mFragmentInfos.containsKey(fragmentToken)) { throw new IllegalArgumentException( "There is an existing TaskFragment with fragmentToken=" + fragmentToken); } return new TaskFragmentCreationParams.Builder( getIOrganizer(), fragmentToken, ownerToken) .setInitialBounds(bounds) .setWindowingMode(windowingMode) .build(); } void resizeTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken, @Nullable Rect bounds) { if (!mFragmentInfos.containsKey(fragmentToken)) { throw new IllegalArgumentException( "Can't find an existing TaskFragment with fragmentToken=" + fragmentToken); } if (bounds == null) { bounds = new Rect(); } wct.setBounds(mFragmentInfos.get(fragmentToken).getToken(), bounds); } void deleteTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) { if (!mFragmentInfos.containsKey(fragmentToken)) { throw new IllegalArgumentException( "Can't find an existing TaskFragment with fragmentToken=" + fragmentToken); } wct.deleteTaskFragment(mFragmentInfos.get(fragmentToken).getToken()); } @Override public void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) { final TaskFragmentInfo info = taskFragmentAppearedInfo.getTaskFragmentInfo(); final IBinder fragmentToken = info.getFragmentToken(); final SurfaceControl leash = taskFragmentAppearedInfo.getLeash(); mFragmentInfos.put(fragmentToken, info); mFragmentLeashes.put(fragmentToken, leash); if (mCallback != null) { mCallback.onTaskFragmentAppeared(taskFragmentAppearedInfo); } } @Override public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) { final IBinder fragmentToken = taskFragmentInfo.getFragmentToken(); mFragmentInfos.put(fragmentToken, taskFragmentInfo); if (mCallback != null) { mCallback.onTaskFragmentInfoChanged(taskFragmentInfo); } } @Override public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) { mFragmentInfos.remove(taskFragmentInfo.getFragmentToken()); mFragmentLeashes.remove(taskFragmentInfo.getFragmentToken()); mFragmentParentConfigs.remove(taskFragmentInfo.getFragmentToken()); if (mCallback != null) { mCallback.onTaskFragmentVanished(taskFragmentInfo); } } @Override public void onTaskFragmentParentInfoChanged( @NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) { mFragmentParentConfigs.put(fragmentToken, parentConfig); if (mCallback != null) { mCallback.onTaskFragmentParentInfoChanged(fragmentToken, parentConfig); } } }
services/core/java/com/android/server/wm/ActivityRecord.java +7 −0 Original line number Diff line number Diff line Loading @@ -1885,6 +1885,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A task.setRootProcess(proc); } proc.addActivityIfNeeded(this); // Update the associated task fragment after setting the process, since it's required for // filtering to only report activities that belong to the same process. final TaskFragment tf = getTaskFragment(); if (tf != null) { tf.sendTaskFragmentInfoChanged(); } } boolean hasProcess() { Loading
services/core/java/com/android/server/wm/TaskFragment.java +11 −1 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ import android.app.servertransaction.NewIntentItem; import android.app.servertransaction.PauseActivityItem; import android.app.servertransaction.ResumeActivityItem; import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; import android.os.IBinder; import android.os.RemoteException; Loading Loading @@ -1475,6 +1476,12 @@ class TaskFragment extends WindowContainer<WindowContainer> { } } void onChildPositionChanged(WindowContainer child) { super.onChildPositionChanged(child); sendTaskFragmentInfoChanged(); } void executeAppTransition(ActivityOptions options) { // No app transition applied to the task fragment. } Loading Loading @@ -2027,13 +2034,16 @@ class TaskFragment extends WindowContainer<WindowContainer> { childActivities.add(wc.asActivityRecord().appToken); } } final Point positionInParent = new Point(); getRelativePosition(positionInParent); return new TaskFragmentInfo( mFragmentToken, mRemoteToken.toWindowContainerToken(), getConfiguration(), getChildCount() == 0, isVisible(), childActivities); childActivities, positionInParent); } @Nullable Loading
services/core/java/com/android/server/wm/WindowOrganizerController.java +2 −2 Original line number Diff line number Diff line Loading @@ -878,8 +878,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } private void sanitizeWindowContainer(WindowContainer wc) { if (!(wc instanceof Task) && !(wc instanceof DisplayArea)) { throw new RuntimeException("Invalid token in task or displayArea transaction"); if (!(wc instanceof TaskFragment) && !(wc instanceof DisplayArea)) { throw new RuntimeException("Invalid token in task fragment or displayArea transaction"); } } Loading