Notify TaskFragmentOrganizer onConfigurationChanged

Bug: 190433129
Bug: 190433500
Test: N/A
Change-Id: I383a434d536ac08f7cf82dfd87cd24bfc53a6d58
This commit is contained in:
Chris Li
2021-06-23 16:23:44 -07:00
parent 4a0aaa65bf
commit ad2dc01882
6 changed files with 138 additions and 32 deletions

View File

@@ -331,11 +331,10 @@ public class TaskInfo {
}
/**
* Returns {@code true} if parameters that are important for task organizers have changed
* and {@link com.android.server.wm.TaskOrginizerController} needs to notify listeners
* about that.
* @hide
*/
* Returns {@code true} if the parameters that are important for task organizers are equal
* between this {@link TaskInfo} and {@param that}.
* @hide
*/
public boolean equalsForTaskOrganizer(@Nullable TaskInfo that) {
if (that == null) {
return false;

View File

@@ -16,7 +16,10 @@
package android.window;
import static android.app.WindowConfiguration.WindowingMode;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.res.Configuration;
import android.os.IBinder;
@@ -94,6 +97,28 @@ public final class TaskFragmentInfo implements Parcelable {
return mIsVisible;
}
@WindowingMode
public int getWindowingMode() {
return mConfiguration.windowConfiguration.getWindowingMode();
}
/**
* Returns {@code true} if the parameters that are important for task fragment organizers are
* equal between this {@link TaskFragmentInfo} and {@param that}.
*/
public boolean equalsForTaskFragmentOrganizer(@Nullable TaskFragmentInfo that) {
if (that == null) {
return false;
}
return mFragmentToken.equals(that.mFragmentToken)
&& mInitialComponentName.equals(that.mInitialComponentName)
&& mToken.equals(that.mToken)
&& mIsEmpty == that.mIsEmpty
&& mIsVisible == that.mIsVisible
&& getWindowingMode() == that.getWindowingMode();
}
private TaskFragmentInfo(Parcel in) {
mFragmentToken = in.readStrongBinder();
mInitialComponentName = in.readTypedObject(ComponentName.CREATOR);

View File

@@ -142,6 +142,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
final ActivityTaskManagerService mAtmService;
final ActivityTaskSupervisor mTaskSupervisor;
final RootWindowContainer mRootWindowContainer;
private final TaskFragmentOrganizerController mTaskFragmentOrganizerController;
// TODO(b/189384393): this is not set in TaskFragment so far. It should be passed from the
// parent task when adding to the hierarchy
@@ -272,6 +273,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
mTaskSupervisor = atmService.mTaskSupervisor;
mRootWindowContainer = mAtmService.mRootWindowContainer;
mCreatedByOrganizer = createdByOrganizer;
mTaskFragmentOrganizerController =
mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController;
}
void setAdjacentTaskFragment(TaskFragment taskFragment) {
@@ -1937,6 +1940,34 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return getTopChild().getActivityType();
}
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
super.onConfigurationChanged(newParentConfig);
if (mTaskFragmentOrganizer != null) {
// Parent config may have changed. The controller will check if there is any important
// config change for the organizer.
mTaskFragmentOrganizerController
.onTaskFragmentParentInfoChanged(mTaskFragmentOrganizer, this);
mTaskFragmentOrganizerController
.onTaskFragmentInfoChanged(mTaskFragmentOrganizer, this);
}
}
// TODO(b/190433129) call when TaskFragment is created from WCT#createTaskFragment
private void sendTaskFragmentAppeared() {
if (mTaskFragmentOrganizer != null) {
mTaskFragmentOrganizerController.onTaskFragmentAppeared(mTaskFragmentOrganizer, this);
}
}
// TODO(b/190433129) call when TaskFragment is removed from WCT#deleteTaskFragment
private void sendTaskFragmentVanished() {
if (mTaskFragmentOrganizer != null) {
mTaskFragmentOrganizerController.onTaskFragmentVanished(mTaskFragmentOrganizer, this);
}
}
/**
* Returns a {@link TaskFragmentInfo} with information from this TaskFragment. Should not be
* called from {@link Task}.

View File

@@ -17,7 +17,9 @@
package com.android.server.wm;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
import android.content.res.Configuration;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -27,11 +29,13 @@ import android.view.SurfaceControl;
import android.window.ITaskFragmentOrganizer;
import android.window.ITaskFragmentOrganizerController;
import android.window.TaskFragmentAppearedInfo;
import android.window.TaskFragmentInfo;
import com.android.internal.protolog.common.ProtoLog;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
/**
* Stores and manages the client {@link android.window.TaskFragmentOrganizer}.
@@ -43,6 +47,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
private final WindowManagerGlobalLock mGlobalLock;
private final Set<ITaskFragmentOrganizer> mOrganizers = new ArraySet<>();
private final Map<ITaskFragmentOrganizer, DeathRecipient> mDeathRecipients = new ArrayMap<>();
private final Map<TaskFragment, TaskFragmentInfo> mLastSentTaskFragmentInfos =
new WeakHashMap<>();
private final Map<TaskFragment, Configuration> mLastSentTaskFragmentParentConfigs =
new WeakHashMap<>();
private class DeathRecipient implements IBinder.DeathRecipient {
final ITaskFragmentOrganizer mOrganizer;
@@ -118,43 +126,75 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
}
void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment tf) {
validateOrganizer(organizer);
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment appeared name=%s", tf.getName());
final TaskFragmentInfo info = tf.getTaskFragmentInfo();
final SurfaceControl outSurfaceControl = new SurfaceControl(tf.getSurfaceControl(),
"TaskFragmentOrganizerController.onTaskFragmentInfoAppeared");
try {
final SurfaceControl outSurfaceControl = new SurfaceControl(tf.getSurfaceControl(),
"TaskFragmentOrganizerController.onTaskFragmentInfoAppeared");
organizer.onTaskFragmentAppeared(
new TaskFragmentAppearedInfo(tf.getTaskFragmentInfo(), outSurfaceControl));
new TaskFragmentAppearedInfo(info, outSurfaceControl));
mLastSentTaskFragmentInfos.put(tf, info);
} catch (RemoteException e) {
// Oh well...
}
}
void onTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) {
validateOrganizer(organizer);
// Check if the info is different from the last reported info.
final TaskFragmentInfo info = tf.getTaskFragmentInfo();
final TaskFragmentInfo lastInfo = mLastSentTaskFragmentInfos.get(tf);
if (info.equalsForTaskFragmentOrganizer(lastInfo) && configurationsAreEqualForOrganizer(
info.getConfiguration(), lastInfo.getConfiguration())) {
return;
}
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s", tf.getName());
try {
organizer.onTaskFragmentInfoChanged(tf.getTaskFragmentInfo());
mLastSentTaskFragmentInfos.put(tf, info);
} catch (RemoteException e) {
// Oh well...
}
}
void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment tf) {
validateOrganizer(organizer);
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment vanished name=%s", tf.getName());
try {
organizer.onTaskFragmentVanished(tf.getTaskFragmentInfo());
} catch (RemoteException e) {
// Oh well...
}
mLastSentTaskFragmentInfos.remove(tf);
mLastSentTaskFragmentParentConfigs.remove(tf);
}
void onTaskFragmentParentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) {
validateOrganizer(organizer);
// Check if the parent info is different from the last reported parent info.
if (tf.getParent() == null || tf.getParent().asTask() == null) {
mLastSentTaskFragmentParentConfigs.remove(tf);
return;
}
final Task parent = tf.getParent().asTask();
final Configuration parentConfig = parent.getConfiguration();
final Configuration lastParentConfig = mLastSentTaskFragmentParentConfigs.get(tf);
if (configurationsAreEqualForOrganizer(parentConfig, lastParentConfig)) {
return;
}
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
"TaskFragment parent info changed name=%s parentTaskId=%d",
tf.getName(), parent.mTaskId);
try {
organizer.onTaskFragmentParentInfoChanged(
tf.getFragmentToken(), parent.getConfiguration());
organizer.onTaskFragmentParentInfoChanged(tf.getFragmentToken(), parentConfig);
mLastSentTaskFragmentParentConfigs.put(tf, parentConfig);
} catch (RemoteException e) {
// Oh well...
}
@@ -167,4 +207,17 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
}
// TODO(b/190432728) move child activities of organized TaskFragment to leaf Task
}
/**
* Makes sure that the organizer has been correctly registered to prevent any Sidecar
* implementation from organizing {@link TaskFragment} without registering first. In such case,
* we wouldn't register {@link DeathRecipient} for the organizer, and might not remove the
* {@link TaskFragment} after the organizer process died.
*/
private void validateOrganizer(ITaskFragmentOrganizer organizer) {
if (!mOrganizers.contains(organizer)) {
throw new IllegalArgumentException(
"TaskFragmentOrganizer has not been registered. Organizer=" + organizer);
}
}
}

