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

Commit 5901e7ce authored by Garfield Tan's avatar Garfield Tan
Browse files

Add window layout affinity.

Window layout affinity is used to combine launch params records for
activities from the same UID that have the same value.

I didn't choose to replace component name as the key to launch params
map by window layout affinity because keeping both has some good traits
when app is updated with some window layout affinity changes:
1) The record with component name is still updated even if it starts to
have a window layout affinity so we don't have to worry about the
orphaned record;
2) Activity that changes/loses window layout affinity can always use the
last launch param that activity saves, instead of starting from default
launch behavior again;
3) App removal can still naturally clean up all useless records.

Those come at a cost that we need to iterate all activities in the same
window layout affinity when getting the launch params, but it's OK
because it's not very common to have specific task affinities and in
cases where they do the number of activities sharing the same task
affinities is limited.

Bug: 146015757
Test: Manual test that 2 activities in a single test app shares the same
launch params record.
Test: atest LaunchParamsPersisterTests

Change-Id: Idb2e7509c6bdf22ac6c9cf41059e9c696419028b
parent 43cae91e
Loading
Loading
Loading
Loading
+23 −9
Original line number Diff line number Diff line
@@ -1222,13 +1222,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
        dest.writeInt(lockTaskLaunchMode);
        if (windowLayout != null) {
            dest.writeInt(1);
            dest.writeInt(windowLayout.width);
            dest.writeFloat(windowLayout.widthFraction);
            dest.writeInt(windowLayout.height);
            dest.writeFloat(windowLayout.heightFraction);
            dest.writeInt(windowLayout.gravity);
            dest.writeInt(windowLayout.minWidth);
            dest.writeInt(windowLayout.minHeight);
            windowLayout.writeToParcel(dest);
        } else {
            dest.writeInt(0);
        }
