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

Commit c5a17006 authored by Evan Rosky's avatar Evan Rosky
Browse files

Move fixed-rotation-related display information into config

Augment the "apparent" display information in configuration
from just the display bounds (maxBounds) to also include the
display rotation and cutout. Like maxBounds, these will be
expected to always be set as basically "the display that this
configuration was built against".

This heavily simplifies fixed-rotation since now we don't
need to deal with the "are we overriding?" question and also
don't need extra activity servertransactions. The configuration
is also in sync (since it is the source of truth used by
resources). Additionally, this means that even the current
legacy fixed-rotation model should work with in any
mixed-rotation situtaion, not just fullscreen.

Bug: 202201326
Test: atest DisplayTest
Change-Id: I6232f74c74324b70b1b0c9f46448c509c2694310
parent 0e688c82
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -7160,11 +7160,6 @@ public class Activity extends ContextThemeWrapper
                writer.println(mChangingConfigurations);
        writer.print(innerPrefix); writer.print("mCurrentConfig=");
                writer.println(mCurrentConfig);
        if (getResources().hasOverrideDisplayAdjustments()) {
            writer.print(innerPrefix);
            writer.print("FixedRotationAdjustments=");
            writer.println(getResources().getDisplayAdjustments().getFixedRotationAdjustments());
        }

        mFragments.dumpLoaders(innerPrefix, fd, writer, args);
        mFragments.getFragmentManager().dump(innerPrefix, fd, writer, args);
+2 −112
Original line number Diff line number Diff line
@@ -175,7 +175,6 @@ import android.util.proto.ProtoOutputStream;
import android.view.Choreographer;
import android.view.Display;
import android.view.DisplayAdjustments;
import android.view.DisplayAdjustments.FixedRotationAdjustments;
import android.view.SurfaceControl;
import android.view.ThreadedRenderer;
import android.view.View;
@@ -598,12 +597,6 @@ public final class ActivityThread extends ClientTransactionHandler
        /** The options for scene transition. */
        ActivityOptions mActivityOptions;

        /**
         * If non-null, the activity is launching with a specified rotation, the adjustments should
         * be consumed before activity creation.
         */
        FixedRotationAdjustments mPendingFixedRotationAdjustments;

        /** Whether this activiy was launched from a bubble. */
        boolean mLaunchedFromBubble;

@@ -625,8 +618,7 @@ public final class ActivityThread extends ClientTransactionHandler
                PersistableBundle persistentState, List<ResultInfo> pendingResults,
                List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
                boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client,
                IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments,
                IBinder shareableActivityToken, boolean launchedFromBubble) {
                IBinder assistToken, IBinder shareableActivityToken, boolean launchedFromBubble) {
            this.token = token;
            this.assistToken = assistToken;
            this.shareableActivityToken = shareableActivityToken;
@@ -646,7 +638,6 @@ public final class ActivityThread extends ClientTransactionHandler
            this.packageInfo = client.getPackageInfoNoCheck(activityInfo.applicationInfo,
                    compatInfo);
            mActivityOptions = activityOptions;
            mPendingFixedRotationAdjustments = fixedRotationAdjustments;
            mLaunchedFromBubble = launchedFromBubble;
            init();
        }
