• 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 = mToken.attachToDisplayArea(type, displayId, options)
108                 ? AttachStatus.STATUS_ATTACHED : AttachStatus.STATUS_FAILED;
109         if (mAttachedToDisplayArea == AttachStatus.STATUS_FAILED) {
110             Log.w(TAG, "attachToDisplayArea fail, type:" + type + ", displayId:"
111                     + displayId);
112         } else if (DEBUG_ATTACH) {
113             Log.d(TAG, "attachToDisplayArea success, type:" + type + ", displayId:"
114                     + displayId);
115         }
116     }
117 
118     /**
119      * Switches to attach the window context to a window token.
120      * <p>
121      * Note that the context should have been attached to a
122      * {@link com.android.server.wm.DisplayArea} by {@link #attachToDisplayArea(int, int, Bundle)}
123      * before attaching to a window token, and the window token's type must match the window
124      * context's type.
125      * </p><p>
126      * A {@link WindowContext} can only attach to a specific window manager node, which is either a
127      * {@link com.android.server.wm.DisplayArea} by calling
128      * {@link #attachToDisplayArea(int, int, Bundle)} or the latest attached {@code windowToken}
129      * although this API is allowed to be called multiple times.
130      * </p>
131      * @throws IllegalStateException if the {@code mClientToken} has not yet attached to
132      * a {@link com.android.server.wm.DisplayArea} by
133      * {@link #attachToDisplayArea(int, int, Bundle)}.
134      *
135      * @see WindowProviderService#attachToWindowToken(IBinder))
136      * @see IWindowManager#attachWindowContextToWindowToken(IBinder, IBinder)
137      */
attachToWindowToken(IBinder windowToken)138     public void attachToWindowToken(IBinder windowToken) {
139         if (mAttachedToDisplayArea != AttachStatus.STATUS_ATTACHED) {
140             throw new IllegalStateException("The Window Context should have been attached"
141                     + " to a DisplayArea. AttachToDisplayArea:" + mAttachedToDisplayArea);
142         }
143         mToken.attachToWindowToken(windowToken);
144     }
145 
146     /** Detaches the window context from the node it's currently associated with. */
detachIfNeeded()147     public void detachIfNeeded() {
148         if (mAttachedToDisplayArea == AttachStatus.STATUS_ATTACHED) {
149             mToken.detachFromWindowContainerIfNeeded();
150             mAttachedToDisplayArea = AttachStatus.STATUS_DETACHED;
151             if (DEBUG_ATTACH) {
152                 Log.d(TAG, "Detach Window Context.");
153             }
154         }
155     }
156 }
157