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

Commit a4936735 authored by Kazuki Takise's avatar Kazuki Takise
Browse files

Create PresentationController

This change is a pure refactoring (mostly just moving the code
added in [1] into PresentationController(Tests)).
PresentationController manages all the presentation windows and
applies relevant policies to them.

Given that we'll put adding/removing presentations into a
transition and that we'll add more policies to presentations,
PresentationController helps encapsulate and better maintain all
such logic in one place.

[1] I26108aa0bc0cac320c8fb50ea67543981ab77e23

Flag: com.android.window.flags.enable_presentation_for_connected_displays
Bug: 394507839
Test: WmTests:PresentationControllerTests
Change-Id: I0b658ce52c81cb58916f08ee552e7e77683e42c5
parent 8d487e5a
Loading
Loading
Loading
Loading
+2 −8
Original line number Original line Diff line number Diff line
@@ -248,7 +248,6 @@ import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.sEnableShellTransitions;
import static com.android.server.wm.WindowManagerService.sEnableShellTransitions;
import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
import static com.android.window.flags.Flags.enablePresentationForConnectedDisplays;


import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.END_TAG;
import static org.xmlpull.v1.XmlPullParser.END_TAG;
@@ -6225,13 +6224,8 @@ final class ActivityRecord extends WindowToken {
            return false;
            return false;
        }
        }


        // Hide all activities on the presenting display so that malicious apps can't do tap
        // A presentation stopps all activities behind on the same display.
        // jacking (b/391466268).
        if (mWmService.mPresentationController.shouldOccludeActivities(getDisplayId())) {
        // For now, this should only be applied to external displays because presentations can only
        // be shown on them.
        // TODO(b/390481621): Disallow a presentation from covering its controlling activity so that
        // the presentation won't stop its controlling activity.
        if (enablePresentationForConnectedDisplays() && mDisplayContent.mIsPresenting) {
            return false;
            return false;
        }
        }


+0 −3
Original line number Original line Diff line number Diff line
@@ -547,9 +547,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
    // TODO(multi-display): remove some of the usages.
    // TODO(multi-display): remove some of the usages.
    boolean isDefaultDisplay;
    boolean isDefaultDisplay;


    /** Indicates whether any presentation is shown on this display. */
    boolean mIsPresenting;

    /** Save allocating when calculating rects */
    /** Save allocating when calculating rects */
    private final Rect mTmpRect = new Rect();
    private final Rect mTmpRect = new Rect();
    private final Region mTmpRegion = new Region();
    private final Region mTmpRegion = new Region();
+79 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2025 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 com.android.server.wm;

import static com.android.window.flags.Flags.enablePresentationForConnectedDisplays;

import android.annotation.NonNull;
import android.util.IntArray;

/**
 * Manages presentation windows.
 */
class PresentationController {

    // TODO(b/395475549): Add support for display add/remove, and activity move across displays.
    private final IntArray mPresentingDisplayIds = new IntArray();

    PresentationController() {}

    private boolean isPresenting(int displayId) {
        return mPresentingDisplayIds.contains(displayId);
    }

    boolean shouldOccludeActivities(int displayId) {
        // All activities on the presenting display must be hidden so that malicious apps can't do
        // tap jacking (b/391466268).
        // For now, this should only be applied to external displays because presentations can only
        // be shown on them.
        // TODO(b/390481621): Disallow a presentation from covering its controlling activity so that
        // the presentation won't stop its controlling activity.
        return enablePresentationForConnectedDisplays() && isPresenting(displayId);
    }

    void onPresentationAdded(@NonNull WindowState win) {
        final int displayId = win.getDisplayId();
        if (isPresenting(displayId)) {
            return;
        }
        mPresentingDisplayIds.add(displayId);
        if (enablePresentationForConnectedDisplays()) {
            // A presentation hides all activities behind on the same display.
            win.mDisplayContent.ensureActivitiesVisible(/*starting=*/ null,
                    /*notifyClients=*/ true);
        }
        win.mWmService.mDisplayManagerInternal.onPresentation(displayId, /*isShown=*/ true);
    }

    void onPresentationRemoved(@NonNull WindowState win) {
        final int displayId = win.getDisplayId();
        if (!isPresenting(displayId)) {
            return;
        }
        // TODO(b/393945496): Make sure that there's one presentation at most per display.
        final int displayIdIndex = mPresentingDisplayIds.indexOf(displayId);
        if (displayIdIndex != -1) {
            mPresentingDisplayIds.remove(displayIdIndex);
        }
        if (enablePresentationForConnectedDisplays()) {
            // A presentation hides all activities behind on the same display.
            win.mDisplayContent.ensureActivitiesVisible(/*starting=*/ null,
                    /*notifyClients=*/ true);
        }
        win.mWmService.mDisplayManagerInternal.onPresentation(displayId, /*isShown=*/ false);
    }
}
+5 −11
Original line number Original line Diff line number Diff line
@@ -157,7 +157,6 @@ import static com.android.server.wm.WindowManagerServiceDumpProto.POLICY;
import static com.android.server.wm.WindowManagerServiceDumpProto.ROOT_WINDOW_CONTAINER;
import static com.android.server.wm.WindowManagerServiceDumpProto.ROOT_WINDOW_CONTAINER;
import static com.android.server.wm.WindowManagerServiceDumpProto.WINDOW_FRAMES_VALID;
import static com.android.server.wm.WindowManagerServiceDumpProto.WINDOW_FRAMES_VALID;
import static com.android.window.flags.Flags.enableDisplayFocusInShellTransitions;
import static com.android.window.flags.Flags.enableDisplayFocusInShellTransitions;
import static com.android.window.flags.Flags.enablePresentationForConnectedDisplays;
import static com.android.window.flags.Flags.multiCrop;
import static com.android.window.flags.Flags.multiCrop;
import static com.android.window.flags.Flags.setScPropertiesInClient;
import static com.android.window.flags.Flags.setScPropertiesInClient;