@@ -1372,8 +1366,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
     * @attr ref android.R.styleable#AndroidManifestLayout_minHeight
     */
    public static final class WindowLayout {
        public WindowLayout(int width, float widthFraction, int height, float heightFraction, int gravity,
                int minWidth, int minHeight) {
        public WindowLayout(int width, float widthFraction, int height, float heightFraction,
                int gravity, int minWidth, int minHeight) {
            this.width = width;
            this.widthFraction = widthFraction;
            this.height = height;
@@ -1392,6 +1386,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
            gravity = source.readInt();
            minWidth = source.readInt();
            minHeight = source.readInt();
            windowLayoutAffinity = source.readString();
        }

        /**
@@ -1457,6 +1452,13 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
         */
        public final int minHeight;

        /**
         * Affinity of window layout parameters. Activities with the same UID and window layout
         * affinity will share the same window dimension record.
         * @hide
         */
        public String windowLayoutAffinity;

        /**
         * Returns if this {@link WindowLayout} has specified bounds.
         * @hide
@@ -1464,5 +1466,17 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
        public boolean hasSpecifiedSize() {
            return width >= 0 || height >= 0 || widthFraction >= 0 || heightFraction >= 0;
        }

        /** @hide */
        public void writeToParcel(Parcel dest) {
            dest.writeInt(width);
            dest.writeFloat(widthFraction);
            dest.writeInt(height);
            dest.writeFloat(heightFraction);
            dest.writeInt(gravity);
            dest.writeInt(minWidth);
            dest.writeInt(minHeight);
            dest.writeString(windowLayoutAffinity);
        }
    }
}
+33 −1
Original line number Diff line number Diff line
@@ -55,7 +55,6 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.content.pm.split.DefaultSplitAssetLoader;
import android.content.pm.split.SplitAssetDependencyLoader;
@@ -209,6 +208,8 @@ public class PackageParser {
    public static final String TAG_USES_SPLIT = "uses-split";

    public static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
    public static final String METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY =
            "android.activity_window_layout_affinity";

    /**
     * Bit mask of all the valid bits that can be set in recreateOnConfigChanges.
@@ -4560,6 +4561,8 @@ public class PackageParser {
            }
        }

        resolveWindowLayout(a);

        if (!setExported) {
            a.info.exported = a.intents.size() > 0;
        }
@@ -4726,6 +4729,35 @@ public class PackageParser {
                height, heightFraction, gravity, minWidth, minHeight);
    }

    /**
     * Resolves values in {@link ActivityInfo.WindowLayout}.
     *
     * <p>{@link ActivityInfo.WindowLayout#windowLayoutAffinity} has a fallback metadata used in
     * Android R and some variants of pre-R.
     */
    private void resolveWindowLayout(Activity activity) {
        // There isn't a metadata for us to fall back. Whatever is in layout is correct.
        if (activity.metaData == null
                || !activity.metaData.containsKey(METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY)) {
            return;
        }

        final ActivityInfo aInfo = activity.info;
        // Layout already specifies a value. We should just use that one.
        if (aInfo.windowLayout != null && aInfo.windowLayout.windowLayoutAffinity != null) {
            return;
        }

        String windowLayoutAffinity = activity.metaData.getString(
                METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY);
        if (aInfo.windowLayout == null) {
            aInfo.windowLayout = new ActivityInfo.WindowLayout(-1 /* width */,
                    -1 /* widthFraction */, -1 /* height */, -1 /* heightFraction */,
                    Gravity.NO_GRAVITY, -1 /* minWidth */, -1 /* minHeight */);
        }
        aInfo.windowLayout.windowLayoutAffinity = windowLayoutAffinity;
    }

    private Activity parseActivityAlias(Package owner, Resources res,
            XmlResourceParser parser, int flags, String[] outError,
            CachedComponentArgs cachedArgs)
+2 −8
Original line number Diff line number Diff line
@@ -285,14 +285,8 @@ public class ParsedActivity extends ParsedMainComponent {
        dest.writeBundle(this.metaData);

        if (windowLayout != null) {
            dest.writeBoolean(true);
            dest.writeInt(windowLayout.width);
            dest.writeFloat(windowLayout.widthFraction);
            dest.writeInt(windowLayout.height);
            dest.writeFloat(windowLayout.heightFraction);
            dest.writeInt(windowLayout.gravity);
            dest.writeInt(windowLayout.minWidth);
            dest.writeInt(windowLayout.minHeight);
            dest.writeInt(1);
            windowLayout.writeToParcel(dest);
        } else {
            dest.writeBoolean(false);
        }
+40 −5
Original line number Diff line number Diff line
@@ -17,16 +17,17 @@
package android.content.pm.parsing.component;

import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;

import static android.content.pm.parsing.component.ComponentParseUtils.flag;

import android.annotation.NonNull;
import android.app.ActivityTaskManager;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageParser;

import android.content.pm.parsing.ParsingPackage;
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.ParsingUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -42,9 +43,6 @@ import android.view.WindowManager;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -379,6 +377,12 @@ public class ParsedActivityUtils {
            }
        }

        ParseResult<ActivityInfo.WindowLayout> layoutResult = resolveWindowLayout(activity, input);
        if (layoutResult.isError()) {
            return input.error(layoutResult);
        }
        activity.windowLayout = layoutResult.getResult();

        if (!setExported) {
            activity.exported = activity.getIntents().size() > 0;
        }
@@ -481,4 +485,35 @@ public class ParsedActivityUtils {
            sw.recycle();
        }
    }

    /**
     * Resolves values in {@link ActivityInfo.WindowLayout}.
     *
     * <p>{@link ActivityInfo.WindowLayout#windowLayoutAffinity} has a fallback metadata used in
     * Android R and some variants of pre-R.
     */
    private static ParseResult<ActivityInfo.WindowLayout> resolveWindowLayout(
            ParsedActivity activity, ParseInput input) {
        // There isn't a metadata for us to fall back. Whatever is in layout is correct.
        if (activity.metaData == null || !activity.metaData.containsKey(
                PackageParser.METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY)) {
            return input.success(activity.windowLayout);
        }

        // Layout already specifies a value. We should just use that one.
        if (activity.windowLayout != null && activity.windowLayout.windowLayoutAffinity != null) {
            return input.success(activity.windowLayout);
        }

        String windowLayoutAffinity = activity.metaData.getString(
                PackageParser.METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY);
        ActivityInfo.WindowLayout layout = activity.windowLayout;
        if (layout == null) {
            layout = new ActivityInfo.WindowLayout(-1 /* width */, -1 /* widthFraction */,
                    -1 /* height */, -1 /* heightFraction */, Gravity.NO_GRAVITY,
                    -1 /* minWidth */, -1 /* minHeight */);
        }
        layout.windowLayoutAffinity = windowLayoutAffinity;
        return input.success(layout);
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -1589,6 +1589,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            info.taskAffinity = uid + ":" + info.taskAffinity;
        }
        taskAffinity = info.taskAffinity;
        if (info.windowLayout != null && info.windowLayout.windowLayoutAffinity != null
                && !info.windowLayout.windowLayoutAffinity.startsWith(uid)) {
            info.windowLayout.windowLayoutAffinity =
                    uid + ":" + info.windowLayout.windowLayoutAffinity;
        }
        stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0;
        nonLocalizedLabel = aInfo.nonLocalizedLabel;
        labelRes = aInfo.labelRes;
Loading