• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static java.lang.annotation.RetentionPolicy.SOURCE;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.content.Context;
25 import android.os.Bundle;
26 import android.os.IBinder;
27 import android.util.Log;
28 import android.view.IWindowManager;
29 import android.view.WindowManager.LayoutParams.WindowType;
30 
31 import com.android.internal.annotations.VisibleForTesting;
32 
33 import java.lang.annotation.Retention;
34 
35 /**
36  * The controller to manage {@link WindowContext}, such as attaching to a window manager node or
37  * detaching from the current attached node. The user must call
38  * {@link #attachToDisplayArea(int, int, Bundle)}, call {@link #attachToWindowToken(IBinder)}
39  * after that if necessary, and then call {@link #detachIfNeeded()} for release.
40  *
41  * @hide
42  */
43 public class WindowContextController {
44     private static final boolean DEBUG_ATTACH = false;
45     private static final String TAG = "WindowContextController";
46 
47     /**
48      * {@link AttachStatus#STATUS_ATTACHED} to indicate that the {@code mToken} is associated with a
49      * {@link com.android.server.wm.DisplayArea}. Note that {@code mToken} is able to attach a
50      * WindowToken after this flag sets to {@link AttachStatus#STATUS_ATTACHED}.
51      */
52     @VisibleForTesting
53     public int mAttachedToDisplayArea = AttachStatus.STATUS_INITIALIZED;
54 
55     /**
56      * Status to indicate that the Window Context attach to a
57      * {@link com.android.server.wm.DisplayArea}.
58      */
59     @Retention(SOURCE)
60     @IntDef({AttachStatus.STATUS_INITIALIZED, AttachStatus.STATUS_ATTACHED,
61             AttachStatus.STATUS_DETACHED, AttachStatus.STATUS_FAILED})
62     public @interface AttachStatus{
63         /**
64          * The Window Context haven't attached to a {@link com.android.server.wm.DisplayArea}.
65          */
66         int STATUS_INITIALIZED = 0;
67         /**
68          * The Window Context has already attached to a {@link com.android.server.wm.DisplayArea}.
69          */
70         int STATUS_ATTACHED = 1;
71         /**
72          * The Window Context has detached from a {@link com.android.server.wm.DisplayArea}.
73          */
74         int STATUS_DETACHED = 2;
75         /**
76          * The Window Context fails to attach to a {@link com.android.server.wm.DisplayArea}.
77          */
78         int STATUS_FAILED = 3;
79     }
80     @NonNull
81     private final WindowTokenClient mToken;
82 
83     /**
84      * Window Context Controller constructor
85      *
86      * @param token The token used to attach to a window manager node. It is usually from
87      *              {@link Context#getWindowContextToken()}.
88      */
WindowContextController(@onNull WindowTokenClient token)89     public WindowContextController(@NonNull WindowTokenClient token) {
90         mToken = token;
91     }
92 
93     /**
94      * Attaches the {@code mToken} to a {@link com.android.server.wm.DisplayArea}.
95      *
96      * @param type The window type of the {@link WindowContext}
97      * @param displayId The {@link Context#getDisplayId() ID of display} to associate with
98      * @param options The window context launched option
99      * @throws IllegalStateException if the {@code mToken} has already been attached to a
100      * DisplayArea.
101      */
attachToDisplayArea(@indowType int type, int displayId, @Nullable Bundle options)102     public void attachToDisplayArea(@WindowType int type, int displayId, @Nullable Bundle options) {
103         if (mAttachedToDisplayArea == AttachStatus.STATUS_ATTACHED) {
104             throw new IllegalStateException("A Window Context can be only attached to "
105                     + "a DisplayArea once.");
106         }
107         mAttachedToDisplayArea = getWindowTokenClientController().attachToDisplayArea(
108                 mToken, type, displayId, options)
109                 ? AttachStatus.STATUS_ATTACHED : AttachStatus.STATUS_FAILED;
110         if (mAttachedToDisplayArea == AttachStatus.STATUS_FAILED) {
111             Log.w(TAG, "attachToDisplayArea fail, type:" + type + ", displayId:"
112                     + displayId);
113         } else if (DEBUG_ATTACH) {
114             Log.d(TAG, "attachToDisplayArea success, type:" + type + ", displayId:"
115                     + displayId);
116         }
117     }
118 
119     /**
120      * Switches to attach the window context to a window token.
121      * <p>
122      * Note that the context should have been attached to a
123      * {@link com.android.server.wm.DisplayArea} by {@link #attachToDisplayArea(int, int, Bundle)}
124      * before attaching to a window token, and the window token's type must match the window
125      * context's type.
126      * </p><p>
127      * A {@link WindowContext} can only attach to a specific window manager node, which is either a
128      * {@link com.android.server.wm.DisplayArea} by calling
129      * {@link #attachToDisplayArea(int, int, Bundle)} or the latest attached {@code windowToken}
130      * although this API is allowed to be called multiple times.
131      * </p>
132      * @throws IllegalStateException if the {@code mClientToken} has not yet attached to
133      * a {@link com.android.server.wm.DisplayArea} by
134      * {@link #attachToDisplayArea(int, int, Bundle)}.
135      *
136      * @see WindowProviderService#attachToWindowToken(IBinder))
137      * @see IWindowManager#attachWindowContextToWindowToken
138      */
attachToWindowToken(@onNull IBinder windowToken)139     public void attachToWindowToken(@NonNull IBinder windowToken) {
140         if (mAttachedToDisplayArea != AttachStatus.STATUS_ATTACHED) {
141             throw new IllegalStateException("The Window Context should have been attached"
142                     + " to a DisplayArea. AttachToDisplayArea:" + mAttachedToDisplayArea);
143         }
144         if (!getWindowTokenClientController().attachToWindowToken(mToken, windowToken)) {
145             Log.e(TAG, "attachToWindowToken fail");
146         }
147     }
148 
149     /** Detaches the window context from the node it's currently associated with. */
detachIfNeeded()150     public void detachIfNeeded() {
151         if (mAttachedToDisplayArea == AttachStatus.STATUS_ATTACHED) {
152             getWindowTokenClientController().detachIfNeeded(mToken);
153             mAttachedToDisplayArea = AttachStatus.STATUS_DETACHED;
154             if (DEBUG_ATTACH) {
155                 Log.d(TAG, "Detach Window Context.");
156             }
157         }
158     }
159 
160     /**
161      * Reparents the window context from the current attached display to another. {@code type} and
162      * {@code options} must be the same as the previous attach call, otherwise this will fail
163      * silently.
164      */
reparentToDisplayArea( @indowType int type, int displayId, @Nullable Bundle options)165     public void reparentToDisplayArea(
166             @WindowType int type, int displayId, @Nullable Bundle options) {
167         if (mAttachedToDisplayArea != AttachStatus.STATUS_ATTACHED) {
168             attachToDisplayArea(type, displayId, options);
169             return;
170         }
171         // No need to propagate type and options as this is already attached and they can't change.
172         getWindowTokenClientController().reparentToDisplayArea(mToken, displayId);
173     }
174 
175     /** Gets the {@link WindowTokenClientController}. */
176     @VisibleForTesting
177     @NonNull
getWindowTokenClientController()178     public WindowTokenClientController getWindowTokenClientController() {
179         return WindowTokenClientController.getInstance();
180     }
181 }
182