• 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.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
20 import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
21 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
22 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
23 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
24 import static android.window.WindowProviderService.isWindowProviderService;
25 
26 import android.annotation.CallbackExecutor;
27 import android.annotation.IntRange;
28 import android.annotation.NonNull;
29 import android.annotation.Nullable;
30 import android.annotation.UiContext;
31 import android.app.ResourcesManager;
32 import android.compat.annotation.UnsupportedAppUsage;
33 import android.content.Context;
34 import android.content.res.Configuration;
35 import android.graphics.Bitmap;
36 import android.graphics.Rect;
37 import android.graphics.Region;
38 import android.os.Bundle;
39 import android.os.IBinder;
40 import android.os.RemoteException;
41 import android.os.StrictMode;
42 import android.window.ITaskFpsCallback;
43 import android.window.TaskFpsCallback;
44 import android.window.WindowContext;
45 import android.window.WindowProvider;
46 
47 import com.android.internal.annotations.GuardedBy;
48 import com.android.internal.annotations.VisibleForTesting;
49 import com.android.internal.os.IResultReceiver;
50 
51 import java.util.ArrayList;
52 import java.util.HashSet;
53 import java.util.Iterator;
54 import java.util.List;
55 import java.util.Set;
56 import java.util.concurrent.Executor;
57 import java.util.function.Consumer;
58 
59 /**
60  * Provides low-level communication with the system window manager for
61  * operations that are bound to a particular context, display or parent window.
62  * Instances of this object are sensitive to the compatibility info associated
63  * with the running application.
64  *
65  * This object implements the {@link ViewManager} interface,
66  * allowing you to add any View subclass as a top-level window on the screen.
67  * Additional window manager specific layout parameters are defined for
68  * control over how windows are displayed.  It also implements the {@link WindowManager}
69  * interface, allowing you to control the displays attached to the device.
70  *
71  * <p>Applications will not normally use WindowManager directly, instead relying
72  * on the higher-level facilities in {@link android.app.Activity} and
73  * {@link android.app.Dialog}.
74  *
75  * <p>Even for low-level window manager access, it is almost never correct to use
76  * this class.  For example, {@link android.app.Activity#getWindowManager}
77  * provides a window manager for adding windows that are associated with that
78  * activity -- the window manager will not normally allow you to add arbitrary
79  * windows that are not associated with an activity.
80  *
81  * @see WindowManager
82  * @see WindowManagerGlobal
83  * @hide
84  */
85 public final class WindowManagerImpl implements WindowManager {
86     @UnsupportedAppUsage
87     private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
88     @UiContext
89     @VisibleForTesting
90     public final Context mContext;
91     private final Window mParentWindow;
92 
93     /**
94      * If {@link LayoutParams#token} is {@code null} and no parent window is specified, the value
95      * of {@link LayoutParams#token} will be overridden to {@code mDefaultToken}.
96      */
97     private IBinder mDefaultToken;
98 
99     /**
100      * This token will be set to {@link LayoutParams#mWindowContextToken} and used to receive
101      * configuration changes from the server side.
102      */
103     @Nullable
104     private final IBinder mWindowContextToken;
105 
106     @GuardedBy("mOnFpsCallbackListenerProxies")
107     private final ArrayList<OnFpsCallbackListenerProxy> mOnFpsCallbackListenerProxies =
108             new ArrayList<>();
109 
WindowManagerImpl(Context context)110     public WindowManagerImpl(Context context) {
111         this(context, null /* parentWindow */, null /* clientToken */);
112     }
113 
WindowManagerImpl(Context context, Window parentWindow, @Nullable IBinder windowContextToken)114     private WindowManagerImpl(Context context, Window parentWindow,
115             @Nullable IBinder windowContextToken) {
116         mContext = context;
117         mParentWindow = parentWindow;
118         mWindowContextToken = windowContextToken;
119     }
120 
createLocalWindowManager(Window parentWindow)121     public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
122         return new WindowManagerImpl(mContext, parentWindow, mWindowContextToken);
123     }
124 
createPresentationWindowManager(Context displayContext)125     public WindowManagerImpl createPresentationWindowManager(Context displayContext) {
126         return new WindowManagerImpl(displayContext, mParentWindow, mWindowContextToken);
127     }
128 
129     /** Creates a {@link WindowManager} for a {@link WindowContext}. */
createWindowContextWindowManager(Context context)130     public static WindowManager createWindowContextWindowManager(Context context) {
131         final IBinder clientToken = context.getWindowContextToken();
132         return new WindowManagerImpl(context, null /* parentWindow */, clientToken);
133     }
134 
135     /**
136      * Sets the window token to assign when none is specified by the client or
137      * available from the parent window.
138      *
139      * @param token The default token to assign.
140      */
setDefaultToken(IBinder token)141     public void setDefaultToken(IBinder token) {
142         mDefaultToken = token;
143     }
144 
145     @Override
addView(@onNull View view, @NonNull ViewGroup.LayoutParams params)146     public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
147         applyTokens(params);
148         mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
149                 mContext.getUserId());
150     }
151 
152     @Override
updateViewLayout(@onNull View view, @NonNull ViewGroup.LayoutParams params)153     public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
154         applyTokens(params);
155         mGlobal.updateViewLayout(view, params);
156     }
157 
applyTokens(@onNull ViewGroup.LayoutParams params)158     private void applyTokens(@NonNull ViewGroup.LayoutParams params) {
159         if (!(params instanceof WindowManager.LayoutParams)) {
160             throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
161         }
162         final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
163         assertWindowContextTypeMatches(wparams.type);
164         // Only use the default token if we don't have a parent window and a token.
165         if (mDefaultToken != null && mParentWindow == null && wparams.token == null) {
166             wparams.token = mDefaultToken;
167         }
168         wparams.mWindowContextToken = mWindowContextToken;
169     }
170 
assertWindowContextTypeMatches(@ayoutParams.WindowType int windowType)171     private void assertWindowContextTypeMatches(@LayoutParams.WindowType int windowType) {
172         if (!(mContext instanceof WindowProvider)) {
173             return;
174         }
175         // Don't need to check sub-window type because sub window should be allowed to be attached
176         // to the parent window.
177         if (windowType >= FIRST_SUB_WINDOW && windowType <= LAST_SUB_WINDOW) {
178             return;
179         }
180         final WindowProvider windowProvider = (WindowProvider) mContext;
181         if (windowProvider.getWindowType() == windowType) {
182             return;
183         }
184         IllegalArgumentException exception = new IllegalArgumentException("Window type mismatch."
185                 + " Window Context's window type is " + windowProvider.getWindowType()
186                 + ", while LayoutParams' type is set to " + windowType + "."
187                 + " Please create another Window Context via"
188                 + " createWindowContext(getDisplay(), " + windowType + ", null)"
189                 + " to add window with type:" + windowType);
190         if (!isWindowProviderService(windowProvider.getWindowContextOptions())) {
191             throw exception;
192         }
193         // Throw IncorrectCorrectViolation if the Window Context is allowed to provide multiple
194         // window types. Usually it's because the Window Context is a WindowProviderService.
195         StrictMode.onIncorrectContextUsed("WindowContext's window type must"
196                 + " match type in WindowManager.LayoutParams", exception);
197     }
198 
199     @Override
removeView(View view)200     public void removeView(View view) {
201         mGlobal.removeView(view, false);
202     }
203 
204     @Override
removeViewImmediate(View view)205     public void removeViewImmediate(View view) {
206         mGlobal.removeView(view, true);
207     }
208 
209     @Override
requestAppKeyboardShortcuts( final KeyboardShortcutsReceiver receiver, int deviceId)210     public void requestAppKeyboardShortcuts(
211             final KeyboardShortcutsReceiver receiver, int deviceId) {
212         IResultReceiver resultReceiver = new IResultReceiver.Stub() {
213             @Override
214             public void send(int resultCode, Bundle resultData) throws RemoteException {
215                 List<KeyboardShortcutGroup> result =
216                         resultData.getParcelableArrayList(PARCEL_KEY_SHORTCUTS_ARRAY);
217                 receiver.onKeyboardShortcutsReceived(result);
218             }
219         };
220         try {
221             WindowManagerGlobal.getWindowManagerService()
222                 .requestAppKeyboardShortcuts(resultReceiver, deviceId);
223         } catch (RemoteException e) {
224         }
225     }
226 
227     @Override
getDefaultDisplay()228     public Display getDefaultDisplay() {
229         return mContext.getDisplayNoVerify();
230     }
231 
232     @Override
getCurrentImeTouchRegion()233     public Region getCurrentImeTouchRegion() {
234         try {
235             return WindowManagerGlobal.getWindowManagerService().getCurrentImeTouchRegion();
236         } catch (RemoteException e) {
237         }
238         return null;
239     }
240 
241     @Override
setShouldShowWithInsecureKeyguard(int displayId, boolean shouldShow)242     public void setShouldShowWithInsecureKeyguard(int displayId, boolean shouldShow) {
243         try {
244             WindowManagerGlobal.getWindowManagerService()
245                     .setShouldShowWithInsecureKeyguard(displayId, shouldShow);
246         } catch (RemoteException e) {
247         }
248     }
249 
250     @Override
setShouldShowSystemDecors(int displayId, boolean shouldShow)251     public void setShouldShowSystemDecors(int displayId, boolean shouldShow) {
252         try {
253             WindowManagerGlobal.getWindowManagerService()
254                     .setShouldShowSystemDecors(displayId, shouldShow);
255         } catch (RemoteException e) {
256         }
257     }
258 
259     @Override
shouldShowSystemDecors(int displayId)260     public boolean shouldShowSystemDecors(int displayId) {
261         try {
262             return WindowManagerGlobal.getWindowManagerService().shouldShowSystemDecors(displayId);
263         } catch (RemoteException e) {
264         }
265         return false;
266     }
267 
268     @Override
setDisplayImePolicy(int displayId, @DisplayImePolicy int imePolicy)269     public void setDisplayImePolicy(int displayId, @DisplayImePolicy int imePolicy) {
270         try {
271             WindowManagerGlobal.getWindowManagerService().setDisplayImePolicy(displayId, imePolicy);
272         } catch (RemoteException e) {
273         }
274     }
275 
276     @Override
getDisplayImePolicy(int displayId)277     public @DisplayImePolicy int getDisplayImePolicy(int displayId) {
278         try {
279             return WindowManagerGlobal.getWindowManagerService().getDisplayImePolicy(displayId);
280         } catch (RemoteException e) {
281         }
282         return DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
283     }
284 
285     @Override
getCurrentWindowMetrics()286     public WindowMetrics getCurrentWindowMetrics() {
287         final Context context = mParentWindow != null ? mParentWindow.getContext() : mContext;
288         final Rect bounds = getCurrentBounds(context);
289 
290         return new WindowMetrics(bounds, computeWindowInsets(bounds));
291     }
292 
getCurrentBounds(Context context)293     private static Rect getCurrentBounds(Context context) {
294         synchronized (ResourcesManager.getInstance()) {
295             return context.getResources().getConfiguration().windowConfiguration.getBounds();
296         }
297     }
298 
299     @Override
getMaximumWindowMetrics()300     public WindowMetrics getMaximumWindowMetrics() {
301         final Context context = mParentWindow != null ? mParentWindow.getContext() : mContext;
302         final Rect maxBounds = getMaximumBounds(context);
303 
304         return new WindowMetrics(maxBounds, computeWindowInsets(maxBounds));
305     }
306 
getMaximumBounds(Context context)307     private static Rect getMaximumBounds(Context context) {
308         synchronized (ResourcesManager.getInstance()) {
309             return context.getResources().getConfiguration().windowConfiguration.getMaxBounds();
310         }
311     }
312 
computeWindowInsets(Rect bounds)313     private WindowInsets computeWindowInsets(Rect bounds) {
314         // Initialize params which used for obtaining all system insets.
315         final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
316         final Context context = (mParentWindow != null) ? mParentWindow.getContext() : mContext;
317         params.token = Context.getToken(context);
318         return getWindowInsetsFromServerForCurrentDisplay(params, bounds);
319     }
320 
getWindowInsetsFromServerForCurrentDisplay( WindowManager.LayoutParams attrs, Rect bounds)321     private WindowInsets getWindowInsetsFromServerForCurrentDisplay(
322             WindowManager.LayoutParams attrs, Rect bounds) {
323         final Configuration config = mContext.getResources().getConfiguration();
324         return getWindowInsetsFromServerForDisplay(mContext.getDisplayId(), attrs, bounds,
325                 config.isScreenRound(), config.windowConfiguration.getWindowingMode());
326     }
327 
328     /**
329      * Retrieves WindowInsets for the given context and display, given the window bounds.
330      *
331      * @param displayId the ID of the logical display to calculate insets for
332      * @param attrs the LayoutParams for the calling app
333      * @param bounds the window bounds to calculate insets for
334      * @param isScreenRound if the display identified by displayId is round
335      * @param windowingMode the windowing mode of the window to calculate insets for
336      * @return WindowInsets calculated for the given window bounds, on the given display
337      */
getWindowInsetsFromServerForDisplay(int displayId, WindowManager.LayoutParams attrs, Rect bounds, boolean isScreenRound, int windowingMode)338     private static WindowInsets getWindowInsetsFromServerForDisplay(int displayId,
339             WindowManager.LayoutParams attrs, Rect bounds, boolean isScreenRound,
340             int windowingMode) {
341         try {
342             final InsetsState insetsState = new InsetsState();
343             final boolean alwaysConsumeSystemBars = WindowManagerGlobal.getWindowManagerService()
344                     .getWindowInsets(attrs, displayId, insetsState);
345             return insetsState.calculateInsets(bounds, null /* ignoringVisibilityState*/,
346                     isScreenRound, alwaysConsumeSystemBars, SOFT_INPUT_ADJUST_NOTHING, attrs.flags,
347                     SYSTEM_UI_FLAG_VISIBLE, attrs.type, windowingMode,
348                     null /* typeSideMap */);
349         } catch (RemoteException e) {
350             throw e.rethrowFromSystemServer();
351         }
352     }
353 
354     @Override
355     @NonNull
getPossibleMaximumWindowMetrics(int displayId)356     public Set<WindowMetrics> getPossibleMaximumWindowMetrics(int displayId) {
357         List<DisplayInfo> possibleDisplayInfos;
358         try {
359             possibleDisplayInfos = WindowManagerGlobal.getWindowManagerService()
360                     .getPossibleDisplayInfo(displayId);
361         } catch (RemoteException e) {
362             throw e.rethrowFromSystemServer();
363         }
364 
365         Set<WindowMetrics> maxMetrics = new HashSet<>();
366         WindowInsets windowInsets;
367         DisplayInfo currentDisplayInfo;
368         final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
369         for (int i = 0; i < possibleDisplayInfos.size(); i++) {
370             currentDisplayInfo = possibleDisplayInfos.get(i);
371 
372             // Calculate max bounds for this rotation and state.
373             Rect maxBounds = new Rect(0, 0, currentDisplayInfo.logicalWidth,
374                     currentDisplayInfo.logicalHeight);
375 
376             // Calculate insets for the rotated max bounds.
377             final boolean isScreenRound = (currentDisplayInfo.flags & Display.FLAG_ROUND) != 0;
378             // Initialize insets based upon display rotation. Note any window-provided insets
379             // will not be set.
380             windowInsets = getWindowInsetsFromServerForDisplay(
381                     currentDisplayInfo.displayId, params,
382                     new Rect(0, 0, currentDisplayInfo.getNaturalWidth(),
383                             currentDisplayInfo.getNaturalHeight()), isScreenRound,
384                     WINDOWING_MODE_FULLSCREEN);
385             // Set the hardware-provided insets.
386             windowInsets = new WindowInsets.Builder(windowInsets).setRoundedCorners(
387                     currentDisplayInfo.roundedCorners)
388                     .setDisplayCutout(currentDisplayInfo.displayCutout).build();
389 
390             maxMetrics.add(new WindowMetrics(maxBounds, windowInsets));
391         }
392         return maxMetrics;
393     }
394 
395     @Override
holdLock(IBinder token, int durationMs)396     public void holdLock(IBinder token, int durationMs) {
397         try {
398             WindowManagerGlobal.getWindowManagerService().holdLock(token, durationMs);
399         } catch (RemoteException e) {
400             throw e.rethrowFromSystemServer();
401         }
402     }
403 
404     @Override
isCrossWindowBlurEnabled()405     public boolean isCrossWindowBlurEnabled() {
406         return CrossWindowBlurListeners.getInstance().isCrossWindowBlurEnabled();
407     }
408 
409     @Override
addCrossWindowBlurEnabledListener(@onNull Consumer<Boolean> listener)410     public void addCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
411         addCrossWindowBlurEnabledListener(mContext.getMainExecutor(), listener);
412     }
413 
414     @Override
addCrossWindowBlurEnabledListener(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> listener)415     public void addCrossWindowBlurEnabledListener(@NonNull @CallbackExecutor Executor executor,
416             @NonNull Consumer<Boolean> listener) {
417         CrossWindowBlurListeners.getInstance().addListener(executor, listener);
418     }
419 
420     @Override
removeCrossWindowBlurEnabledListener(@onNull Consumer<Boolean> listener)421     public void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
422         CrossWindowBlurListeners.getInstance().removeListener(listener);
423     }
424 
425     @Override
isTaskSnapshotSupported()426     public boolean isTaskSnapshotSupported() {
427         try {
428             return WindowManagerGlobal.getWindowManagerService().isTaskSnapshotSupported();
429         } catch (RemoteException e) {
430         }
431         return false;
432     }
433 
434     @Override
registerTaskFpsCallback(@ntRangefrom = 0) int taskId, @NonNull Executor executor, TaskFpsCallback callback)435     public void registerTaskFpsCallback(@IntRange(from = 0) int taskId, @NonNull Executor executor,
436             TaskFpsCallback callback) {
437         final OnFpsCallbackListenerProxy onFpsCallbackListenerProxy =
438                 new OnFpsCallbackListenerProxy(executor, callback);
439         try {
440             WindowManagerGlobal.getWindowManagerService().registerTaskFpsCallback(
441                     taskId, onFpsCallbackListenerProxy);
442         } catch (RemoteException e) {
443             throw e.rethrowFromSystemServer();
444         }
445         synchronized (mOnFpsCallbackListenerProxies) {
446             mOnFpsCallbackListenerProxies.add(onFpsCallbackListenerProxy);
447         }
448     }
449 
450     @Override
unregisterTaskFpsCallback(TaskFpsCallback callback)451     public void unregisterTaskFpsCallback(TaskFpsCallback callback) {
452         synchronized (mOnFpsCallbackListenerProxies) {
453             final Iterator<OnFpsCallbackListenerProxy> iterator =
454                     mOnFpsCallbackListenerProxies.iterator();
455             while (iterator.hasNext()) {
456                 final OnFpsCallbackListenerProxy proxy = iterator.next();
457                 if (proxy.mCallback == callback) {
458                     try {
459                         WindowManagerGlobal.getWindowManagerService()
460                                 .unregisterTaskFpsCallback(proxy);
461                     } catch (RemoteException e) {
462                         throw e.rethrowFromSystemServer();
463                     }
464                     iterator.remove();
465                 }
466             }
467         }
468     }
469 
470     private static class OnFpsCallbackListenerProxy
471             extends ITaskFpsCallback.Stub {
472         private final Executor mExecutor;
473         private final TaskFpsCallback mCallback;
474 
OnFpsCallbackListenerProxy(Executor executor, TaskFpsCallback callback)475         private OnFpsCallbackListenerProxy(Executor executor, TaskFpsCallback callback) {
476             mExecutor = executor;
477             mCallback = callback;
478         }
479 
480         @Override
onFpsReported(float fps)481         public void onFpsReported(float fps) {
482             mExecutor.execute(() -> {
483                 mCallback.onFpsReported(fps);
484             });
485         }
486     }
487 
488     @Override
snapshotTaskForRecents(int taskId)489     public Bitmap snapshotTaskForRecents(int taskId) {
490         try {
491             return WindowManagerGlobal.getWindowManagerService().snapshotTaskForRecents(taskId);
492         } catch (RemoteException e) {
493             e.rethrowAsRuntimeException();
494         }
495         return null;
496     }
497 }
498