1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.window;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.Context;
22 import android.os.Bundle;
23 import android.os.IBinder;
24 import android.view.IWindowManager;
25 import android.view.WindowManager.LayoutParams.WindowType;
26 
27 import com.android.internal.annotations.VisibleForTesting;
28 
29 /**
30  * The controller to manage {@link WindowContext}, such as attaching to a window manager node or
31  * detaching from the current attached node. The user must call
32  * {@link #attachToDisplayArea(int, int, Bundle)}, call {@link #attachToWindowToken(IBinder)}
33  * after that if necessary, and then call {@link #detachIfNeeded()} for release.
34  *
35  * @hide
36  */
37 public class WindowContextController {
38     /**
39      * {@code true} to indicate that the {@code mToken} is associated with a
40      * {@link com.android.server.wm.DisplayArea}. Note that {@code mToken} is able to attach a
41      * WindowToken after this flag sets to {@code true}.
42      */
43     @VisibleForTesting
44     public boolean mAttachedToDisplayArea;
45     @NonNull
46     private final WindowTokenClient mToken;
47 
48     /**
49      * Window Context Controller constructor
50      *
51      * @param token The token used to attach to a window manager node. It is usually from
52      *              {@link Context#getWindowContextToken()}.
53      */
WindowContextController(@onNull WindowTokenClient token)54     public WindowContextController(@NonNull WindowTokenClient token) {
55         mToken = token;
56     }
57 
58     /**
59      * Attaches the {@code mToken} to a {@link com.android.server.wm.DisplayArea}.
60      *
61      * @param type The window type of the {@link WindowContext}
62      * @param displayId The {@link Context#getDisplayId() ID of display} to associate with
63      * @param options The window context launched option
64      * @throws IllegalStateException if the {@code mToken} has already been attached to a
65      * DisplayArea.
66      */
attachToDisplayArea(@indowType int type, int displayId, @Nullable Bundle options)67     public void attachToDisplayArea(@WindowType int type, int displayId, @Nullable Bundle options) {
68         if (mAttachedToDisplayArea) {
69             throw new IllegalStateException("A Window Context can be only attached to "
70                     + "a DisplayArea once.");
71         }
72         mAttachedToDisplayArea = mToken.attachToDisplayArea(type, displayId, options);
73     }
74 
75     /**
76      * Switches to attach the window context to a window token.
77      * <p>
78      * Note that the context should have been attached to a
79      * {@link com.android.server.wm.DisplayArea} by {@link #attachToDisplayArea(int, int, Bundle)}
80      * before attaching to a window token, and the window token's type must match the window
81      * context's type.
82      * </p><p>
83      * A {@link WindowContext} can only attach to a specific window manager node, which is either a
84      * {@link com.android.server.wm.DisplayArea} by calling
85      * {@link #attachToDisplayArea(int, int, Bundle)} or the latest attached {@code windowToken}
86      * although this API is allowed to be called multiple times.
87      * </p>
88      * @throws IllegalStateException if the {@code mClientToken} has not yet attached to
89      * a {@link com.android.server.wm.DisplayArea} by
90      * {@link #attachToDisplayArea(int, int, Bundle)}.
91      *
92      * @see WindowProviderService#attachToWindowToken(IBinder))
93      * @see IWindowManager#attachWindowContextToWindowToken(IBinder, IBinder)
94      */
attachToWindowToken(IBinder windowToken)95     public void attachToWindowToken(IBinder windowToken) {
96         if (!mAttachedToDisplayArea) {
97             throw new IllegalStateException("The Window Context should have been attached"
98                     + " to a DisplayArea.");
99         }
100         mToken.attachToWindowToken(windowToken);
101     }
102 
103     /** Detaches the window context from the node it's currently associated with. */
detachIfNeeded()104     public void detachIfNeeded() {
105         if (mAttachedToDisplayArea) {
106             mToken.detachFromWindowContainerIfNeeded();
107             mAttachedToDisplayArea = false;
108         }
109     }
110 }
111