Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d7d9c3e3 authored by Adrian Roos's avatar Adrian Roos Committed by Android (Google) Code Review
Browse files

Merge "Introduce WindowContext API"

parents ca571492 4a316973
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -9965,6 +9965,7 @@ package android.content {
    method public abstract android.content.Context createDisplayContext(@NonNull android.view.Display);
    method @NonNull public android.content.Context createFeatureContext(@Nullable String);
    method public abstract android.content.Context createPackageContext(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
    method @NonNull public android.content.Context createWindowContext(int);
    method public abstract String[] databaseList();
    method public abstract boolean deleteDatabase(String);
    method public abstract boolean deleteFile(String);
@@ -9989,6 +9990,7 @@ package android.content {
    method public abstract java.io.File getDataDir();
    method public abstract java.io.File getDatabasePath(String);
    method public abstract java.io.File getDir(String, int);
    method @Nullable public android.view.Display getDisplay();
    method @Nullable public final android.graphics.drawable.Drawable getDrawable(@DrawableRes int);
    method @Nullable public abstract java.io.File getExternalCacheDir();
    method public abstract java.io.File[] getExternalCacheDirs();
@@ -54608,7 +54610,7 @@ package android.view {
  }
  public interface WindowManager extends android.view.ViewManager {
    method public android.view.Display getDefaultDisplay();
    method @Deprecated public android.view.Display getDefaultDisplay();
    method public void removeViewImmediate(android.view.View);
  }
+0 −2
Original line number Diff line number Diff line
@@ -758,7 +758,6 @@ package android.content {
    method @NonNull public android.content.Context createContextAsUser(@NonNull android.os.UserHandle, int);
    method @NonNull public android.content.Context createPackageContextAsUser(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
    method @NonNull public java.io.File getCrateDir(@NonNull String);
    method public abstract android.view.Display getDisplay();
    method public abstract int getDisplayId();
    method public android.os.UserHandle getUser();
    method public int getUserId();
@@ -779,7 +778,6 @@ package android.content {
  }

  public class ContextWrapper extends android.content.Context {
    method public android.view.Display getDisplay();
    method public int getDisplayId();
  }

+56 −22
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package android.app;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.AutofillOptions;
import android.content.BroadcastReceiver;
@@ -201,7 +200,7 @@ class ContextImpl extends Context {
    @UnsupportedAppUsage
    private @Nullable ClassLoader mClassLoader;

    private final @Nullable IBinder mActivityToken;
    private final @Nullable IBinder mToken;

    private final @NonNull UserHandle mUser;

@@ -219,7 +218,7 @@ class ContextImpl extends Context {
    private final @NonNull ResourcesManager mResourcesManager;
    @UnsupportedAppUsage
    private @NonNull Resources mResources;
    private @Nullable Display mDisplay; // may be null if default display
    private @Nullable Display mDisplay; // may be null if invalid display or not initialized yet.

    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
    private final int mFlags;
@@ -244,6 +243,9 @@ class ContextImpl extends Context {

    private final Object mSync = new Object();

    private boolean mIsSystemOrSystemUiContext;
    private boolean mIsUiContext;

    @GuardedBy("mSync")
    private File mDatabasesDir;
    @GuardedBy("mSync")
@@ -1883,6 +1885,9 @@ class ContextImpl extends Context {

    @Override
    public Object getSystemService(String name) {
        if (isUiComponent(name) && !isUiContext()) {
            Log.w(TAG, name + " should be accessed from Activity or other visual Context");
        }
        return SystemServiceRegistry.getSystemService(this, name);
    }

@@ -1891,6 +1896,15 @@ class ContextImpl extends Context {
        return SystemServiceRegistry.getSystemServiceName(serviceClass);
    }

    boolean isUiContext() {
        return mIsSystemOrSystemUiContext || mIsUiContext;
    }

    private static boolean isUiComponent(String name) {
        return WINDOW_SERVICE.equals(name) || LAYOUT_INFLATER_SERVICE.equals(name)
                || WALLPAPER_SERVICE.equals(name);
    }

    @Override
    public int checkPermission(String permission, int pid, int uid) {
        if (permission == null) {
@@ -2229,12 +2243,12 @@ class ContextImpl extends Context {
        LoadedApk pi = mMainThread.getPackageInfo(application, mResources.getCompatibilityInfo(),
                flags | CONTEXT_REGISTER_PACKAGE);
        if (pi != null) {
            ContextImpl c = new ContextImpl(this, mMainThread, pi, null, null, mActivityToken,
            ContextImpl c = new ContextImpl(this, mMainThread, pi, null, null, mToken,
                    new UserHandle(UserHandle.getUserId(application.uid)), flags, null, null);

            final int displayId = getDisplayId();

            c.setResources(createResources(mActivityToken, pi, null, displayId, null,
            c.setResources(createResources(mToken, pi, null, displayId, null,
                    getDisplayAdjustments(displayId).getCompatibilityInfo()));
            if (c.mResources != null) {
                return c;
@@ -2258,18 +2272,18 @@ class ContextImpl extends Context {
            // The system resources are loaded in every application, so we can safely copy
            // the context without reloading Resources.
            return new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId, null,
                    mActivityToken, user, flags, null, null);
                    mToken, user, flags, null, null);
        }

        LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
                flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
        if (pi != null) {
            ContextImpl c = new ContextImpl(this, mMainThread, pi, mFeatureId, null,
                    mActivityToken, user, flags, null, null);
                    mToken, user, flags, null, null);

            final int displayId = getDisplayId();

            c.setResources(createResources(mActivityToken, pi, null, displayId, null,
            c.setResources(createResources(mToken, pi, null, displayId, null,
                    getDisplayAdjustments(displayId).getCompatibilityInfo()));
            if (c.mResources != null) {
                return c;
@@ -2301,12 +2315,12 @@ class ContextImpl extends Context {
        final String[] paths = mPackageInfo.getSplitPaths(splitName);

        final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo,
                mFeatureId, splitName, mActivityToken, mUser, mFlags, classLoader, null);
                mFeatureId, splitName, mToken, mUser, mFlags, classLoader, null);

        final int displayId = getDisplayId();

        context.setResources(ResourcesManager.getInstance().getResources(
                mActivityToken,
                mToken,
                mPackageInfo.getResDir(),
                paths,
                mPackageInfo.getOverlayDirs(),
@@ -2325,10 +2339,10 @@ class ContextImpl extends Context {
        }

        ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId,
                mSplitName, mActivityToken, mUser, mFlags, mClassLoader, null);
                mSplitName, mToken, mUser, mFlags, mClassLoader, null);

        final int displayId = getDisplayId();
        context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId,
        context.setResources(createResources(mToken, mPackageInfo, mSplitName, displayId,
                overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo()));
        return context;
    }
@@ -2340,19 +2354,36 @@ class ContextImpl extends Context {
        }

        ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId,
                mSplitName, mActivityToken, mUser, mFlags, mClassLoader, null);
                mSplitName, mToken, mUser, mFlags, mClassLoader, null);

        final int displayId = display.getDisplayId();
        context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId,
        context.setResources(createResources(mToken, mPackageInfo, mSplitName, displayId,
                null, getDisplayAdjustments(displayId).getCompatibilityInfo()));
        context.mDisplay = display;
        return context;
    }

    @Override
    public @NonNull WindowContext createWindowContext(int type) {
        if (getDisplay() == null) {
            throw new UnsupportedOperationException("WindowContext can only be created from "
                    + "other visual contexts, such as Activity or one created with "
                    + "Context#createDisplayContext(Display)");
        }
        return new WindowContext(this, null /* token */, type);
    }

    ContextImpl createBaseWindowContext(IBinder token) {
        ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId,
                mSplitName, token, mUser, mFlags, mClassLoader, null);
        context.mIsUiContext = true;
        return context;
    }

    @Override
    public @NonNull Context createFeatureContext(@Nullable String featureId) {
        return new ContextImpl(this, mMainThread, mPackageInfo, featureId, mSplitName,
                mActivityToken, mUser, mFlags, mClassLoader, null);
                mToken, mUser, mFlags, mClassLoader, null);
    }

    @Override
@@ -2360,7 +2391,7 @@ class ContextImpl extends Context {
        final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE)
                | Context.CONTEXT_DEVICE_PROTECTED_STORAGE;
        return new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId, mSplitName,
                mActivityToken, mUser, flags, mClassLoader, null);
                mToken, mUser, flags, mClassLoader, null);
    }

    @Override
@@ -2368,7 +2399,7 @@ class ContextImpl extends Context {
        final int flags = (mFlags & ~Context.CONTEXT_DEVICE_PROTECTED_STORAGE)
                | Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE;
        return new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId, mSplitName,
                mActivityToken, mUser, flags, mClassLoader, null);
                mToken, mUser, flags, mClassLoader, null);
    }

    @Override
@@ -2394,8 +2425,6 @@ class ContextImpl extends Context {
        return (mFlags & Context.CONTEXT_IGNORE_SECURITY) != 0;
    }

    @UnsupportedAppUsage
    @TestApi
    @Override
    public Display getDisplay() {
        if (mDisplay == null) {
@@ -2408,7 +2437,8 @@ class ContextImpl extends Context {

    @Override
    public int getDisplayId() {
        return mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
        final Display display = getDisplay();
        return display != null ? display.getDisplayId() : Display.DEFAULT_DISPLAY;
    }

    @Override
@@ -2518,6 +2548,7 @@ class ContextImpl extends Context {
        context.setResources(packageInfo.getResources());
        context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
                context.mResourcesManager.getDisplayMetrics());
        context.mIsSystemOrSystemUiContext = true;
        return context;
    }

@@ -2535,6 +2566,7 @@ class ContextImpl extends Context {
        context.setResources(createResources(null, packageInfo, null, displayId, null,
                packageInfo.getCompatibilityInfo()));
        context.updateDisplay(displayId);
        context.mIsSystemOrSystemUiContext = true;
        return context;
    }

@@ -2584,6 +2616,7 @@ class ContextImpl extends Context {

        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null,
                activityInfo.splitName, activityToken, null, 0, classLoader, null);
        context.mIsUiContext = true;

        // Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.
        displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;
@@ -2629,7 +2662,7 @@ class ContextImpl extends Context {
        }

        mMainThread = mainThread;
        mActivityToken = activityToken;
        mToken = activityToken;
        mFlags = flags;

        if (user == null) {
@@ -2649,6 +2682,7 @@ class ContextImpl extends Context {
            opPackageName = container.mOpPackageName;
            setResources(container.mResources);
            mDisplay = container.mDisplay;
            mIsSystemOrSystemUiContext = container.mIsSystemOrSystemUiContext;
        } else {
            mBasePackageName = packageInfo.mPackageName;
            ApplicationInfo ainfo = packageInfo.getApplicationInfo();
@@ -2710,7 +2744,7 @@ class ContextImpl extends Context {
    @Override
    @UnsupportedAppUsage
    public IBinder getActivityToken() {
        return mActivityToken;
        return mToken;
    }

    private void checkMode(int mode) {
+123 −0
Original line number Diff line number Diff line
/*
 * 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 android.annotation.NonNull;
import android.content.Context;
import android.content.ContextWrapper;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerImpl;

/**
 * {@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)
 * @hide
 */
// TODO(b/128338354): Handle config/display changes from server side.
public class WindowContext extends ContextWrapper {
    private final WindowManagerImpl mWindowManager;
    private final IWindowManager mWms;
    private final IBinder mToken;
    private final int mDisplayId;
    private boolean mOwnsToken;

    /**
     * Default constructor. Can either accept an existing token or generate one and registers it
     * with the server if necessary.
     *
     * @param base Base {@link Context} for this new instance.
     * @param token A valid {@link com.android.server.wm.WindowToken}. Pass {@code null} to generate
     *              one.
     * @param type Window type to be used with this context.
     * @hide
     */
    public WindowContext(Context base, IBinder token, int type) {
        super(null /* base */);

        mWms = WindowManagerGlobal.getWindowManagerService();
        if (token != null && !isWindowToken(token)) {
            throw new IllegalArgumentException("Token must be registered to server.");
        }

        final ContextImpl contextImpl = createBaseWindowContext(base, token);
        attachBaseContext(contextImpl);
        contextImpl.setOuterContext(this);

        mToken = token != null ? token : new Binder();
        mDisplayId = getDisplayId();
        mWindowManager = new WindowManagerImpl(this);
        mWindowManager.setDefaultToken(mToken);

        // TODO(b/128338354): Obtain the correct config from WM and adjust resources.
        if (token != null) {
            mOwnsToken = false;
            return;
        }
        try {
            mWms.addWindowContextToken(mToken, type, mDisplayId, getPackageName());
            // TODO(window-context): remove token with a DeathObserver
        }  catch (RemoteException e) {
            mOwnsToken = false;
            throw e.rethrowFromSystemServer();
        }
        mOwnsToken = true;
    }

    /** Check if the passed window token is registered with the server. */
    private boolean isWindowToken(@NonNull IBinder token) {
        try {
            return mWms.isWindowToken(token);
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
        }
        return false;
    }

    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 {
        if (mOwnsToken) {
            try {
                mWms.removeWindowToken(mToken, mDisplayId);
                mOwnsToken = false;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
        super.finalize();
    }
}
+67 −5
Original line number Diff line number Diff line
@@ -5729,6 +5729,63 @@ public abstract class Context {
     */
    public abstract Context createDisplayContext(@NonNull Display display);

    /**
     * Creates a Context for a non-activity window.
     *
     * <p>
     * A window context is a context that can be used to add non-activity windows, such as
     * {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY}. A window context
     * must be created from a context that has an associated {@link Display}, such as
     * {@link android.app.Activity Activity} or a context created with
     * {@link #createDisplayContext(Display)}.
     *
     * <p>
     * The window context is created with the appropriate {@link Configuration} for the area of the
     * display that the windows created with it can occupy; it must be used when
     * {@link android.view.LayoutInflater inflating} views, such that they can be inflated with
     * proper {@link Resources}.
     *
     * Below is a sample code to <b>add an application overlay window on the primary display:<b/>
     * <pre class="prettyprint">
     * ...
     * final DisplayManager dm = anyContext.getSystemService(DisplayManager.class);
     * final Display primaryDisplay = dm.getDisplay(DEFAULT_DISPLAY);
     * final Context windowContext = anyContext.createDisplayContext(primaryDisplay)
     *         .createWindowContext(TYPE_APPLICATION_OVERLAY);
     * final View overlayView = Inflater.from(windowContext).inflate(someLayoutXml, null);
     *
     * // WindowManager.LayoutParams initialization
     * ...
     * mParams.type = TYPE_APPLICATION_OVERLAY;
     * ...
     *
     * mWindowContext.getSystemService(WindowManager.class).addView(overlayView, mParams);
     * </pre>
     *
     * <p>
     * This context's configuration and resources are adjusted to a display area where the windows
     * with provided type will be added. <b>Note that all windows associated with the same context
     * will have an affinity and can only be moved together between different displays or areas on a
     * display.</b> If there is a need to add different window types, or non-associated windows,
     * separate Contexts should be used.
     * </p>
     *
     * @param type Window type in {@link WindowManager.LayoutParams}
     * @return A {@link Context} that can be used to create windows.
     * @throws UnsupportedOperationException if this is called on a non-UI context, such as
     *         {@link android.app.Application Application} or {@link android.app.Service Service}.
     *
     * @see #getSystemService(String)
     * @see #getSystemService(Class)
     * @see #WINDOW_SERVICE
     * @see #LAYOUT_INFLATER_SERVICE
     * @see #WALLPAPER_SERVICE
     * @throws IllegalArgumentException if token is invalid
     */
    public @NonNull Context createWindowContext(int type)  {
        throw new RuntimeException("Not implemented. Must override in a subclass.");
    }

    /**
     * Return a new Context object for the current Context but for a different feature in the app.
     * Features can be used by complex apps to separate logical parts.
@@ -5813,17 +5870,22 @@ public abstract class Context {
    public abstract DisplayAdjustments getDisplayAdjustments(int displayId);

    /**
     * Get the display this context is associated with. Applications should use this method with
     * {@link android.app.Activity} or a context associated with a {@link Display} via
     * {@link #createDisplayContext(Display)} to get a display object associated with a Context, or
     * {@link android.hardware.display.DisplayManager#getDisplay} to get a display object by id.
     * @return Returns the {@link Display} object this context is associated with.
     * @hide
     */
    @UnsupportedAppUsage
    @TestApi
    public abstract Display getDisplay();
    @Nullable
    public Display getDisplay() {
        throw new RuntimeException("Not implemented. Must override in a subclass.");
    }

    /**
     * Gets the display ID.
     * Gets the ID of the display this context is associated with.
     *
     * @return display ID associated with this {@link Context}.
     * @see #getDisplay()
     * @hide
     */
    @TestApi
Loading