• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 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.view;
18 
19 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
20 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
21 import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
22 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
23 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
24 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
25 
26 import android.annotation.CallbackExecutor;
27 import android.annotation.NonNull;
28 import android.annotation.Nullable;
29 import android.annotation.UiContext;
30 import android.app.ResourcesManager;
31 import android.compat.annotation.UnsupportedAppUsage;
32 import android.content.Context;
33 import android.content.res.Configuration;
34 import android.graphics.Rect;
35 import android.graphics.Region;
36 import android.os.Bundle;
37 import android.os.IBinder;
38 import android.os.RemoteException;
39 import android.window.WindowContext;
40 
41 import com.android.internal.annotations.VisibleForTesting;
42 import com.android.internal.os.IResultReceiver;
43 
44 import java.util.List;
45 import java.util.concurrent.Executor;
46 import java.util.function.Consumer;
47 
48 /**
49  * Provides low-level communication with the system window manager for
50  * operations that are bound to a particular context, display or parent window.
51  * Instances of this object are sensitive to the compatibility info associated
52  * with the running application.
53  *
54  * This object implements the {@link ViewManager} interface,
55  * allowing you to add any View subclass as a top-level window on the screen.
56  * Additional window manager specific layout parameters are defined for
57  * control over how windows are displayed.  It also implements the {@link WindowManager}
58  * interface, allowing you to control the displays attached to the device.
59  *
60  * <p>Applications will not normally use WindowManager directly, instead relying
61  * on the higher-level facilities in {@link android.app.Activity} and
62  * {@link android.app.Dialog}.
63  *
64  * <p>Even for low-level window manager access, it is almost never correct to use
65  * this class.  For example, {@link android.app.Activity#getWindowManager}
66  * provides a window manager for adding windows that are associated with that
67  * activity -- the window manager will not normally allow you to add arbitrary
68  * windows that are not associated with an activity.
69  *
70  * @see WindowManager
71  * @see WindowManagerGlobal
72  * @hide
73  */
74 public final class WindowManagerImpl implements WindowManager {
75     @UnsupportedAppUsage
76     private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
77     @UiContext
78     @VisibleForTesting
79     public final Context mContext;
80     private final Window mParentWindow;
81 
82     /**
83      * If {@link LayoutParams#token} is {@code null} and no parent window is specified, the value
84      * of {@link LayoutParams#token} will be overridden to {@code mDefaultToken}.
85      */
86     private IBinder mDefaultToken;
87 
88     /**
89      * This token will be set to {@link LayoutParams#mWindowContextToken} and used to receive
90      * configuration changes from the server side.
91      */
92     @Nullable
93     private final IBinder mWindowContextToken;
94 
WindowManagerImpl(Context context)95     public WindowManagerImpl(Context context) {
96         this(context, null /* parentWindow */, null /* clientToken */);
97     }
98 
WindowManagerImpl(Context context, Window parentWindow, @Nullable IBinder windowContextToken)99     private WindowManagerImpl(Context context, Window parentWindow,
100             @Nullable IBinder windowContextToken) {
101         mContext = context;
102         mParentWindow = parentWindow;
103         mWindowContextToken = windowContextToken;
104     }
105 
createLocalWindowManager(Window parentWindow)106     public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
107         return new WindowManagerImpl(mContext, parentWindow, mWindowContextToken);
108     }
109 
createPresentationWindowManager(Context displayContext)110     public WindowManagerImpl createPresentationWindowManager(Context displayContext) {
111         return new WindowManagerImpl(displayContext, mParentWindow, mWindowContextToken);
112     }
113 
114     /** Creates a {@link WindowManager} for a {@link WindowContext}. */
createWindowContextWindowManager(Context context)115     public static WindowManager createWindowContextWindowManager(Context context) {
116         final IBinder clientToken = context.getWindowContextToken();
117         return new WindowManagerImpl(context, null /* parentWindow */, clientToken);
118     }
119 
120     /**
121      * Sets the window token to assign when none is specified by the client or
122      * available from the parent window.
123      *
124      * @param token The default token to assign.
125      */
setDefaultToken(IBinder token)126     public void setDefaultToken(IBinder token) {
127         mDefaultToken = token;
128     }
129 
130     @Override
addView(@onNull View view, @NonNull ViewGroup.LayoutParams params)131     public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
132         applyTokens(params);
133         mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
134                 mContext.getUserId());
135     }
136 
137     @Override
updateViewLayout(@onNull View view, @NonNull ViewGroup.LayoutParams params)138     public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
139         applyTokens(params);
140         mGlobal.updateViewLayout(view, params);
141     }
142 
applyTokens(@onNull ViewGroup.LayoutParams params)143     private void applyTokens(@NonNull ViewGroup.LayoutParams params) {
144         if (!(params instanceof WindowManager.LayoutParams)) {
145             throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
146         }
147         final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
148         // Only use the default token if we don't have a parent window and a token.
149         if (mDefaultToken != null && mParentWindow == null && wparams.token == null) {
150             wparams.token = mDefaultToken;
151         }
152         wparams.mWindowContextToken = mWindowContextToken;
153     }
154 
155     @Override
removeView(View view)156     public void removeView(View view) {
157         mGlobal.removeView(view, false);
158     }
159 
160     @Override
removeViewImmediate(View view)161     public void removeViewImmediate(View view) {
162         mGlobal.removeView(view, true);
163     }
164 
165     @Override
requestAppKeyboardShortcuts( final KeyboardShortcutsReceiver receiver, int deviceId)166     public void requestAppKeyboardShortcuts(
167             final KeyboardShortcutsReceiver receiver, int deviceId) {
168         IResultReceiver resultReceiver = new IResultReceiver.Stub() {
169             @Override
170             public void send(int resultCode, Bundle resultData) throws RemoteException {
171                 List<KeyboardShortcutGroup> result =
172                         resultData.getParcelableArrayList(PARCEL_KEY_SHORTCUTS_ARRAY);
173                 receiver.onKeyboardShortcutsReceived(result);
174             }
175         };
176         try {
177             WindowManagerGlobal.getWindowManagerService()
178                 .requestAppKeyboardShortcuts(resultReceiver, deviceId);
179         } catch (RemoteException e) {
180         }
181     }
182 
183     @Override
getDefaultDisplay()184     public Display getDefaultDisplay() {
185         return mContext.getDisplayNoVerify();
186     }
187 
188     @Override
getCurrentImeTouchRegion()189     public Region getCurrentImeTouchRegion() {
190         try {
191             return WindowManagerGlobal.getWindowManagerService().getCurrentImeTouchRegion();
192         } catch (RemoteException e) {
193         }
194         return null;
195     }
196 
197     @Override
setShouldShowWithInsecureKeyguard(int displayId, boolean shouldShow)198     public void setShouldShowWithInsecureKeyguard(int displayId, boolean shouldShow) {
199         try {
200             WindowManagerGlobal.getWindowManagerService()
201                     .setShouldShowWithInsecureKeyguard(displayId, shouldShow);
202         } catch (RemoteException e) {
203         }
204     }
205 
206     @Override
setShouldShowSystemDecors(int displayId, boolean shouldShow)207     public void setShouldShowSystemDecors(int displayId, boolean shouldShow) {
208         try {
209             WindowManagerGlobal.getWindowManagerService()
210                     .setShouldShowSystemDecors(displayId, shouldShow);
211         } catch (RemoteException e) {
212         }
213     }
214 
215     @Override
shouldShowSystemDecors(int displayId)216     public boolean shouldShowSystemDecors(int displayId) {
217         try {
218             return WindowManagerGlobal.getWindowManagerService().shouldShowSystemDecors(displayId);
219         } catch (RemoteException e) {
220         }
221         return false;
222     }
223 
224     @Override
setDisplayImePolicy(int displayId, @DisplayImePolicy int imePolicy)225     public void setDisplayImePolicy(int displayId, @DisplayImePolicy int imePolicy) {
226         try {
227             WindowManagerGlobal.getWindowManagerService().setDisplayImePolicy(displayId, imePolicy);
228         } catch (RemoteException e) {
229         }
230     }
231 
232     @Override
getDisplayImePolicy(int displayId)233     public @DisplayImePolicy int getDisplayImePolicy(int displayId) {
234         try {
235             return WindowManagerGlobal.getWindowManagerService().getDisplayImePolicy(displayId);
236         } catch (RemoteException e) {
237         }
238         return DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
239     }
240 
241     @Override
getCurrentWindowMetrics()242     public WindowMetrics getCurrentWindowMetrics() {
243         final Context context = mParentWindow != null ? mParentWindow.getContext() : mContext;
244         final Rect bounds = getCurrentBounds(context);
245 
246         return new WindowMetrics(bounds, computeWindowInsets(bounds));
247     }
248 
getCurrentBounds(Context context)249     private static Rect getCurrentBounds(Context context) {
250         synchronized (ResourcesManager.getInstance()) {
251             return context.getResources().getConfiguration().windowConfiguration.getBounds();
252         }
253     }
254 
255     @Override
getMaximumWindowMetrics()256     public WindowMetrics getMaximumWindowMetrics() {
257         final Context context = mParentWindow != null ? mParentWindow.getContext() : mContext;
258         final Rect maxBounds = getMaximumBounds(context);
259 
260         return new WindowMetrics(maxBounds, computeWindowInsets(maxBounds));
261     }
262 
getMaximumBounds(Context context)263     private static Rect getMaximumBounds(Context context) {
264         synchronized (ResourcesManager.getInstance()) {
265             return context.getResources().getConfiguration().windowConfiguration.getMaxBounds();
266         }
267     }
268 
269     // TODO(b/150095967): Set window type to LayoutParams
computeWindowInsets(Rect bounds)270     private WindowInsets computeWindowInsets(Rect bounds) {
271         // Initialize params which used for obtaining all system insets.
272         final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
273         params.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
274         final Context context = (mParentWindow != null) ? mParentWindow.getContext() : mContext;
275         params.token = Context.getToken(context);
276         params.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
277                 | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
278         params.setFitInsetsTypes(0);
279         params.setFitInsetsSides(0);
280 
281         return getWindowInsetsFromServer(params, bounds);
282     }
283 
getWindowInsetsFromServer(WindowManager.LayoutParams attrs, Rect bounds)284     private WindowInsets getWindowInsetsFromServer(WindowManager.LayoutParams attrs, Rect bounds) {
285         try {
286             final InsetsState insetsState = new InsetsState();
287             final boolean alwaysConsumeSystemBars = WindowManagerGlobal.getWindowManagerService()
288                     .getWindowInsets(attrs, mContext.getDisplayId(), insetsState);
289             final Configuration config = mContext.getResources().getConfiguration();
290             final boolean isScreenRound = config.isScreenRound();
291             final int windowingMode = config.windowConfiguration.getWindowingMode();
292             return insetsState.calculateInsets(bounds, null /* ignoringVisibilityState*/,
293                     isScreenRound, alwaysConsumeSystemBars, SOFT_INPUT_ADJUST_NOTHING, attrs.flags,
294                     SYSTEM_UI_FLAG_VISIBLE, attrs.type, windowingMode, null /* typeSideMap */);
295         } catch (RemoteException e) {
296             throw e.rethrowFromSystemServer();
297         }
298     }
299 
300     @Override
holdLock(IBinder token, int durationMs)301     public void holdLock(IBinder token, int durationMs) {
302         try {
303             WindowManagerGlobal.getWindowManagerService().holdLock(token, durationMs);
304         } catch (RemoteException e) {
305             throw e.rethrowFromSystemServer();
306         }
307     }
308 
309     @Override
isCrossWindowBlurEnabled()310     public boolean isCrossWindowBlurEnabled() {
311         return CrossWindowBlurListeners.getInstance().isCrossWindowBlurEnabled();
312     }
313 
314     @Override
addCrossWindowBlurEnabledListener(@onNull Consumer<Boolean> listener)315     public void addCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
316         addCrossWindowBlurEnabledListener(mContext.getMainExecutor(), listener);
317     }
318 
319     @Override
addCrossWindowBlurEnabledListener(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> listener)320     public void addCrossWindowBlurEnabledListener(@NonNull @CallbackExecutor Executor executor,
321             @NonNull Consumer<Boolean> listener) {
322         CrossWindowBlurListeners.getInstance().addListener(executor, listener);
323     }
324 
325     @Override
removeCrossWindowBlurEnabledListener(@onNull Consumer<Boolean> listener)326     public void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
327         CrossWindowBlurListeners.getInstance().removeListener(listener);
328     }
329 
330     @Override
isTaskSnapshotSupported()331     public boolean isTaskSnapshotSupported() {
332         try {
333             return WindowManagerGlobal.getWindowManagerService().isTaskSnapshotSupported();
334         } catch (RemoteException e) {
335         }
336         return false;
337     }
338 }
339