View File

@@ -23,15 +23,13 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANI
import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission;
import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_STARTING_REVEAL;
import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFIGS;
import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS;
import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.WindowConfiguration;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ParceledListSlice;
import android.graphics.Rect;
import android.os.Binder;
@@ -69,13 +67,6 @@ import java.util.function.Consumer;
class TaskOrganizerController extends ITaskOrganizerController.Stub {
private static final String TAG = "TaskOrganizerController";
/**
* Masks specifying which configurations are important to report back to an organizer when
* changed.
*/
private static final int REPORT_CONFIGS = CONTROLLABLE_CONFIGS;
private static final int REPORT_WINDOW_CONFIGS = CONTROLLABLE_WINDOW_CONFIGS;
// The set of modes that are currently supports
// TODO: Remove once the task organizer can support all modes
@VisibleForTesting
@@ -790,18 +781,9 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
mTmpTaskInfo.configuration.unset();
task.fillTaskInfo(mTmpTaskInfo);
boolean changed = !mTmpTaskInfo.equalsForTaskOrganizer(lastInfo);
if (!changed) {
int cfgChanges = mTmpTaskInfo.configuration.diff(lastInfo.configuration);
final int winCfgChanges = (cfgChanges & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
? (int) mTmpTaskInfo.configuration.windowConfiguration.diff(
lastInfo.configuration.windowConfiguration,
true /* compareUndefined */) : 0;
if ((winCfgChanges & REPORT_WINDOW_CONFIGS) == 0) {
cfgChanges &= ~ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
}
changed = (cfgChanges & REPORT_CONFIGS) != 0;
}
boolean changed = !mTmpTaskInfo.equalsForTaskOrganizer(lastInfo)
|| !configurationsAreEqualForOrganizer(
mTmpTaskInfo.configuration, lastInfo.configuration);
if (!(changed || force)) {
// mTmpTaskInfo will be reused next time.
return;

View File

@@ -847,6 +847,22 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
}
/** Whether the configuration changes are important to report back to an organizer. */
static boolean configurationsAreEqualForOrganizer(
Configuration newConfig, @Nullable Configuration oldConfig) {
if (oldConfig == null) {
return false;
}
int cfgChanges = newConfig.diff(oldConfig);
final int winCfgChanges = (cfgChanges & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
? (int) newConfig.windowConfiguration.diff(oldConfig.windowConfiguration,
true /* compareUndefined */) : 0;
if ((winCfgChanges & CONTROLLABLE_WINDOW_CONFIGS) == 0) {
cfgChanges &= ~ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
}
return (cfgChanges & CONTROLLABLE_CONFIGS) == 0;
}
private void enforceTaskPermission(String func) {
mService.enforceTaskPermission(func);
}