summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jiaming Liu <jiamingliu@google.com> 2025-02-07 21:44:10 +0000
committer Jiaming Liu <jiamingliu@google.com> 2025-02-08 17:51:21 +0000
commita32517c0a1924468d5ace0c9ff9fc6b0c31a2e64 (patch)
tree163b2178a2c13e255118aa7c1ebd2233ab70dc41
parentb088b1268362a33e6a92b7858d12286aa8cb9bf5 (diff)
Allow system organizer to watch additional config changes
System organizer may want to get TaskFragment info callbacks for some configuration changes, e.g. Launcher wants UI mode change callbacks for the TaskFragment. Bug: 385676993 Test: WindowOrganizerTests TaskFragmentOrganizerControllerTest Flag: EXEMPT bugfix Change-Id: I493b1d908b89422cc55087da9e2319b366f6006a
-rw-r--r--core/java/android/window/TaskFragmentCreationParams.java43
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java17
-rw-r--r--services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java20
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java27
5 files changed, 109 insertions, 4 deletions
diff --git a/core/java/android/window/TaskFragmentCreationParams.java b/core/java/android/window/TaskFragmentCreationParams.java
index 89327fe358f5..bc5ad50483ee 100644
--- a/core/java/android/window/TaskFragmentCreationParams.java
+++ b/core/java/android/window/TaskFragmentCreationParams.java
@@ -24,6 +24,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.TestApi;
+import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo.ScreenOrientation;
import android.graphics.Rect;
import android.os.IBinder;
@@ -112,12 +113,21 @@ public final class TaskFragmentCreationParams implements Parcelable {
*/
private final @ScreenOrientation int mOverrideOrientation;
+ /**
+ * {@link android.content.pm.ActivityInfo.Config} mask that specifies which
+ * configuration changes should trigger TaskFragment info change callbacks.
+ *
+ * @see android.content.pm.ActivityInfo.Config
+ */
+ private final @ActivityInfo.Config int mConfigurationChangeMask;
+
private TaskFragmentCreationParams(
@NonNull TaskFragmentOrganizerToken organizer, @NonNull IBinder fragmentToken,
@NonNull IBinder ownerToken, @NonNull Rect initialRelativeBounds,
@WindowingMode int windowingMode, @Nullable IBinder pairedPrimaryFragmentToken,
@Nullable IBinder pairedActivityToken, boolean allowTransitionWhenEmpty,
- @ScreenOrientation int overrideOrientation) {
+ @ScreenOrientation int overrideOrientation,
+ @ActivityInfo.Config int configurationChangeMask) {
if (pairedPrimaryFragmentToken != null && pairedActivityToken != null) {
throw new IllegalArgumentException("pairedPrimaryFragmentToken and"
+ " pairedActivityToken should not be set at the same time.");
@@ -131,6 +141,7 @@ public final class TaskFragmentCreationParams implements Parcelable {
mPairedActivityToken = pairedActivityToken;
mAllowTransitionWhenEmpty = allowTransitionWhenEmpty;
mOverrideOrientation = overrideOrientation;
+ mConfigurationChangeMask = configurationChangeMask;
}
@NonNull
@@ -186,6 +197,11 @@ public final class TaskFragmentCreationParams implements Parcelable {
return mOverrideOrientation;
}
+ /** @hide */
+ public @ActivityInfo.Config int getConfigurationChangeMask() {
+ return mConfigurationChangeMask;
+ }
+
private TaskFragmentCreationParams(Parcel in) {
mOrganizer = TaskFragmentOrganizerToken.CREATOR.createFromParcel(in);
mFragmentToken = in.readStrongBinder();
@@ -196,6 +212,7 @@ public final class TaskFragmentCreationParams implements Parcelable {
mPairedActivityToken = in.readStrongBinder();
mAllowTransitionWhenEmpty = in.readBoolean();
mOverrideOrientation = in.readInt();
+ mConfigurationChangeMask = in.readInt();
}
/** @hide */
@@ -210,6 +227,7 @@ public final class TaskFragmentCreationParams implements Parcelable {
dest.writeStrongBinder(mPairedActivityToken);
dest.writeBoolean(mAllowTransitionWhenEmpty);
dest.writeInt(mOverrideOrientation);
+ dest.writeInt(mConfigurationChangeMask);
}
@NonNull
@@ -238,6 +256,7 @@ public final class TaskFragmentCreationParams implements Parcelable {
+ " pairedActivityToken=" + mPairedActivityToken
+ " allowTransitionWhenEmpty=" + mAllowTransitionWhenEmpty
+ " overrideOrientation=" + mOverrideOrientation
+ + " configurationChangeMask=" + mConfigurationChangeMask
+ "}";
}
@@ -275,6 +294,8 @@ public final class TaskFragmentCreationParams implements Parcelable {
private @ScreenOrientation int mOverrideOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+ private @ActivityInfo.Config int mConfigurationChangeMask = 0;
+
public Builder(@NonNull TaskFragmentOrganizerToken organizer,
@NonNull IBinder fragmentToken, @NonNull IBinder ownerToken) {
mOrganizer = organizer;
@@ -369,12 +390,30 @@ public final class TaskFragmentCreationParams implements Parcelable {
return this;
}
+ /**
+ * Sets {@link android.content.pm.ActivityInfo.Config} mask that specifies which
+ * configuration changes should trigger TaskFragment info change callbacks.
+ *
+ * Only system organizers are allowed to configure this value. This value is ignored for
+ * non-system organizers.
+ *
+ * @see android.content.pm.ActivityInfo.Config
+ * @hide
+ */
+ @NonNull
+ public Builder setConfigurationChangeMask(
+ @ActivityInfo.Config int configurationChangeMask) {
+ mConfigurationChangeMask = configurationChangeMask;
+ return this;
+ }
+
/** Constructs the options to create TaskFragment with. */
@NonNull
public TaskFragmentCreationParams build() {
return new TaskFragmentCreationParams(mOrganizer, mFragmentToken, mOwnerToken,
mInitialRelativeBounds, mWindowingMode, mPairedPrimaryFragmentToken,
- mPairedActivityToken, mAllowTransitionWhenEmpty, mOverrideOrientation);
+ mPairedActivityToken, mAllowTransitionWhenEmpty, mOverrideOrientation,
+ mConfigurationChangeMask);
}
}
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index ba48fdc963de..129525729f83 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -394,6 +394,12 @@ class TaskFragment extends WindowContainer<WindowContainer> {
*/
private boolean mAllowTransitionWhenEmpty;
+ /**
+ * Specifies which configuration changes should trigger TaskFragment info changed callbacks.
+ * Only system TaskFragment organizers are allowed to set this value.
+ */
+ private @ActivityInfo.Config int mConfigurationChangeMaskForOrganizer;
+
/** When set, will force the task to report as invisible. */
static final int FLAG_FORCE_HIDDEN_FOR_PINNED_TASK = 1;
static final int FLAG_FORCE_HIDDEN_FOR_TASK_ORG = 1 << 1;
@@ -656,6 +662,17 @@ class TaskFragment extends WindowContainer<WindowContainer> {
mAllowTransitionWhenEmpty = allowTransitionWhenEmpty;
}
+ void setConfigurationChangeMaskForOrganizer(@ActivityInfo.Config int mask) {
+ // Only system organizers are allowed to set configuration change mask.
+ if (mTaskFragmentOrganizerController.isSystemOrganizer(mTaskFragmentOrganizer.asBinder())) {
+ mConfigurationChangeMaskForOrganizer = mask;
+ }
+ }
+
+ @ActivityInfo.Config int getConfigurationChangeMaskForOrganizer() {
+ return mConfigurationChangeMaskForOrganizer;
+ }
+
/** @see #mIsolatedNav */
boolean isIsolatedNav() {
return isEmbedded() && mIsolatedNav;
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index aaae160084a9..aa1baabb863e 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -349,8 +349,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
// 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())) {
+ final int configurationChangeMask = tf.getConfigurationChangeMaskForOrganizer();
+ if (info.equalsForTaskFragmentOrganizer(lastInfo)
+ && configurationsAreEqualForOrganizer(info.getConfiguration(),
+ lastInfo.getConfiguration(), configurationChangeMask)) {
return null;
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index a11f4b1f3fc3..f411aaea97be 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -2441,10 +2441,28 @@ 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) {
+ return configurationsAreEqualForOrganizer(newConfig, oldConfig, 0 /* additionalMask */);
+ }
+
+ /**
+ * Whether the configuration changes are important to report back to an organizer.
+ *
+ * @param newConfig the new configuration
+ * @param oldConfig the old configuration
+ * @param additionalMask specifies additional configuration changes that the organizer is
+ * interested in. If the configuration change matches any bit in the mask,
+ * {@code false} is returned.
+ */
+ static boolean configurationsAreEqualForOrganizer(
+ Configuration newConfig, @Nullable Configuration oldConfig,
+ @ActivityInfo.Config int additionalMask) {
if (oldConfig == null) {
return false;
}
int cfgChanges = newConfig.diff(oldConfig);
+ if ((cfgChanges & additionalMask) != 0) {
+ return false;
+ }
final int winCfgChanges = (cfgChanges & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
? (int) newConfig.windowConfiguration.diff(oldConfig.windowConfiguration,
true /* compareUndefined */) : 0;
@@ -2651,6 +2669,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
ownerActivity.getUid(), ownerActivity.info.processName);
if (mTaskFragmentOrganizerController.isSystemOrganizer(organizerToken.asBinder())) {
taskFragment.setOverrideOrientation(creationParams.getOverrideOrientation());
+ taskFragment.setConfigurationChangeMaskForOrganizer(
+ creationParams.getConfigurationChangeMask());
}
final int position;
if (creationParams.getPairedPrimaryFragmentToken() != null) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 1281be5132d3..7030d986494f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -26,6 +26,7 @@ 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 android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -33,6 +34,8 @@ import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
+import static android.content.res.Configuration.UI_MODE_NIGHT_NO;
+import static android.content.res.Configuration.UI_MODE_NIGHT_YES;
import static android.view.InsetsSource.FLAG_FORCE_CONSUMING;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
@@ -1983,6 +1986,30 @@ public class WindowOrganizerTests extends WindowTestsBase {
testSetAlwaysOnTop(displayArea);
}
+ @Test
+ public void testConfigurationsAreEqualForOrganizer() {
+ Configuration config1 = new Configuration();
+ config1.smallestScreenWidthDp = 300;
+ config1.uiMode = UI_MODE_NIGHT_YES;
+
+ Configuration config2 = new Configuration(config1);
+ config2.uiMode = UI_MODE_NIGHT_NO;
+
+ Configuration config3 = new Configuration(config1);
+ config3.smallestScreenWidthDp = 500;
+
+ // Should be equal for non-controllable configuration changes.
+ assertTrue(WindowOrganizerController.configurationsAreEqualForOrganizer(config1, config2));
+
+ // Should be unequal for non-controllable configuration changes if the organizer is
+ // interested in that change.
+ assertFalse(WindowOrganizerController.configurationsAreEqualForOrganizer(
+ config1, config2, CONFIG_UI_MODE));
+
+ // Should be unequal for controllable configuration changes.
+ assertFalse(WindowOrganizerController.configurationsAreEqualForOrganizer(config1, config3));
+ }
+
private void testSetAlwaysOnTop(WindowContainer wc) {
final WindowContainerTransaction t = new WindowContainerTransaction();
t.setAlwaysOnTop(wc.mRemoteToken.toWindowContainerToken(), true);