| /* |
| * Copyright (C) 2006 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.view; |
| |
| import android.annotation.NonNull; |
| import android.app.ResourcesManager; |
| import android.compat.annotation.UnsupportedAppUsage; |
| import android.content.Context; |
| import android.graphics.Insets; |
| import android.graphics.Point; |
| import android.graphics.Rect; |
| import android.graphics.Region; |
| import android.os.Bundle; |
| import android.os.IBinder; |
| import android.os.RemoteException; |
| import android.util.Size; |
| |
| import com.android.internal.os.IResultReceiver; |
| |
| import java.util.List; |
| |
| /** |
| * Provides low-level communication with the system window manager for |
| * operations that are bound to a particular context, display or parent window. |
| * Instances of this object are sensitive to the compatibility info associated |
| * with the running application. |
| * |
| * This object implements the {@link ViewManager} interface, |
| * allowing you to add any View subclass as a top-level window on the screen. |
| * Additional window manager specific layout parameters are defined for |
| * control over how windows are displayed. It also implements the {@link WindowManager} |
| * interface, allowing you to control the displays attached to the device. |
| * |
| * <p>Applications will not normally use WindowManager directly, instead relying |
| * on the higher-level facilities in {@link android.app.Activity} and |
| * {@link android.app.Dialog}. |
| * |
| * <p>Even for low-level window manager access, it is almost never correct to use |
| * this class. For example, {@link android.app.Activity#getWindowManager} |
| * provides a window manager for adding windows that are associated with that |
| * activity -- the window manager will not normally allow you to add arbitrary |
| * windows that are not associated with an activity. |
| * |
| * @see WindowManager |
| * @see WindowManagerGlobal |
| * @hide |
| */ |
| public final class WindowManagerImpl implements WindowManager { |
| @UnsupportedAppUsage |
| private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); |
| private final Context mContext; |
| private final Window mParentWindow; |
| |
| private IBinder mDefaultToken; |
| |
| private boolean mIsViewAdded; |
| private View mLastView; |
| private WindowManager.LayoutParams mLastParams; |
| |
| public WindowManagerImpl(Context context) { |
| this(context, null); |
| } |
| |
| private WindowManagerImpl(Context context, Window parentWindow) { |
| mContext = context; |
| mParentWindow = parentWindow; |
| } |
| |
| public WindowManagerImpl createLocalWindowManager(Window parentWindow) { |
| return new WindowManagerImpl(mContext, parentWindow); |
| } |
| |
| public WindowManagerImpl createPresentationWindowManager(Context displayContext) { |
| return new WindowManagerImpl(displayContext, mParentWindow); |
| } |
| |
| /** |
| * Sets the window token to assign when none is specified by the client or |
| * available from the parent window. |
| * |
| * @param token The default token to assign. |
| */ |
| public void setDefaultToken(IBinder token) { |
| mDefaultToken = token; |
| } |
| |
| @Override |
| public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { |
| applyDefaultToken(params); |
| mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); |
| mIsViewAdded = true; |
| mLastView = view; |
| mLastParams = (WindowManager.LayoutParams) params; |
| } |
| |
| @Override |
| public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { |
| applyDefaultToken(params); |
| mGlobal.updateViewLayout(view, params); |
| } |
| |
| private void applyDefaultToken(@NonNull ViewGroup.LayoutParams params) { |
| // Only use the default token if we don't have a parent window. |
| if (mDefaultToken != null && mParentWindow == null) { |
| if (!(params instanceof WindowManager.LayoutParams)) { |
| throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); |
| } |
| |
| // Only use the default token if we don't already have a token. |
| final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; |
| if (wparams.token == null) { |
| wparams.token = mDefaultToken; |
| } |
| } |
| } |
| |
| @Override |
| public void removeView(View view) { |
| mGlobal.removeView(view, false); |
| } |
| |
| @Override |
| public void removeViewImmediate(View view) { |
| mGlobal.removeView(view, true); |
| } |
| |
| @Override |
| public void requestAppKeyboardShortcuts( |
| final KeyboardShortcutsReceiver receiver, int deviceId) { |
| IResultReceiver resultReceiver = new IResultReceiver.Stub() { |
| @Override |
| public void send(int resultCode, Bundle resultData) throws RemoteException { |
| List<KeyboardShortcutGroup> result = |
| resultData.getParcelableArrayList(PARCEL_KEY_SHORTCUTS_ARRAY); |
| receiver.onKeyboardShortcutsReceived(result); |
| } |
| }; |
| try { |
| WindowManagerGlobal.getWindowManagerService() |
| .requestAppKeyboardShortcuts(resultReceiver, deviceId); |
| } catch (RemoteException e) { |
| } |
| } |
| |
| @Override |
| public Display getDefaultDisplay() { |
| return mContext.getDisplay(); |
| } |
| |
| @Override |
| public Region getCurrentImeTouchRegion() { |
| try { |
| return WindowManagerGlobal.getWindowManagerService().getCurrentImeTouchRegion(); |
| } catch (RemoteException e) { |
| } |
| return null; |
| } |
| |
| @Override |
| public void setShouldShowWithInsecureKeyguard(int displayId, boolean shouldShow) { |
| try { |
| WindowManagerGlobal.getWindowManagerService() |
| .setShouldShowWithInsecureKeyguard(displayId, shouldShow); |
| } catch (RemoteException e) { |
| } |
| } |
| |
| @Override |
| public void setShouldShowSystemDecors(int displayId, boolean shouldShow) { |
| try { |
| WindowManagerGlobal.getWindowManagerService() |
| .setShouldShowSystemDecors(displayId, shouldShow); |
| } catch (RemoteException e) { |
| } |
| } |
| |
| @Override |
| public boolean shouldShowSystemDecors(int displayId) { |
| try { |
| return WindowManagerGlobal.getWindowManagerService().shouldShowSystemDecors(displayId); |
| } catch (RemoteException e) { |
| } |
| return false; |
| } |
| |
| @Override |
| public void setShouldShowIme(int displayId, boolean shouldShow) { |
| try { |
| WindowManagerGlobal.getWindowManagerService().setShouldShowIme(displayId, shouldShow); |
| } catch (RemoteException e) { |
| } |
| } |
| |
| @Override |
| public boolean shouldShowIme(int displayId) { |
| try { |
| return WindowManagerGlobal.getWindowManagerService().shouldShowIme(displayId); |
| } catch (RemoteException e) { |
| } |
| return false; |
| } |
| |
| @Override |
| public WindowMetrics getCurrentWindowMetrics() { |
| final Context context = mParentWindow != null ? mParentWindow.getContext() : mContext; |
| final Rect bound = getCurrentBounds(context); |
| |
| return new WindowMetrics(toSize(bound), computeWindowInsets()); |
| } |
| |
| private static Rect getCurrentBounds(Context context) { |
| synchronized (ResourcesManager.getInstance()) { |
| return context.getResources().getConfiguration().windowConfiguration.getBounds(); |
| } |
| } |
| |
| @Override |
| public WindowMetrics getMaximumWindowMetrics() { |
| return new WindowMetrics(toSize(getMaximumBounds()), computeWindowInsets()); |
| } |
| |
| private Size toSize(Rect frame) { |
| return new Size(frame.width(), frame.height()); |
| } |
| |
| private Rect getMaximumBounds() { |
| // TODO(b/128338354): Current maximum bound is display size, but it should be displayArea |
| // bound after displayArea feature is finished. |
| final Display display = mContext.getDisplay(); |
| final Point displaySize = new Point(); |
| display.getRealSize(displaySize); |
| return new Rect(0, 0, displaySize.x, displaySize.y); |
| } |
| |
| private WindowInsets computeWindowInsets() { |
| // TODO(window-context): This can only be properly implemented |
| // once we flip the new insets mode flag. |
| if (mParentWindow != null) { |
| if (mParentWindow.getDecorView().isAttachedToWindow()) { |
| return mParentWindow.getDecorView().getViewRootImpl() |
| .getWindowInsets(true /* forceConstruct */); |
| } |
| return getWindowInsetsFromServer(mParentWindow.getAttributes()); |
| } |
| if (mIsViewAdded) { |
| return mLastView.getViewRootImpl().getWindowInsets(true /* forceConstruct */); |
| } else { |
| return getWindowInsetsFromServer(new WindowManager.LayoutParams()); |
| } |
| |
| } |
| |
| private WindowInsets getWindowInsetsFromServer(WindowManager.LayoutParams attrs) { |
| try { |
| final Rect systemWindowInsets = new Rect(); |
| final Rect stableInsets = new Rect(); |
| final DisplayCutout.ParcelableWrapper displayCutout = |
| new DisplayCutout.ParcelableWrapper(); |
| WindowManagerGlobal.getWindowManagerService().getWindowInsets(attrs, |
| mContext.getDisplayId(), systemWindowInsets, stableInsets, displayCutout); |
| return new WindowInsets.Builder() |
| .setSystemWindowInsets(Insets.of(systemWindowInsets)) |
| .setStableInsets(Insets.of(stableInsets)) |
| .setDisplayCutout(displayCutout.get()).build(); |
| } catch (RemoteException e) { |
| } |
| return null; |
| } |
| } |