Loading core/java/android/view/WindowContainerTransaction.java +35 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,18 @@ public class WindowContainerTransaction implements Parcelable { return this; } /** * Sets whether a container or any of its children can be focusable. When {@code false}, no * child can be focused; however, when {@code true}, it is still possible for children to be * non-focusable due to WM policy. */ public WindowContainerTransaction setFocusable(IWindowContainer container, boolean focusable) { Change chg = getOrCreateChange(container.asBinder()); chg.mFocusable = focusable; chg.mChangeMask |= Change.CHANGE_FOCUSABLE; return this; } public Map<IBinder, Change> getChanges() { return mChanges; } Loading Loading @@ -112,7 +124,11 @@ public class WindowContainerTransaction implements Parcelable { * @hide */ public static class Change implements Parcelable { public static final int CHANGE_FOCUSABLE = 1; private final Configuration mConfiguration = new Configuration(); private boolean mFocusable = true; private int mChangeMask = 0; private @ActivityInfo.Config int mConfigSetMask = 0; private @WindowConfiguration.WindowConfig int mWindowSetMask = 0; Loading @@ -123,6 +139,8 @@ public class WindowContainerTransaction implements Parcelable { protected Change(Parcel in) { mConfiguration.readFromParcel(in); mFocusable = in.readBoolean(); mChangeMask = in.readInt(); mConfigSetMask = in.readInt(); mWindowSetMask = in.readInt(); mSchedulePipCallback = (in.readInt() != 0); Loading @@ -136,6 +154,18 @@ public class WindowContainerTransaction implements Parcelable { return mConfiguration; } /** Gets the requested focusable value */ public boolean getFocusable() { if ((mChangeMask & CHANGE_FOCUSABLE) == 0) { throw new RuntimeException("Focusable not set. check CHANGE_FOCUSABLE first"); } return mFocusable; } public int getChangeMask() { return mChangeMask; } @ActivityInfo.Config public int getConfigSetMask() { return mConfigSetMask; Loading Loading @@ -170,6 +200,9 @@ public class WindowContainerTransaction implements Parcelable { if (changesSss) { sb.append("ssw:" + mConfiguration.smallestScreenWidthDp + ","); } if ((mChangeMask & CHANGE_FOCUSABLE) != 0) { sb.append("focusable:" + mFocusable + ","); } sb.append("}"); return sb.toString(); } Loading @@ -177,6 +210,8 @@ public class WindowContainerTransaction implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { mConfiguration.writeToParcel(dest, flags); dest.writeBoolean(mFocusable); dest.writeInt(mChangeMask); dest.writeInt(mConfigSetMask); dest.writeInt(mWindowSetMask); Loading services/core/java/com/android/server/wm/ActivityRecord.java +4 −2 Original line number Diff line number Diff line Loading @@ -2137,8 +2137,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A (intent == null || (intent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0); } @Override boolean isFocusable() { return mRootWindowContainer.isFocusable(this, isAlwaysFocusable()); return super.isFocusable() && (getWindowConfiguration().canReceiveKeys() || isAlwaysFocusable()); } boolean isResizeable() { Loading Loading @@ -2489,7 +2491,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // We are finishing the top focused activity and its stack has nothing to be focused so // the next focusable stack should be focused. if (mayAdjustTop && (stack.topRunningActivity() == null || !stack.isFocusable())) { && (stack.topRunningActivity() == null || !stack.isTopActivityFocusable())) { if (shouldAdjustGlobalFocus) { // Move the entire hierarchy to top with updating global top resumed activity // and focused application if needed. Loading services/core/java/com/android/server/wm/ActivityStack.java +10 −3 Original line number Diff line number Diff line Loading @@ -161,9 +161,9 @@ import android.util.proto.ProtoOutputStream; import android.view.Display; import android.view.DisplayCutout; import android.view.DisplayInfo; import android.view.ITaskOrganizer; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.ITaskOrganizer; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -1248,13 +1248,20 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn } } @Override boolean isFocusable() { return super.isFocusable() && !(inSplitScreenPrimaryWindowingMode() && mRootWindowContainer.mIsDockMinimized); } boolean isTopActivityFocusable() { final ActivityRecord r = topRunningActivity(); return mRootWindowContainer.isFocusable(this, r != null && r.isFocusable()); return r != null ? r.isFocusable() : (isFocusable() && getWindowConfiguration().canReceiveKeys()); } boolean isFocusableAndVisible() { return isFocusable() && shouldBeVisible(null /* starting */); return isTopActivityFocusable() && shouldBeVisible(null /* starting */); } @Override Loading services/core/java/com/android/server/wm/ActivityStarter.java +2 −2 Original line number Diff line number Diff line Loading @@ -1569,7 +1569,7 @@ class ActivityStarter { if (mDoResume) { final ActivityRecord topTaskActivity = mStartActivity.getTask().topRunningActivityLocked(); if (!mTargetStack.isFocusable() if (!mTargetStack.isTopActivityFocusable() || (topTaskActivity != null && topTaskActivity.isTaskOverlay() && mStartActivity != topTaskActivity)) { // If the activity is not focusable, we can't resume it, but still would like to Loading @@ -1588,7 +1588,7 @@ class ActivityStarter { // will not update the focused stack. If starting the new activity now allows the // task stack to be focusable, then ensure that we now update the focused stack // accordingly. if (mTargetStack.isFocusable() if (mTargetStack.isTopActivityFocusable() && !mRootWindowContainer.isTopDisplayFocusedStack(mTargetStack)) { mTargetStack.moveToFront("startActivityInner"); } Loading services/core/java/com/android/server/wm/ActivityTaskManagerService.java +67 −21 Original line number Diff line number Diff line Loading @@ -248,7 +248,6 @@ import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.KeyguardDismissCallback; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastPrintWriter; import com.android.internal.util.Preconditions; import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledFunction; import com.android.internal.util.function.pooled.PooledLambda; Loading Loading @@ -345,6 +344,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** This activity is being relaunched due to a free-resize operation. */ public static final int RELAUNCH_REASON_FREE_RESIZE = 2; /** Flag indicating that an applied transaction may have effected lifecycle */ private static final int TRANSACT_EFFECTS_CLIENT_CONFIG = 1; private static final int TRANSACT_EFFECTS_LIFECYCLE = 1 << 1; Context mContext; /** Loading Loading @@ -3300,7 +3303,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } private void sanitizeAndApplyConfigChange(ConfigurationContainer container, private int sanitizeAndApplyChange(ConfigurationContainer container, WindowContainerTransaction.Change change) { if (!(container instanceof Task || container instanceof ActivityStack)) { throw new RuntimeException("Invalid token in task transaction"); Loading @@ -3312,12 +3315,22 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { configMask &= ActivityInfo.CONFIG_WINDOW_CONFIGURATION | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; windowMask &= WindowConfiguration.WINDOW_CONFIG_BOUNDS; int effects = 0; if (configMask != 0) { Configuration c = new Configuration(container.getRequestedOverrideConfiguration()); c.setTo(change.getConfiguration(), configMask, windowMask); container.onRequestedOverrideConfigurationChanged(c); // TODO(b/145675353): remove the following once we could apply new bounds to the // pinned stack together with its children. resizePinnedStackIfNeeded(container, configMask, windowMask, c); effects |= TRANSACT_EFFECTS_CLIENT_CONFIG; } if ((change.getChangeMask() & WindowContainerTransaction.Change.CHANGE_FOCUSABLE) != 0) { if (container.setFocusable(change.getFocusable())) { effects |= TRANSACT_EFFECTS_LIFECYCLE; } } return effects; } private void resizePinnedStackIfNeeded(ConfigurationContainer container, int configMask, Loading @@ -3334,9 +3347,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } private void applyWindowContainerChange(ConfigurationContainer cc, private int applyWindowContainerChange(ConfigurationContainer cc, WindowContainerTransaction.Change c) { sanitizeAndApplyConfigChange(cc, c); int effects = sanitizeAndApplyChange(cc, c); Rect enterPipBounds = c.getEnterPipBounds(); if (enterPipBounds != null) { Loading @@ -3344,25 +3357,58 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mStackSupervisor.updatePictureInPictureMode(tr, enterPipBounds, true); } return effects; } @Override public void applyContainerTransaction(WindowContainerTransaction t) { mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "applyContainerTransaction()"); long ident = Binder.clearCallingIdentity(); try { if (t == null) { return; } long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { int effects = 0; deferWindowLayout(); try { ArraySet<WindowContainer> haveConfigChanges = new ArraySet<>(); Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries = t.getChanges().entrySet().iterator(); while (entries.hasNext()) { final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next(); final ConfigurationContainer cc = ConfigurationContainer.RemoteToken.fromBinder( final ConfigurationContainer cc = ConfigurationContainer.RemoteToken.fromBinder( entry.getKey()).getContainer(); applyWindowContainerChange(cc, entry.getValue()); int containerEffect = applyWindowContainerChange(cc, entry.getValue()); effects |= containerEffect; // Lifecycle changes will trigger ensureConfig for everything. if ((effects & TRANSACT_EFFECTS_LIFECYCLE) == 0 && (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) { if (cc instanceof WindowContainer) { haveConfigChanges.add((WindowContainer) cc); } } } if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) { // Already calls ensureActivityConfig mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); } else if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) { final PooledConsumer f = PooledLambda.obtainConsumer( ActivityRecord::ensureActivityConfiguration, PooledLambda.__(ActivityRecord.class), 0, false /* preserveWindow */); try { for (int i = haveConfigChanges.size() - 1; i >= 0; --i) { haveConfigChanges.valueAt(i).forAllActivities(f); } } finally { f.recycle(); } } } finally { continueWindowLayout(); } } } finally { Loading Loading
core/java/android/view/WindowContainerTransaction.java +35 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,18 @@ public class WindowContainerTransaction implements Parcelable { return this; } /** * Sets whether a container or any of its children can be focusable. When {@code false}, no * child can be focused; however, when {@code true}, it is still possible for children to be * non-focusable due to WM policy. */ public WindowContainerTransaction setFocusable(IWindowContainer container, boolean focusable) { Change chg = getOrCreateChange(container.asBinder()); chg.mFocusable = focusable; chg.mChangeMask |= Change.CHANGE_FOCUSABLE; return this; } public Map<IBinder, Change> getChanges() { return mChanges; } Loading Loading @@ -112,7 +124,11 @@ public class WindowContainerTransaction implements Parcelable { * @hide */ public static class Change implements Parcelable { public static final int CHANGE_FOCUSABLE = 1; private final Configuration mConfiguration = new Configuration(); private boolean mFocusable = true; private int mChangeMask = 0; private @ActivityInfo.Config int mConfigSetMask = 0; private @WindowConfiguration.WindowConfig int mWindowSetMask = 0; Loading @@ -123,6 +139,8 @@ public class WindowContainerTransaction implements Parcelable { protected Change(Parcel in) { mConfiguration.readFromParcel(in); mFocusable = in.readBoolean(); mChangeMask = in.readInt(); mConfigSetMask = in.readInt(); mWindowSetMask = in.readInt(); mSchedulePipCallback = (in.readInt() != 0); Loading @@ -136,6 +154,18 @@ public class WindowContainerTransaction implements Parcelable { return mConfiguration; } /** Gets the requested focusable value */ public boolean getFocusable() { if ((mChangeMask & CHANGE_FOCUSABLE) == 0) { throw new RuntimeException("Focusable not set. check CHANGE_FOCUSABLE first"); } return mFocusable; } public int getChangeMask() { return mChangeMask; } @ActivityInfo.Config public int getConfigSetMask() { return mConfigSetMask; Loading Loading @@ -170,6 +200,9 @@ public class WindowContainerTransaction implements Parcelable { if (changesSss) { sb.append("ssw:" + mConfiguration.smallestScreenWidthDp + ","); } if ((mChangeMask & CHANGE_FOCUSABLE) != 0) { sb.append("focusable:" + mFocusable + ","); } sb.append("}"); return sb.toString(); } Loading @@ -177,6 +210,8 @@ public class WindowContainerTransaction implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { mConfiguration.writeToParcel(dest, flags); dest.writeBoolean(mFocusable); dest.writeInt(mChangeMask); dest.writeInt(mConfigSetMask); dest.writeInt(mWindowSetMask); Loading
services/core/java/com/android/server/wm/ActivityRecord.java +4 −2 Original line number Diff line number Diff line Loading @@ -2137,8 +2137,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A (intent == null || (intent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0); } @Override boolean isFocusable() { return mRootWindowContainer.isFocusable(this, isAlwaysFocusable()); return super.isFocusable() && (getWindowConfiguration().canReceiveKeys() || isAlwaysFocusable()); } boolean isResizeable() { Loading Loading @@ -2489,7 +2491,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // We are finishing the top focused activity and its stack has nothing to be focused so // the next focusable stack should be focused. if (mayAdjustTop && (stack.topRunningActivity() == null || !stack.isFocusable())) { && (stack.topRunningActivity() == null || !stack.isTopActivityFocusable())) { if (shouldAdjustGlobalFocus) { // Move the entire hierarchy to top with updating global top resumed activity // and focused application if needed. Loading
services/core/java/com/android/server/wm/ActivityStack.java +10 −3 Original line number Diff line number Diff line Loading @@ -161,9 +161,9 @@ import android.util.proto.ProtoOutputStream; import android.view.Display; import android.view.DisplayCutout; import android.view.DisplayInfo; import android.view.ITaskOrganizer; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.ITaskOrganizer; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -1248,13 +1248,20 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn } } @Override boolean isFocusable() { return super.isFocusable() && !(inSplitScreenPrimaryWindowingMode() && mRootWindowContainer.mIsDockMinimized); } boolean isTopActivityFocusable() { final ActivityRecord r = topRunningActivity(); return mRootWindowContainer.isFocusable(this, r != null && r.isFocusable()); return r != null ? r.isFocusable() : (isFocusable() && getWindowConfiguration().canReceiveKeys()); } boolean isFocusableAndVisible() { return isFocusable() && shouldBeVisible(null /* starting */); return isTopActivityFocusable() && shouldBeVisible(null /* starting */); } @Override Loading
services/core/java/com/android/server/wm/ActivityStarter.java +2 −2 Original line number Diff line number Diff line Loading @@ -1569,7 +1569,7 @@ class ActivityStarter { if (mDoResume) { final ActivityRecord topTaskActivity = mStartActivity.getTask().topRunningActivityLocked(); if (!mTargetStack.isFocusable() if (!mTargetStack.isTopActivityFocusable() || (topTaskActivity != null && topTaskActivity.isTaskOverlay() && mStartActivity != topTaskActivity)) { // If the activity is not focusable, we can't resume it, but still would like to Loading @@ -1588,7 +1588,7 @@ class ActivityStarter { // will not update the focused stack. If starting the new activity now allows the // task stack to be focusable, then ensure that we now update the focused stack // accordingly. if (mTargetStack.isFocusable() if (mTargetStack.isTopActivityFocusable() && !mRootWindowContainer.isTopDisplayFocusedStack(mTargetStack)) { mTargetStack.moveToFront("startActivityInner"); } Loading
services/core/java/com/android/server/wm/ActivityTaskManagerService.java +67 −21 Original line number Diff line number Diff line Loading @@ -248,7 +248,6 @@ import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.KeyguardDismissCallback; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastPrintWriter; import com.android.internal.util.Preconditions; import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledFunction; import com.android.internal.util.function.pooled.PooledLambda; Loading Loading @@ -345,6 +344,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** This activity is being relaunched due to a free-resize operation. */ public static final int RELAUNCH_REASON_FREE_RESIZE = 2; /** Flag indicating that an applied transaction may have effected lifecycle */ private static final int TRANSACT_EFFECTS_CLIENT_CONFIG = 1; private static final int TRANSACT_EFFECTS_LIFECYCLE = 1 << 1; Context mContext; /** Loading Loading @@ -3300,7 +3303,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } private void sanitizeAndApplyConfigChange(ConfigurationContainer container, private int sanitizeAndApplyChange(ConfigurationContainer container, WindowContainerTransaction.Change change) { if (!(container instanceof Task || container instanceof ActivityStack)) { throw new RuntimeException("Invalid token in task transaction"); Loading @@ -3312,12 +3315,22 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { configMask &= ActivityInfo.CONFIG_WINDOW_CONFIGURATION | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; windowMask &= WindowConfiguration.WINDOW_CONFIG_BOUNDS; int effects = 0; if (configMask != 0) { Configuration c = new Configuration(container.getRequestedOverrideConfiguration()); c.setTo(change.getConfiguration(), configMask, windowMask); container.onRequestedOverrideConfigurationChanged(c); // TODO(b/145675353): remove the following once we could apply new bounds to the // pinned stack together with its children. resizePinnedStackIfNeeded(container, configMask, windowMask, c); effects |= TRANSACT_EFFECTS_CLIENT_CONFIG; } if ((change.getChangeMask() & WindowContainerTransaction.Change.CHANGE_FOCUSABLE) != 0) { if (container.setFocusable(change.getFocusable())) { effects |= TRANSACT_EFFECTS_LIFECYCLE; } } return effects; } private void resizePinnedStackIfNeeded(ConfigurationContainer container, int configMask, Loading @@ -3334,9 +3347,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } private void applyWindowContainerChange(ConfigurationContainer cc, private int applyWindowContainerChange(ConfigurationContainer cc, WindowContainerTransaction.Change c) { sanitizeAndApplyConfigChange(cc, c); int effects = sanitizeAndApplyChange(cc, c); Rect enterPipBounds = c.getEnterPipBounds(); if (enterPipBounds != null) { Loading @@ -3344,25 +3357,58 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mStackSupervisor.updatePictureInPictureMode(tr, enterPipBounds, true); } return effects; } @Override public void applyContainerTransaction(WindowContainerTransaction t) { mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "applyContainerTransaction()"); long ident = Binder.clearCallingIdentity(); try { if (t == null) { return; } long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { int effects = 0; deferWindowLayout(); try { ArraySet<WindowContainer> haveConfigChanges = new ArraySet<>(); Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries = t.getChanges().entrySet().iterator(); while (entries.hasNext()) { final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next(); final ConfigurationContainer cc = ConfigurationContainer.RemoteToken.fromBinder( final ConfigurationContainer cc = ConfigurationContainer.RemoteToken.fromBinder( entry.getKey()).getContainer(); applyWindowContainerChange(cc, entry.getValue()); int containerEffect = applyWindowContainerChange(cc, entry.getValue()); effects |= containerEffect; // Lifecycle changes will trigger ensureConfig for everything. if ((effects & TRANSACT_EFFECTS_LIFECYCLE) == 0 && (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) { if (cc instanceof WindowContainer) { haveConfigChanges.add((WindowContainer) cc); } } } if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) { // Already calls ensureActivityConfig mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); } else if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) { final PooledConsumer f = PooledLambda.obtainConsumer( ActivityRecord::ensureActivityConfiguration, PooledLambda.__(ActivityRecord.class), 0, false /* preserveWindow */); try { for (int i = haveConfigChanges.size() - 1; i >= 0; --i) { haveConfigChanges.valueAt(i).forAllActivities(f); } } finally { f.recycle(); } } } finally { continueWindowLayout(); } } } finally { Loading