1 /* 2 * Copyright (C) 2020 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 package android.app; 17 18 import static android.view.WindowManagerGlobal.ADD_OKAY; 19 import static android.view.WindowManagerGlobal.ADD_TOO_MANY_TOKENS; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.content.Context; 24 import android.content.ContextWrapper; 25 import android.os.Bundle; 26 import android.os.IBinder; 27 import android.os.RemoteException; 28 import android.view.IWindowManager; 29 import android.view.WindowManagerGlobal; 30 import android.view.WindowManagerImpl; 31 32 import com.android.internal.annotations.VisibleForTesting; 33 34 import java.lang.ref.Reference; 35 36 /** 37 * {@link WindowContext} is a context for non-activity windows such as 38 * {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY} windows or system 39 * windows. Its resources and configuration are adjusted to the area of the display that will be 40 * used when a new window is added via {@link android.view.WindowManager#addView}. 41 * 42 * @see Context#createWindowContext(int, Bundle) 43 * @hide 44 */ 45 public class WindowContext extends ContextWrapper { 46 private final WindowManagerImpl mWindowManager; 47 private final IWindowManager mWms; 48 private final WindowTokenClient mToken; 49 private boolean mOwnsToken; 50 51 /** 52 * Default constructor. Will generate a {@link WindowTokenClient} and attach this context to 53 * the token. 54 * 55 * @param base Base {@link Context} for this new instance. 56 * @param type Window type to be used with this context. 57 * @hide 58 */ WindowContext(@onNull Context base, int type, @Nullable Bundle options)59 public WindowContext(@NonNull Context base, int type, @Nullable Bundle options) { 60 // Correct base context will be built once the token is resolved, so passing 'null' here. 61 super(null /* base */); 62 63 mWms = WindowManagerGlobal.getWindowManagerService(); 64 mToken = new WindowTokenClient(); 65 66 final ContextImpl contextImpl = createBaseWindowContext(base, mToken); 67 attachBaseContext(contextImpl); 68 contextImpl.setOuterContext(this); 69 70 mToken.attachContext(this); 71 72 mWindowManager = new WindowManagerImpl(this); 73 mWindowManager.setDefaultToken(mToken); 74 75 int result; 76 try { 77 // Register the token with WindowManager. This will also call back with the current 78 // config back to the client. 79 result = mWms.addWindowTokenWithOptions( 80 mToken, type, getDisplayId(), options, getPackageName()); 81 } catch (RemoteException e) { 82 mOwnsToken = false; 83 throw e.rethrowFromSystemServer(); 84 } 85 if (result == ADD_TOO_MANY_TOKENS) { 86 throw new UnsupportedOperationException("createWindowContext failed! Too many unused " 87 + "window contexts. Please see Context#createWindowContext documentation for " 88 + "detail."); 89 } 90 mOwnsToken = result == ADD_OKAY; 91 Reference.reachabilityFence(this); 92 } 93 createBaseWindowContext(Context outer, IBinder token)94 private static ContextImpl createBaseWindowContext(Context outer, IBinder token) { 95 final ContextImpl contextImpl = ContextImpl.getImpl(outer); 96 return contextImpl.createBaseWindowContext(token); 97 } 98 99 @Override getSystemService(String name)100 public Object getSystemService(String name) { 101 if (WINDOW_SERVICE.equals(name)) { 102 return mWindowManager; 103 } 104 return super.getSystemService(name); 105 } 106 107 @Override finalize()108 protected void finalize() throws Throwable { 109 release(); 110 super.finalize(); 111 } 112 113 /** Used for test to invoke because we can't invoke finalize directly. */ 114 @VisibleForTesting release()115 public void release() { 116 if (mOwnsToken) { 117 try { 118 mWms.removeWindowToken(mToken, getDisplayId()); 119 mOwnsToken = false; 120 } catch (RemoteException e) { 121 throw e.rethrowFromSystemServer(); 122 } 123 } 124 destroy(); 125 } 126 destroy()127 void destroy() { 128 final ContextImpl impl = (ContextImpl) getBaseContext(); 129 impl.scheduleFinalCleanup(getClass().getName(), "WindowContext"); 130 Reference.reachabilityFence(this); 131 } 132 } 133