@@ -503,6 +502,8 @@ public class WindowManagerService extends IWindowManager.Stub


    final StartingSurfaceController mStartingSurfaceController;
    final StartingSurfaceController mStartingSurfaceController;


    final PresentationController mPresentationController;

    private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
    private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
        @Override
        @Override
        public void onVrStateChanged(boolean enabled) {
        public void onVrStateChanged(boolean enabled) {
@@ -1419,6 +1420,7 @@ public class WindowManagerService extends IWindowManager.Stub
        setGlobalShadowSettings();
        setGlobalShadowSettings();
        mAnrController = new AnrController(this);
        mAnrController = new AnrController(this);
        mStartingSurfaceController = new StartingSurfaceController(this);
        mStartingSurfaceController = new StartingSurfaceController(this);
        mPresentationController = new PresentationController();


        mBlurController = new BlurController(mContext, mPowerManager);
        mBlurController = new BlurController(mContext, mPowerManager);
        mTaskFpsCallbackController = new TaskFpsCallbackController(mContext);
        mTaskFpsCallbackController = new TaskFpsCallbackController(mContext);
@@ -1923,16 +1925,8 @@ public class WindowManagerService extends IWindowManager.Stub
            }
            }
            outSizeCompatScale[0] = win.getCompatScaleForClient();
            outSizeCompatScale[0] = win.getCompatScaleForClient();


            if (res >= ADD_OKAY
            if (res >= ADD_OKAY && win.isPresentation()) {
                    && (type == TYPE_PRESENTATION || type == TYPE_PRIVATE_PRESENTATION)) {
                mPresentationController.onPresentationAdded(win);
                displayContent.mIsPresenting = true;
                if (enablePresentationForConnectedDisplays()) {
                    // A presentation hides all activities behind on the same display.
                    displayContent.ensureActivitiesVisible(/*starting=*/ null,
                            /*notifyClients=*/ true);
                }
                mDisplayManagerInternal.onPresentation(displayContent.getDisplay().getDisplayId(),
                        /*isShown=*/ true);
            }
            }
        }
        }


+6 −10
Original line number Original line Diff line number Diff line
@@ -182,7 +182,6 @@ import static com.android.server.wm.WindowStateProto.UNRESTRICTED_KEEP_CLEAR_ARE
import static com.android.server.wm.WindowStateProto.VIEW_VISIBILITY;
import static com.android.server.wm.WindowStateProto.VIEW_VISIBILITY;
import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER;
import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER;
import static com.android.server.wm.WindowStateProto.WINDOW_FRAMES;
import static com.android.server.wm.WindowStateProto.WINDOW_FRAMES;
import static com.android.window.flags.Flags.enablePresentationForConnectedDisplays;
import static com.android.window.flags.Flags.surfaceTrustedOverlay;
import static com.android.window.flags.Flags.surfaceTrustedOverlay;


import android.annotation.CallSuper;
import android.annotation.CallSuper;
@@ -2317,15 +2316,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP


        final int type = mAttrs.type;
        final int type = mAttrs.type;


        if (type == TYPE_PRESENTATION || type == TYPE_PRIVATE_PRESENTATION) {
        if (isPresentation()) {
            // TODO(b/393945496): Make sure that there's one presentation at most per display.
            mWmService.mPresentationController.onPresentationRemoved(this);
            dc.mIsPresenting = false;
            if (enablePresentationForConnectedDisplays()) {
                // A presentation hides all activities behind on the same display.
                dc.ensureActivitiesVisible(/*starting=*/ null, /*notifyClients=*/ true);
            }
            mWmService.mDisplayManagerInternal.onPresentation(dc.getDisplay().getDisplayId(),
                    /*isShown=*/ false);
        }
        }
        // Check if window provides non decor insets before clearing its provided insets.
        // Check if window provides non decor insets before clearing its provided insets.
        final boolean windowProvidesDisplayDecorInsets = providesDisplayDecorInsets();
        final boolean windowProvidesDisplayDecorInsets = providesDisplayDecorInsets();
@@ -3354,6 +3346,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        }
        }
    }
    }


    boolean isPresentation() {
        return mAttrs.type == TYPE_PRESENTATION || mAttrs.type == TYPE_PRIVATE_PRESENTATION;
    }

    private boolean isOnVirtualDisplay() {
    private boolean isOnVirtualDisplay() {
        return getDisplayContent().mDisplay.getType() == Display.TYPE_VIRTUAL;
        return getDisplayContent().mDisplay.getType() == Display.TYPE_VIRTUAL;
    }
    }
Loading