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

Commit 334c5bb8 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes I14c90b6a,I7850a556

* changes:
  Reset configuration of invisible size-compat activity if display changes
  Don't involve decor inset into app bounds of fixed aspect ratio app
parents ee2cca7a aec5544d
Loading
Loading
Loading
Loading
+143 −57
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.wm;

import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
import static android.app.ActivityManager.TaskDescription.ATTR_TASKDESCRIPTION_PREFIX;
import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
import static android.app.ActivityOptions.ANIM_CUSTOM;
@@ -2710,22 +2711,50 @@ final class ActivityRecord extends ConfigurationContainer {
        if (!shouldUseSizeCompatMode()) {
            return false;
        }
        final Configuration parentConfig = getParent().getConfiguration();
        final Configuration resolvedConfig = getResolvedOverrideConfiguration();
        final Rect resolvedAppBounds = resolvedConfig.windowConfiguration.getAppBounds();
        if (resolvedAppBounds == null) {
            // The override configuration has not been resolved yet.
            return false;
        }

        final Configuration parentConfig = getParent().getConfiguration();
        // Although colorMode, screenLayout, smallestScreenWidthDp are also fixed, generally these
        // fields should be changed with density and bounds, so here only compares the most
        // significant field.
        if (parentConfig.densityDpi != resolvedConfig.densityDpi) {
            return true;
        }

        final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
        final Rect parentBounds = parentAppBounds != null
                ? parentAppBounds : parentConfig.windowConfiguration.getBounds();
        final Rect overrideBounds = resolvedConfig.windowConfiguration.getBounds();
        final int appWidth = resolvedAppBounds.width();
        final int appHeight = resolvedAppBounds.height();
        final int parentAppWidth = parentAppBounds.width();
        final int parentAppHeight = parentAppBounds.height();
        if (parentAppWidth < appWidth || parentAppHeight < appHeight) {
            // One side is larger than the parent.
            return true;
        }

        if (info.hasFixedAspectRatio()) {
            final float aspectRatio = (0.5f + Math.max(appWidth, appHeight))
                    / Math.min(appWidth, appHeight);
            final float parentAspectRatio = (0.5f + Math.max(parentAppWidth, parentAppHeight))
                    / Math.min(parentAppWidth, parentAppHeight);
            // Check if the parent still has available space in long side.
            if (aspectRatio < parentAspectRatio
                    && (aspectRatio < info.maxAspectRatio || info.minAspectRatio > 0)) {
                return true;
            }
        }

        final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
        // If the width or height is the same as parent, it is already the best fit of the override
        // bounds, therefore this condition is considered as not size compatibility mode.
        return parentBounds.width() != overrideBounds.width()
                && parentBounds.height() != overrideBounds.height();
        // bounds, therefore this condition is considered as not size compatibility mode. Here uses
        // right and bottom as width and height of parent because the bounds may contain decor
        // insets which has been accounted in override bounds. See {@link #computeBounds}.
        return parentAppBounds.right != resolvedBounds.width()
                && parentAppBounds.bottom != resolvedBounds.height();
    }

    /**
@@ -2778,15 +2807,18 @@ final class ActivityRecord extends ConfigurationContainer {
                // are relative to bounds and density, they will be calculated in
                // {@link TaskRecord#computeConfigResourceOverrides} and the result will also be
                // relatively fixed.
                final Configuration srcConfig = task.getConfiguration();
                overrideConfig.colorMode = srcConfig.colorMode;
                overrideConfig.densityDpi = srcConfig.densityDpi;
                overrideConfig.screenLayout = srcConfig.screenLayout
                final Configuration parentConfig = task.getConfiguration();
                // Don't account decor insets into app bounds.
                mTmpBounds.intersect(parentConfig.windowConfiguration.getAppBounds());
                overrideConfig.windowConfiguration.setAppBounds(mTmpBounds);
                overrideConfig.colorMode = parentConfig.colorMode;
                overrideConfig.densityDpi = parentConfig.densityDpi;
                overrideConfig.screenLayout = parentConfig.screenLayout
                        & (Configuration.SCREENLAYOUT_LONG_MASK
                                | Configuration.SCREENLAYOUT_SIZE_MASK);
                // The smallest screen width is the short side of screen bounds. Because the bounds
                // and density won't be changed, smallestScreenWidthDp is also fixed.
                overrideConfig.smallestScreenWidthDp = srcConfig.smallestScreenWidthDp;
                overrideConfig.smallestScreenWidthDp = parentConfig.smallestScreenWidthDp;
            }
        }
        onRequestedOverrideConfigurationChanged(overrideConfig);
@@ -2794,33 +2826,38 @@ final class ActivityRecord extends ConfigurationContainer {

    @Override
    void resolveOverrideConfiguration(Configuration newParentConfiguration) {
        // If the activity has override bounds, the relative configuration (e.g. screen size,
        // layout) needs to be resolved according to the bounds.
        final boolean hasOverrideBounds = !matchParentBounds();
        if (hasOverrideBounds && shouldUseSizeCompatMode()) {
            resolveSizeCompatModeConfiguration(newParentConfiguration);
        } else {
            super.resolveOverrideConfiguration(newParentConfiguration);
            if (hasOverrideBounds) {
                task.computeConfigResourceOverrides(getResolvedOverrideConfiguration(),
                        newParentConfiguration, true /* insideParentBounds */);
            }
        }

        // Assign configuration sequence number into hierarchy because there is a different way than
        // ensureActivityConfiguration() in this class that uses configuration in WindowState during
        // layout traversals.
        mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
        getResolvedOverrideConfiguration().seq = mConfigurationSeq;

        if (matchParentBounds()) {
            return;
    }

    private void resolveSizeCompatModeConfiguration(Configuration newParentConfiguration) {
        final Configuration resolvedConfig = getResolvedOverrideConfiguration();
        if (!shouldUseSizeCompatMode()) {
            computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
                    ORIENTATION_UNDEFINED, true /* insideParentBounds */);
            return;
        }
        final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();

        final Configuration displayConfig = getDisplay().getConfiguration();
        int orientation = getConfiguration().orientation;
        if (orientation != displayConfig.orientation && isConfigurationCompatible(displayConfig)) {
        if (orientation != newParentConfiguration.orientation
                && isConfigurationCompatible(newParentConfiguration)) {
            // The activity is compatible to apply the orientation change or it requests different
            // fixed orientation.
            orientation = displayConfig.orientation;
            orientation = newParentConfiguration.orientation;
        } else {
            if (resolvedConfig.windowConfiguration.getAppBounds() != null) {
            if (!resolvedBounds.isEmpty()) {
                // Keep the computed resolved override configuration.
                return;
            }
@@ -2830,35 +2867,55 @@ final class ActivityRecord extends ConfigurationContainer {
            }
        }

        // Adjust the bounds to match the current orientation.
        if (orientation != ORIENTATION_UNDEFINED) {
            final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
            final int longSide = Math.max(resolvedBounds.height(), resolvedBounds.width());
            final int shortSide = Math.min(resolvedBounds.height(), resolvedBounds.width());
            final boolean toBeLandscape = orientation == ORIENTATION_LANDSCAPE;
            final int width = toBeLandscape ? longSide : shortSide;
            final int height = toBeLandscape ? shortSide : longSide;
            // Assume the bounds is always started from zero because the size may be bigger than its
        // The requested override bounds will set to the resolved bounds.
        super.resolveOverrideConfiguration(newParentConfiguration);

        boolean shouldSwapAppBounds = false;
        int width = resolvedBounds.width();
        int height = resolvedBounds.height();
        if ((orientation == ORIENTATION_LANDSCAPE && height > width)
                || (orientation == ORIENTATION_PORTRAIT && width > height)) {
            // Swap width and height because they are opposite to the orientation.
            width = resolvedBounds.height();
            height = resolvedBounds.width();
            // Assume the bounds always starts from zero because the size may be larger than its
            // parent (task ~ display). The actual letterboxing will be done by surface offset.
            resolvedBounds.set(0, 0, width, height);
        }

        // In size compatible mode, activity is allowed to have larger bounds than its parent.
        computeConfigResourceOverrides(resolvedConfig, newParentConfiguration, orientation,
            shouldSwapAppBounds = true;
        } else if (width == height) {
            // The bounds may contain decor insets, then its app bounds may not be 1:1 and need to
            // be adjusted according to the orientation.
            final int appWidth = resolvedConfig.windowConfiguration.getAppBounds().width();
            final int appHeight = resolvedConfig.windowConfiguration.getAppBounds().height();
            shouldSwapAppBounds = (orientation == ORIENTATION_LANDSCAPE && appHeight > appWidth)
                    || (orientation == ORIENTATION_PORTRAIT && appWidth > appHeight);
        }

        final Rect resolvedAppBounds = resolvedConfig.windowConfiguration.getAppBounds();
        final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
        if (shouldSwapAppBounds) {
            // Preserve the original decor insets (the left and top of the resolved app bounds) if
            // the parent also has the insets at the corresponding side.
            final int left = parentAppBounds.left > 0 ? resolvedAppBounds.top : 0;
            final int top = parentAppBounds.top > 0 ? resolvedAppBounds.left : 0;
            final int appWidth = resolvedAppBounds.height();
            final int appHeight = resolvedAppBounds.width();
            resolvedAppBounds.set(left, top, appWidth + left, appHeight + top);
        }
        // The horizontal inset included in width is not needed if the activity cannot fill the
        // parent, because the offset will be applied by {@link AppWindowToken#mSizeCompatBounds}.
        if (resolvedBounds.width() < parentAppBounds.width()) {
            resolvedBounds.right -= resolvedAppBounds.left;
        }

        // In size compatibility mode, activity is allowed to have larger bounds than its parent.
        task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
                false /* insideParentBounds */);
        // Use parent orientation if it cannot be decided by bounds, so the activity can fit inside
        // the parent bounds appropriately.
        if (resolvedConfig.screenWidthDp == resolvedConfig.screenHeightDp) {
            resolvedConfig.orientation = newParentConfiguration.orientation;
        }

    private void computeConfigResourceOverrides(Configuration inOutConfig,
            Configuration parentConfig, int orientation, boolean insideParentBounds) {
        // Set the real orientation or undefined value to ensure the output orientation won't be the
        // old value. Also reset app bounds so it will be updated according to bounds.
        inOutConfig.orientation = orientation;
        final Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
        if (outAppBounds != null) {
            outAppBounds.setEmpty();
        }

        task.computeConfigResourceOverrides(inOutConfig, parentConfig, insideParentBounds);
    }

    @Override
@@ -2889,8 +2946,27 @@ final class ActivityRecord extends ConfigurationContainer {
        }

        final ActivityDisplay display = getDisplay();
        if (display != null) {
        if (display == null) {
            return;
        }
        if (visible) {
            // It may toggle the UI for user to restart the size compatibility mode activity.
            display.handleActivitySizeCompatModeIfNeeded(this);
        } else if (shouldUseSizeCompatMode()) {
            // The override changes can only be obtained from display, because we don't have the
            // difference of full configuration in each hierarchy.
            final int displayChanges = display.getLastOverrideConfigurationChanges();
            final int orientationChanges = CONFIG_WINDOW_CONFIGURATION
                    | CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION;
            final boolean hasNonOrienSizeChanged = hasResizeChange(displayChanges)
                    // Filter out the case of simple orientation change.
                    && (displayChanges & orientationChanges) != orientationChanges;
            // For background activity that uses size compatibility mode, if the size or density of
            // the display is changed, then reset the override configuration and kill the activity's
            // process if its process state is not important to user.
            if (hasNonOrienSizeChanged || (displayChanges & ActivityInfo.CONFIG_DENSITY) != 0) {
                restartProcessIfVisible();
            }
        }
    }

@@ -2990,14 +3066,14 @@ final class ActivityRecord extends ConfigurationContainer {
            // {@link #getRequestedOverrideBounds()} will be empty (representing no override). If
            // the method has run before, then effect of {@link #getRequestedOverrideBounds()} will
            // already have been applied to the value returned from {@link getConfiguration}. Refer
            // to {@link TaskRecord#computeOverrideConfiguration}.
            // to {@link TaskRecord#computeConfigResourceOverrides()}.
            outBounds.set(getRequestedOverrideBounds());
            return;
        }

        // Compute configuration based on max supported width and height.
        // Also account for the left / top insets (e.g. from display cutouts), which will be clipped
        // away later in StackWindowController.adjustConfigurationForBounds(). Otherwise, the app
        // away later in {@link TaskRecord#computeConfigResourceOverrides()}. Otherwise, the app
        // bounds would end up too small.
        outBounds.set(0, 0, activityWidth + appBounds.left, activityHeight + appBounds.top);
    }
@@ -3357,7 +3433,8 @@ final class ActivityRecord extends ConfigurationContainer {
    void restartProcessIfVisible() {
        Slog.i(TAG, "Request to restart process of " + this);

        // Reset the existing override configuration to the latest configuration.
        // Reset the existing override configuration so it can be updated according to the latest
        // configuration.
        getRequestedOverrideConfiguration().setToDefaults();
        getResolvedOverrideConfiguration().setToDefaults();
        if (visible) {
@@ -3377,8 +3454,17 @@ final class ActivityRecord extends ConfigurationContainer {
            // Kill its process immediately because the activity should be in background.
            // The activity state will be update to {@link #DESTROYED} in
            // {@link ActivityStack#cleanUpActivityLocked} when handling process died.
            mAtmService.mH.post(() -> mAtmService.mAmInternal.killProcess(
                    app.mName, app.mUid, "restartActivityProcess"));
            mAtmService.mH.post(() -> {
                final WindowProcessController wpc;
                synchronized (mAtmService.mGlobalLock) {
                    if (!hasProcess()
                            || app.getReportedProcState() <= PROCESS_STATE_IMPORTANT_FOREGROUND) {
                        return;
                    }
                    wpc = app;
                }
                mAtmService.mAmInternal.killProcess(wpc.mName, wpc.mUid, "resetConfig");
            });
            return;
        }

+1 −1
Original line number Diff line number Diff line
@@ -5209,7 +5209,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
                // the ATMS lock held.
                final Message msg = PooledLambda.obtainMessage(
                        ActivityManagerInternal::killAllBackgroundProcessesExcept, mAmInternal,
                        N, ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
                        N, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
                mH.sendMessage(msg);
            }
        }
+6 −2
Original line number Diff line number Diff line
@@ -1627,7 +1627,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
                // If the changes come from change-listener, the incoming parent configuration is
                // still the old one. Make sure their orientations are the same to reduce computing
                // the compatibility bounds for the intermediate state.
                && getResolvedOverrideConfiguration().orientation == newParentConfig.orientation) {
                && (task.mTaskRecord == null || task.mTaskRecord
                        .getConfiguration().orientation == newParentConfig.orientation)) {
            final Rect taskBounds = task.getBounds();
            // Since we only center the activity horizontally, if only the fixed height is smaller
            // than its container, the override bounds don't need to take effect.
@@ -1763,7 +1764,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
        final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds();
        final Rect viewportBounds = parentAppBounds != null
                ? parentAppBounds : newParentConfig.windowConfiguration.getBounds();
        final Rect contentBounds = getResolvedOverrideBounds();
        final Rect appBounds = getWindowConfiguration().getAppBounds();
        final Rect contentBounds = appBounds != null ? appBounds : getResolvedOverrideBounds();
        final float contentW = contentBounds.width();
        final float contentH = contentBounds.height();
        final float viewportW = viewportBounds.width();
@@ -1780,6 +1782,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
        mSizeCompatBounds.set(contentBounds);
        mSizeCompatBounds.offsetTo(0, 0);
        mSizeCompatBounds.scale(mSizeCompatScale);
        // The decor inset is included in height.
        mSizeCompatBounds.bottom += viewportBounds.top;
        mSizeCompatBounds.left += offsetX;
        mSizeCompatBounds.right += offsetX;
    }
+10 −1
Original line number Diff line number Diff line
@@ -77,6 +77,9 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
     */
    private Configuration mFullConfiguration = new Configuration();

    /** The bit mask of the last override fields of full configuration. */
    private int mLastOverrideConfigurationChanges;

    /**
     * Contains merged override configuration settings from the top of the hierarchy down to this
     * particular instance. It is different from {@link #mFullConfiguration} because it starts from
@@ -108,6 +111,11 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
        return mFullConfiguration;
    }

    /** Returns the last changes from applying override configuration. */
    int getLastOverrideConfigurationChanges() {
        return mLastOverrideConfigurationChanges;
    }

    /**
     * Notify that parent config changed and we need to update full configuration.
     * @see #mFullConfiguration
@@ -116,6 +124,7 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
        mTmpConfig.setTo(mResolvedOverrideConfiguration);
        resolveOverrideConfiguration(newParentConfig);
        mFullConfiguration.setTo(newParentConfig);
        mLastOverrideConfigurationChanges =
                mFullConfiguration.updateFrom(mResolvedOverrideConfiguration);
        if (!mTmpConfig.equals(mResolvedOverrideConfiguration)) {
            onMergedOverrideConfigurationChanged();
+3 −2
Original line number Diff line number Diff line
@@ -2115,8 +2115,9 @@ class TaskRecord extends ConfigurationContainer {
                // {@link WindowManagerPolicy#getNonDecorInsetsLw}.
                calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, bounds, di);
            } else {
                mTmpNonDecorBounds.set(bounds);
                mTmpStableBounds.set(bounds);
                // Set to app bounds because it excludes decor insets.
                mTmpNonDecorBounds.set(outAppBounds);
                mTmpStableBounds.set(outAppBounds);
            }

            if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
Loading