/* * Copyright (C) 2020 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.app; import static android.view.WindowManagerGlobal.ADD_OKAY; import static android.view.WindowManagerGlobal.ADD_TOO_MANY_TOKENS; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.ContextWrapper; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.view.IWindowManager; import android.view.WindowManagerGlobal; import android.view.WindowManagerImpl; import com.android.internal.annotations.VisibleForTesting; import java.lang.ref.Reference; /** * {@link WindowContext} is a context for non-activity windows such as * {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY} windows or system * windows. Its resources and configuration are adjusted to the area of the display that will be * used when a new window is added via {@link android.view.WindowManager#addView}. * * @see Context#createWindowContext(int, Bundle) * @hide */ public class WindowContext extends ContextWrapper { private final WindowManagerImpl mWindowManager; private final IWindowManager mWms; private final WindowTokenClient mToken; private boolean mOwnsToken; /** * Default constructor. Will generate a {@link WindowTokenClient} and attach this context to * the token. * * @param base Base {@link Context} for this new instance. * @param type Window type to be used with this context. * @hide */ public WindowContext(@NonNull Context base, int type, @Nullable Bundle options) { // Correct base context will be built once the token is resolved, so passing 'null' here. super(null /* base */); mWms = WindowManagerGlobal.getWindowManagerService(); mToken = new WindowTokenClient(); final ContextImpl contextImpl = createBaseWindowContext(base, mToken); attachBaseContext(contextImpl); contextImpl.setOuterContext(this); mToken.attachContext(this); mWindowManager = new WindowManagerImpl(this); mWindowManager.setDefaultToken(mToken); int result; try { // Register the token with WindowManager. This will also call back with the current // config back to the client. result = mWms.addWindowTokenWithOptions( mToken, type, getDisplayId(), options, getPackageName()); } catch (RemoteException e) { mOwnsToken = false; throw e.rethrowFromSystemServer(); } if (result == ADD_TOO_MANY_TOKENS) { throw new UnsupportedOperationException("createWindowContext failed! Too many unused " + "window contexts. Please see Context#createWindowContext documentation for " + "detail."); } mOwnsToken = result == ADD_OKAY; Reference.reachabilityFence(this); } private static ContextImpl createBaseWindowContext(Context outer, IBinder token) { final ContextImpl contextImpl = ContextImpl.getImpl(outer); return contextImpl.createBaseWindowContext(token); } @Override public Object getSystemService(String name) { if (WINDOW_SERVICE.equals(name)) { return mWindowManager; } return super.getSystemService(name); } @Override protected void finalize() throws Throwable { release(); super.finalize(); } /** Used for test to invoke because we can't invoke finalize directly. */ @VisibleForTesting public void release() { if (mOwnsToken) { try { mWms.removeWindowToken(mToken, getDisplayId()); mOwnsToken = false; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } destroy(); } void destroy() { final ContextImpl impl = (ContextImpl) getBaseContext(); impl.scheduleFinalCleanup(getClass().getName(), "WindowContext"); Reference.reachabilityFence(this); } }