@@ -3512,21 +3503,6 @@ public final class ActivityThread extends ClientTransactionHandler
        mH.sendMessage(msg);
    }

    private void sendMessage(int what, Object obj, int arg1, int arg2, int seq) {
        if (DEBUG_MESSAGES) Slog.v(
                TAG, "SCHEDULE " + mH.codeToString(what) + " arg1=" + arg1 + " arg2=" + arg2 +
                        "seq= " + seq);
        Message msg = Message.obtain();
        msg.what = what;
        SomeArgs args = SomeArgs.obtain();
        args.arg1 = obj;
        args.argi1 = arg1;
        args.argi2 = arg2;
        args.argi3 = seq;
        msg.obj = args;
        mH.sendMessage(msg);
    }

    final void scheduleContextCleanup(ContextImpl context, String who,
            String what) {
        ContextCleanupInfo cci = new ContextCleanupInfo();
@@ -3536,64 +3512,6 @@ public final class ActivityThread extends ClientTransactionHandler
        sendMessage(H.CLEAN_UP_CONTEXT, cci);
    }

    /**
     * Applies the rotation adjustments to override display information in resources belong to the
     * provided token. If the token is activity token, the adjustments also apply to application
     * because the appearance of activity is usually more sensitive to the application resources.
     *
     * @param token The token to apply the adjustments.
     * @param fixedRotationAdjustments The information to override the display adjustments of
     *                                 corresponding resources. If it is null, the exiting override
     *                                 will be cleared.
     */
    @Override
    public void handleFixedRotationAdjustments(@NonNull IBinder token,
            @Nullable FixedRotationAdjustments fixedRotationAdjustments) {
        final Consumer<DisplayAdjustments> override = fixedRotationAdjustments != null
                ? displayAdjustments -> displayAdjustments
                        .setFixedRotationAdjustments(fixedRotationAdjustments)
                : null;
        if (!mResourcesManager.overrideTokenDisplayAdjustments(token, override)) {
            // No resources are associated with the token.
            return;
        }
        if (mActivities.get(token) == null) {
            // Nothing to do for application if it is not an activity token.
            return;
        }

        overrideApplicationDisplayAdjustments(token, override);
    }

    /**
     * Applies the last override to application resources for compatibility. Because the Resources
     * of Display can be from application, e.g.
     *   applicationContext.getSystemService(DisplayManager.class).getDisplay(displayId)
     * and the deprecated usage:
     *   applicationContext.getSystemService(WindowManager.class).getDefaultDisplay();
     *
     * @param token The owner and target of the override.
     * @param override The display adjustments override for application resources. If it is null,
     *                 the override of the token will be removed and pop the last one to use.
     */
    private void overrideApplicationDisplayAdjustments(@NonNull IBinder token,
            @Nullable Consumer<DisplayAdjustments> override) {
        final Consumer<DisplayAdjustments> appOverride;
        if (mActiveRotationAdjustments == null) {
            mActiveRotationAdjustments = new ArrayList<>(2);
        }
        if (override != null) {
            mActiveRotationAdjustments.add(Pair.create(token, override));
            appOverride = override;
        } else {
            mActiveRotationAdjustments.removeIf(adjustmentsPair -> adjustmentsPair.first == token);
            appOverride = mActiveRotationAdjustments.isEmpty()
                    ? null
                    : mActiveRotationAdjustments.get(mActiveRotationAdjustments.size() - 1).second;
        }
        mInitialApplication.getResources().overrideDisplayAdjustments(appOverride);
    }

    /**  Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ActivityInfo aInfo = r.activityInfo;
@@ -3811,19 +3729,6 @@ public final class ActivityThread extends ClientTransactionHandler
        ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);

        // The rotation adjustments must be applied before creating the activity, so the activity
        // can get the adjusted display info during creation.
        if (r.mPendingFixedRotationAdjustments != null) {
            // The adjustments should have been set by handleLaunchActivity, so the last one is the
            // override for activity resources.
            if (mActiveRotationAdjustments != null && !mActiveRotationAdjustments.isEmpty()) {
                mResourcesManager.overrideTokenDisplayAdjustments(r.token,
                        mActiveRotationAdjustments.get(
                                mActiveRotationAdjustments.size() - 1).second);
            }
            r.mPendingFixedRotationAdjustments = null;
        }

        final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
        // For debugging purposes, if the activity's package name contains the value of
        // the "debug.use-second-display" system property as a substring, then show
@@ -3859,13 +3764,6 @@ public final class ActivityThread extends ClientTransactionHandler
            mProfiler.startProfiling();
        }

        if (r.mPendingFixedRotationAdjustments != null) {
            // The rotation adjustments must be applied before handling configuration, so process
            // level display metrics can be adjusted.
            overrideApplicationDisplayAdjustments(r.token, adjustments ->
                    adjustments.setFixedRotationAdjustments(r.mPendingFixedRotationAdjustments));
        }

        // Make sure we are running with the most recent config.
        mConfigurationController.handleConfigurationChanged(null, null);

@@ -5974,13 +5872,6 @@ public final class ActivityThread extends ClientTransactionHandler
        final Configuration finalOverrideConfig = createNewConfigAndUpdateIfNotNull(
                amOverrideConfig, contextThemeWrapperOverrideConfig);
        mResourcesManager.updateResourcesForActivity(activityToken, finalOverrideConfig, displayId);
        final Resources res = activity.getResources();
        if (res.hasOverrideDisplayAdjustments()) {
            // If fixed rotation is applied while the activity is visible (e.g. PiP), the rotated
            // configuration of activity may be sent later than the adjustments. In this case, the
            // adjustments need to be updated for the consistency of display info.
            res.getDisplayAdjustments().getConfiguration().updateFrom(finalOverrideConfig);
        }

        activity.mConfigChangeFlags = 0;
        activity.mCurrentConfig = new Configuration(newConfig);
@@ -7643,8 +7534,7 @@ public final class ActivityThread extends ClientTransactionHandler
                // We need to apply this change to the resources immediately, because upon returning
                // the view hierarchy will be informed about it.
                if (mResourcesManager.applyConfigurationToResources(globalConfig,
                        null /* compat */,
                        mInitialApplication.getResources().getDisplayAdjustments())) {
                        null /* compat */)) {
                    mConfigurationController.updateLocaleListFromAppContext(
                            mInitialApplication.getApplicationContext());

+0 −5
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@ import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.os.IBinder;
import android.util.MergedConfiguration;
import android.view.DisplayAdjustments.FixedRotationAdjustments;
import android.view.SurfaceControl;
import android.window.SplashScreenView.SplashScreenViewParcelable;

@@ -187,10 +186,6 @@ public abstract class ClientTransactionHandler {
    /** Deliver app configuration change notification. */
    public abstract void handleConfigurationChanged(Configuration config);

    /** Apply addition adjustments to override display information. */
    public abstract void handleFixedRotationAdjustments(IBinder token,
            FixedRotationAdjustments fixedRotationAdjustments);

    /**
     * Get {@link android.app.ActivityThread.ActivityClientRecord} instance that corresponds to the
     * provided token.
+1 −8
Original line number Diff line number Diff line
@@ -185,14 +185,7 @@ class ConfigurationController {

            final Application app = mActivityThread.getApplication();
            final Resources appResources = app.getResources();
            if (appResources.hasOverrideDisplayAdjustments()) {
                // The value of Display#getRealSize will be adjusted by FixedRotationAdjustments,
                // but Display#getSize refers to DisplayAdjustments#mConfiguration. So the rotated
                // configuration also needs to set to the adjustments for consistency.
                appResources.getDisplayAdjustments().getConfiguration().updateFrom(config);
            }
            mResourcesManager.applyConfigurationToResources(config, compat,
                    appResources.getDisplayAdjustments());
            mResourcesManager.applyConfigurationToResources(config, compat);
            updateLocaleListFromAppContext(app.getApplicationContext());

            if (mConfiguration == null) {
+20 −48
Original line number Diff line number Diff line
@@ -65,7 +65,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.WeakHashMap;
import java.util.function.Consumer;
import java.util.function.Function;

/** @hide */
@@ -343,6 +342,25 @@ public class ResourcesManager {
        return dm;
    }

    /**
     * Like getDisplayMetrics, but will adjust the result based on the display information in
     * config. This is used to make sure that the global configuration matches the activity's
     * apparent display.
     */
    private DisplayMetrics getDisplayMetrics(Configuration config) {
        final DisplayManagerGlobal displayManagerGlobal = DisplayManagerGlobal.getInstance();
        final DisplayMetrics dm = new DisplayMetrics();
        final DisplayInfo displayInfo = displayManagerGlobal != null
                ? displayManagerGlobal.getDisplayInfo(mResDisplayId) : null;
        if (displayInfo != null) {
            displayInfo.getAppMetrics(dm,
                    DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS.getCompatibilityInfo(), config);
        } else {
            dm.setToDefaults();
        }
        return dm;
    }

    private static void applyDisplayMetricsToConfiguration(@NonNull DisplayMetrics dm,
            @NonNull Configuration config) {
        config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
@@ -1312,12 +1330,6 @@ public class ResourcesManager {

    public final boolean applyConfigurationToResources(@NonNull Configuration config,
            @Nullable CompatibilityInfo compat) {
        return applyConfigurationToResources(config, compat, null /* adjustments */);
    }

    /** Applies the global configuration to the managed resources. */
    public final boolean applyConfigurationToResources(@NonNull Configuration config,
            @Nullable CompatibilityInfo compat, @Nullable DisplayAdjustments adjustments) {
        synchronized (mLock) {
            try {
                Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
@@ -1347,12 +1359,7 @@ public class ResourcesManager {
                    applyAllPendingAppInfoUpdates();
                }

                DisplayMetrics displayMetrics = getDisplayMetrics();
                if (adjustments != null) {
                    // Currently the only case where the adjustment takes effect is to simulate
                    // placing an app in a rotated display.
                    adjustments.adjustGlobalAppMetrics(displayMetrics);
                }
                final DisplayMetrics displayMetrics = getDisplayMetrics(config);
                Resources.updateSystemConfiguration(config, displayMetrics, compat);

                ApplicationPackageManager.configurationChanged();
@@ -1592,41 +1599,6 @@ public class ResourcesManager {
        }
    }

    /**
     * Overrides the display adjustments of all resources which are associated with the given token.
     *
     * @param token The token that owns the resources.
     * @param override The operation to override the existing display adjustments. If it is null,
     *                 the override adjustments will be cleared.
     * @return {@code true} if the override takes effect.
     */
    public boolean overrideTokenDisplayAdjustments(IBinder token,
            @Nullable Consumer<DisplayAdjustments> override) {
        boolean handled = false;
        synchronized (mLock) {
            final ActivityResources tokenResources = mActivityResourceReferences.get(token);
            if (tokenResources == null) {
                return false;
            }
            final ArrayList<ActivityResource> resourcesRefs = tokenResources.activityResources;
            for (int i = resourcesRefs.size() - 1; i >= 0; i--) {
                final ActivityResource activityResource = resourcesRefs.get(i);
                if (activityResource.overrideDisplayId != null) {
                    // This resource overrides the display of the token so we should not be
                    // modifying its display adjustments here.
                    continue;
                }

                final Resources res = activityResource.resources.get();
                if (res != null) {
                    res.overrideDisplayAdjustments(override);
                    handled = true;
                }
            }
        }
        return handled;
    }

    private class UpdateHandler implements Resources.UpdateCallbacks {

        /**
Loading