Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 226de137 authored by Evan Rosky's avatar Evan Rosky
Browse files

Add focusability into the hierarchy and Container transaction

Split-screen will eventually be replaced by a hierarchical
mechinasm. This means the RAC.mIsDockMinimized and primary split
checking will go away.

In its place, add focusable to windowcontainer and have it
override all children's focusability.

Also, fixes a bug where activity configuration wasn't updated
properly after a WC transaction.

Bug: 133381284
Test: added wmtest
Change-Id: I35ed1561cc32785528854a8a53e52a13144f31c1
parent a6fb9db9
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -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;
    }
@@ -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;

@@ -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);
@@ -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;
@@ -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();
        }
@@ -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);

+4 −2
Original line number Diff line number Diff line
@@ -2130,8 +2130,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() {
@@ -2482,7 +2484,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.
+10 −3
Original line number Diff line number Diff line
@@ -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;
@@ -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
+2 −2
Original line number Diff line number Diff line
@@ -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
@@ -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");
                }
+67 −21
Original line number Diff line number Diff line
@@ -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;
@@ -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;

    /**
@@ -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");
@@ -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,
@@ -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) {
@@ -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