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 android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.content.Context; 22 import android.os.Bundle; 23 import android.os.IBinder; 24 import android.os.RemoteException; 25 import android.view.IWindowManager; 26 import android.view.WindowManager.LayoutParams.WindowType; 27 import android.view.WindowManagerGlobal; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 31 /** 32 * The controller to manage {@link WindowContext}, such as attaching to a window manager node or 33 * detaching from the current attached node. The user must call 34 * {@link #attachToDisplayArea(int, int, Bundle)}, call {@link #attachToWindowToken(IBinder)} 35 * after that if necessary, and then call {@link #detachIfNeeded()} for release. 36 * 37 * @hide 38 */ 39 public class WindowContextController { 40 private final IWindowManager mWms; 41 /** 42 * {@code true} to indicate that the {@code mToken} is associated with a 43 * {@link com.android.server.wm.DisplayArea}. Note that {@code mToken} is able to attach a 44 * WindowToken after this flag sets to {@code true}. 45 */ 46 @VisibleForTesting 47 public boolean mAttachedToDisplayArea; 48 @NonNull 49 private final IBinder mToken; 50 51 /** 52 * Window Context Controller constructor 53 * 54 * @param token The token used to attach to a window manager node. It is usually from 55 * {@link Context#getWindowContextToken()}. 56 */ 57 public WindowContextController(@NonNull IBinder token) { 58 mToken = token; 59 mWms = WindowManagerGlobal.getWindowManagerService(); 60 } 61 62 /** Used for test only. DO NOT USE it in production code. */ 63 @VisibleForTesting 64 public WindowContextController(@NonNull IBinder token, IWindowManager mockWms) { 65 mToken = token; 66 mWms = mockWms; 67 } 68 69 /** 70 * Attaches the {@code mToken} to a {@link com.android.server.wm.DisplayArea}. 71 * 72 * @param type The window type of the {@link WindowContext} 73 * @param displayId The {@link Context#getDisplayId() ID of display} to associate with 74 * @param options The window context launched option 75 * @throws IllegalStateException if the {@code mToken} has already been attached to a 76 * DisplayArea. 77 */ 78 public void attachToDisplayArea(@WindowType int type, int displayId, @Nullable Bundle options) { 79 if (mAttachedToDisplayArea) { 80 throw new IllegalStateException("A Window Context can be only attached to " 81 + "a DisplayArea once."); 82 } 83 try { 84 mAttachedToDisplayArea = mWms.attachWindowContextToDisplayArea(mToken, type, displayId, 85 options); 86 } catch (RemoteException e) { 87 throw e.rethrowFromSystemServer(); 88 } 89 } 90 91 /** 92 * Switches to attach the window context to a window token. 93 * <p> 94 * Note that the context should have been attached to a 95 * {@link com.android.server.wm.DisplayArea} by {@link #attachToDisplayArea(int, int, Bundle)} 96 * before attaching to a window token, and the window token's type must match the window 97 * context's type. 98 * </p><p> 99 * A {@link WindowContext} can only attach to a specific window manager node, which is either a 100 * {@link com.android.server.wm.DisplayArea} by calling 101 * {@link #attachToDisplayArea(int, int, Bundle)} or the latest attached {@code windowToken} 102 * although this API is allowed to be called multiple times. 103 * </p> 104 * @throws IllegalStateException if the {@code mClientToken} has not yet attached to 105 * a {@link com.android.server.wm.DisplayArea} by 106 * {@link #attachToDisplayArea(int, int, Bundle)}. 107 * 108 * @see WindowProviderService#attachToWindowToken(IBinder)) 109 * @see IWindowManager#attachWindowContextToWindowToken(IBinder, IBinder) 110 */ 111 public void attachToWindowToken(IBinder windowToken) { 112 if (!mAttachedToDisplayArea) { 113 throw new IllegalStateException("The Window Context should have been attached" 114 + " to a DisplayArea."); 115 } 116 try { 117 mWms.attachWindowContextToWindowToken(mToken, windowToken); 118 } catch (RemoteException e) { 119 throw e.rethrowFromSystemServer(); 120 } 121 } 122 123 /** Detaches the window context from the node it's currently associated with. */ 124 public void detachIfNeeded() { 125 if (mAttachedToDisplayArea) { 126 try { 127 mWms.detachWindowContextFromWindowContainer(mToken); 128 mAttachedToDisplayArea = false; 129 } catch (RemoteException e) { 130 throw e.rethrowFromSystemServer(); 131 } 132 } 133 } 134 } 135