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

Commit f0d6cb38 authored by Christopher Tate's avatar Christopher Tate
Browse files

Prioritize most-recently-enabled link-handling app

In the case when multiple apps handle a given web-link action,
all of which have been marked as "launch the app instead of a
browser" and so are otherwise ambiguous, always prefer the app
that was most recently placed into the always-handle-links state.

Bug 22051035

Change-Id: I3f43c19b0d7b74e9843445e41971bb5433affb1c
parent c09544bb
Loading
Loading
Loading
Loading
+22 −6
Original line number Diff line number Diff line
@@ -26,7 +26,9 @@ import android.os.Parcelable;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;

import com.android.internal.util.XmlUtils;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -181,14 +183,28 @@ public final class IntentFilterVerificationInfo implements Parcelable {
        return getStatusStringFromValue(mMainStatus);
    }

    public static String getStatusStringFromValue(int val) {
        switch (val) {
            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK       : return "ask";
            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS    : return "always";
            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER     : return "never";
    public static String getStatusStringFromValue(long val) {
        StringBuilder sb = new StringBuilder();
        switch ((int)(val >> 32)) {
            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS:
                sb.append("always : ");
                sb.append(Long.toHexString(val & 0x00000000FFFFFFFF));
                break;

            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK:
                sb.append("ask");
                break;

            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER:
                sb.append("never");
                break;

            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED:
            default:
            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED : return "undefined";
                sb.append("undefined");
                break;
        }
        return sb.toString();
    }

    @Override
+2 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ public class PackageUserState {
    public ArraySet<String> enabledComponents;

    public int domainVerificationStatus;
    public int appLinkGeneration;

    public PackageUserState() {
        installed = true;
@@ -60,5 +61,6 @@ public class PackageUserState {
                ? new ArraySet<>(o.enabledComponents) : null;
        blockUninstall = o.blockUninstall;
        domainVerificationStatus = o.domainVerificationStatus;
        appLinkGeneration = o.appLinkGeneration;
    }
}
+24 −13
Original line number Diff line number Diff line
@@ -284,7 +284,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    static final boolean DEBUG_PREFERRED = false;
    static final boolean DEBUG_UPGRADE = false;
    static final boolean DEBUG_DOMAIN_VERIFICATION = false;
    private static final boolean DEBUG_BACKUP = true;
    private static final boolean DEBUG_BACKUP = false;
    private static final boolean DEBUG_INSTALL = false;
    private static final boolean DEBUG_REMOVE = false;
    private static final boolean DEBUG_BROADCASTS = false;
@@ -4581,7 +4581,8 @@ public class PackageManagerService extends IPackageManager.Stub {
            if (ps == null) {
                continue;
            }
            int status = getDomainVerificationStatusLPr(ps, parentUserId);
            long verificationState = getDomainVerificationStatusLPr(ps, parentUserId);
            int status = (int)(verificationState >> 32);
            if (result == null) {
                result = new CrossProfileDomainInfo();
                result.resolveInfo =
@@ -4678,11 +4679,17 @@ public class PackageManagerService extends IPackageManager.Stub {
                        continue;
                    }
                    // Try to get the status from User settings first
                    int status = getDomainVerificationStatusLPr(ps, userId);
                    long packedStatus = getDomainVerificationStatusLPr(ps, userId);
                    int status = (int)(packedStatus >> 32);
                    int linkGeneration = (int)(packedStatus & 0xFFFFFFFF);
                    if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
                        if (DEBUG_DOMAIN_VERIFICATION) {
                            Slog.i(TAG, "  + always: " + info.activityInfo.packageName);
                            Slog.i(TAG, "  + always: " + info.activityInfo.packageName
                                    + " : linkgen=" + linkGeneration);
                        }
                        // Use link-enabled generation as preferredOrder, i.e.
                        // prefer newly-enabled over earlier-enabled.
                        info.preferredOrder = linkGeneration;
                        alwaysList.add(info);
                    } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
                        if (DEBUG_DOMAIN_VERIFICATION) {
@@ -4698,7 +4705,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                    }
                }
            }
            // First try to add the "always" resolution for the current user if there is any
            // First try to add the "always" resolution(s) for the current user, if any
            if (alwaysList.size() > 0) {
                result.addAll(alwaysList);
            // if there is an "always" for the parent user, add it.
@@ -4759,15 +4766,19 @@ public class PackageManagerService extends IPackageManager.Stub {
        return result;
    }
    private int getDomainVerificationStatusLPr(PackageSetting ps, int userId) {
        int status = ps.getDomainVerificationStatusForUser(userId);
    // Returns a packed value as a long:
    //
    // high 'int'-sized word: link status: undefined/ask/never/always.
    // low 'int'-sized word: relative priority among 'always' results.
    private long getDomainVerificationStatusLPr(PackageSetting ps, int userId) {
        long result = ps.getDomainVerificationStatusForUser(userId);
        // if none available, get the master status
        if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
        if (result >> 32 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
            if (ps.getIntentFilterVerificationInfo() != null) {
                status = ps.getIntentFilterVerificationInfo().getStatus();
                result = ((long)ps.getIntentFilterVerificationInfo().getStatus()) << 32;
            }
        }
        return status;
        return result;
    }
    private ResolveInfo querySkipCurrentProfileIntents(
@@ -12963,7 +12974,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                        false, //hidden
                        null, null, null,
                        false, // blockUninstall
                        INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
                        INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
                if (!isSystemApp(ps)) {
                    if (ps.isAnyInstalled(sUserManager.getUserIds())) {
                        // Other user still have this package installed, so all
@@ -14886,8 +14897,8 @@ public class PackageManagerService extends IPackageManager.Stub {
                            pw.println();
                            count = 0;
                            for (PackageSetting ps : allPackageSettings) {
                                final int status = ps.getDomainVerificationStatusForUser(userId);
                                if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
                                final long status = ps.getDomainVerificationStatusForUser(userId);
                                if (status >> 32 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
                                    continue;
                                }
                                pw.println(prefix + "Package: " + ps.name);
+18 −5
Original line number Diff line number Diff line
@@ -341,7 +341,8 @@ abstract class PackageSettingBase extends SettingBase {
    void setUserState(int userId, int enabled, boolean installed, boolean stopped,
            boolean notLaunched, boolean hidden,
            String lastDisableAppCaller, ArraySet<String> enabledComponents,
            ArraySet<String> disabledComponents, boolean blockUninstall, int domainVerifState) {
            ArraySet<String> disabledComponents, boolean blockUninstall, int domainVerifState,
            int linkGeneration) {
        PackageUserState state = modifyUserState(userId);
        state.enabled = enabled;
        state.installed = installed;
@@ -353,6 +354,7 @@ abstract class PackageSettingBase extends SettingBase {
        state.disabledComponents = disabledComponents;
        state.blockUninstall = blockUninstall;
        state.domainVerificationStatus = domainVerifState;
        state.appLinkGeneration = linkGeneration;
    }

    ArraySet<String> getEnabledComponents(int userId) {
@@ -449,12 +451,23 @@ abstract class PackageSettingBase extends SettingBase {
        verificationInfo = info;
    }

    int getDomainVerificationStatusForUser(int userId) {
        return readUserState(userId).domainVerificationStatus;
    // Returns a packed value as a long:
    //
    // high 'int'-sized word: link status: undefined/ask/never/always.
    // low 'int'-sized word: relative priority among 'always' results.
    long getDomainVerificationStatusForUser(int userId) {
        PackageUserState state = readUserState(userId);
        long result = (long) state.appLinkGeneration;
        result |= ((long) state.domainVerificationStatus) << 32;
        return result;
    }

    void setDomainVerificationStatusForUser(int status, int userId) {
        modifyUserState(userId).domainVerificationStatus = status;
    void setDomainVerificationStatusForUser(final int status, int generation, int userId) {
        PackageUserState state = modifyUserState(userId);
        state.domainVerificationStatus = status;
        if (status == PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
            state.appLinkGeneration = generation;
        }
    }

    void clearDomainVerificationStatusForUser(int userId) {
+33 −6
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.Xml;

import java.io.BufferedOutputStream;
@@ -196,6 +197,7 @@ final class Settings {
    private static final String ATTR_DOMAIN_VERIFICATON_STATE = "domainVerificationStatus";
    private static final String ATTR_PACKAGE_NAME= "packageName";
    private static final String ATTR_FINGERPRINT = "fingerprint";
    private static final String ATTR_APP_LINK_GENERATION = "app-link-generation";

    private final Object mLock;

@@ -294,6 +296,9 @@ final class Settings {
    // For every user, it is used to find the package name of the default Browser App.
    final SparseArray<String> mDefaultBrowserApp = new SparseArray<String>();

    // App-link priority tracking, per-user
    final SparseIntArray mNextAppLinkGeneration = new SparseIntArray();

    final StringBuilder mReadMessages = new StringBuilder();

    /**
@@ -624,7 +629,7 @@ final class Settings {
                                    false, // hidden
                                    null, null, null,
                                    false, // blockUninstall
                                    INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
                                    INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
                            writePackageRestrictionsLPr(user.id);
                        }
                    }
@@ -1051,7 +1056,7 @@ final class Settings {
            }
            return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
        }
        int status = ps.getDomainVerificationStatusForUser(userId);
        int status = (int)(ps.getDomainVerificationStatusForUser(userId) >> 32);
        if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
            if (ps.getIntentFilterVerificationInfo() != null) {
                status = ps.getIntentFilterVerificationInfo().getStatus();
@@ -1060,7 +1065,7 @@ final class Settings {
        return status;
    }

    boolean updateIntentFilterVerificationStatusLPw(String packageName, int status, int userId) {
    boolean updateIntentFilterVerificationStatusLPw(String packageName, final int status, int userId) {
        // Update the status for the current package
        PackageSetting current = mPackages.get(packageName);
        if (current == null) {
@@ -1070,7 +1075,15 @@ final class Settings {
            return false;
        }

        current.setDomainVerificationStatusForUser(status, userId);
        final int alwaysGeneration;
        if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
            alwaysGeneration = mNextAppLinkGeneration.get(userId) + 1;
            mNextAppLinkGeneration.put(userId, alwaysGeneration);
        } else {
            alwaysGeneration = 0;
        }

        current.setDomainVerificationStatusForUser(status, alwaysGeneration, userId);
        return true;
    }

@@ -1382,7 +1395,7 @@ final class Settings {
                                false,  // hidden
                                null, null, null,
                                false, // blockUninstall
                                INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
                                INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
                    }
                    return;
                }
@@ -1404,6 +1417,8 @@ final class Settings {
                return;
            }

            int maxAppLinkGeneration = 0;

            int outerDepth = parser.getDepth();
            PackageSetting ps = null;
            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1457,6 +1472,12 @@ final class Settings {
                            PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED :
                            Integer.parseInt(verifStateStr);

                    final String linkGenStr = parser.getAttributeValue(null, ATTR_APP_LINK_GENERATION);
                    final int linkGeneration = linkGenStr == null ? 0 : Integer.parseInt(linkGenStr);
                    if (linkGeneration > maxAppLinkGeneration) {
                        maxAppLinkGeneration = linkGeneration;
                    }

                    ArraySet<String> enabledComponents = null;
                    ArraySet<String> disabledComponents = null;

@@ -1478,7 +1499,7 @@ final class Settings {

                    ps.setUserState(userId, enabled, installed, stopped, notLaunched, hidden,
                            enabledCaller, enabledComponents, disabledComponents, blockUninstall,
                            verifState);
                            verifState, linkGeneration);
                } else if (tagName.equals("preferred-activities")) {
                    readPreferredActivitiesLPw(parser, userId);
                } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
@@ -1496,6 +1517,8 @@ final class Settings {

            str.close();

            mNextAppLinkGeneration.put(userId, maxAppLinkGeneration + 1);

        } catch (XmlPullParserException e) {
            mReadMessages.append("Error reading: " + e.toString());
            PackageManagerService.reportSettingsProblem(Log.ERROR,
@@ -1749,6 +1772,10 @@ final class Settings {
                        serializer.attribute(null, ATTR_DOMAIN_VERIFICATON_STATE,
                                Integer.toString(ustate.domainVerificationStatus));
                    }
                    if (ustate.appLinkGeneration != 0) {
                        serializer.attribute(null, ATTR_APP_LINK_GENERATION,
                                Integer.toString(ustate.appLinkGeneration));
                    }
                    if (ustate.enabledComponents != null
                            && ustate.enabledComponents.size() > 0) {
                        serializer.startTag(null, TAG_ENABLED_COMPONENTS);