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

Commit 3f4b1ca9 authored by Makoto Onuki's avatar Makoto Onuki
Browse files

ShortcutManager refactor: per-user information class

Bug 27548047

Change-Id: Id6de8bfbad6281daec5e89be85ba8b140b599268
parent d51b363c
Loading
Loading
Loading
Loading
+91 −73
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

/**
@@ -149,6 +150,7 @@ public class ShortcutService extends IShortcutService.Stub {
    static final String DIRECTORY_BITMAPS = "bitmaps";

    static final String TAG_ROOT = "root";
    static final String TAG_USER = "user";
    static final String TAG_PACKAGE = "package";
    static final String TAG_LAST_RESET_TIME = "last_reset_time";
    static final String TAG_INTENT_EXTRAS = "intent-extras";
@@ -221,11 +223,10 @@ public class ShortcutService extends IShortcutService.Stub {
    private long mRawLastResetTime;

    /**
     * User ID -> package name -> list of ShortcutInfos.
     * User ID -> UserShortcuts
     */
    @GuardedBy("mLock")
    private final SparseArray<ArrayMap<String, PackageShortcuts>> mShortcuts =
            new SparseArray<>();
    private final SparseArray<UserShortcuts> mUsers = new SparseArray<>();

    /**
     * Max number of dynamic shortcuts that each application can have at a time.
@@ -313,7 +314,7 @@ public class ShortcutService extends IShortcutService.Stub {
    /** lifecycle event */
    void onCleanupUserInner(int userId) {
        // Unload
        mShortcuts.delete(userId);
        mUsers.delete(userId);
    }

    /** Return the base state file name */
@@ -583,20 +584,9 @@ public class ShortcutService extends IShortcutService.Stub {
            XmlSerializer out = new FastXmlSerializer();
            out.setOutput(outs, StandardCharsets.UTF_8.name());
            out.startDocument(null, true);
            out.startTag(null, TAG_ROOT);

            final ArrayMap<String, PackageShortcuts> packages = getUserShortcutsLocked(userId);

            // Body.
            for (int i = 0; i < packages.size(); i++) {
                final String packageName = packages.keyAt(i);
                final PackageShortcuts packageShortcuts = packages.valueAt(i);

                packageShortcuts.saveToXml(out);
            }
            getUserShortcutsLocked(userId).saveToXml(out);

            // Epilogue.
            out.endTag(null, TAG_ROOT);
            out.endDocument();

            // Close.
@@ -612,7 +602,7 @@ public class ShortcutService extends IShortcutService.Stub {
    }

    @Nullable
    private ArrayMap<String, PackageShortcuts> loadUserLocked(@UserIdInt int userId) {
    private UserShortcuts loadUserLocked(@UserIdInt int userId) {
        final File path = new File(injectUserDataPath(userId), FILENAME_USER_PACKAGES);
        if (DEBUG) {
            Slog.i(TAG, "Loading from " + path);
@@ -628,13 +618,11 @@ public class ShortcutService extends IShortcutService.Stub {
            }
            return null;
        }
        final ArrayMap<String, PackageShortcuts> ret = new ArrayMap<>();
        UserShortcuts ret = null;
        try {
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(in, StandardCharsets.UTF_8.name());

            PackageShortcuts shortcuts = null;

            int type;
            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
                if (type != XmlPullParser.START_TAG) {
@@ -647,23 +635,10 @@ public class ShortcutService extends IShortcutService.Stub {
                    Slog.d(TAG, String.format("depth=%d type=%d name=%s",
                            depth, type, tag));
                }
                switch (depth) {
                    case 1: {
                        if (TAG_ROOT.equals(tag)) {
                if ((depth == 1) && TAG_USER.equals(tag)) {
                    ret = UserShortcuts.loadFromXml(parser, userId);
                    continue;
                }
                        break;
                    }
                    case 2: {
                        switch (tag) {
                            case TAG_PACKAGE:
                                shortcuts = PackageShortcuts.loadFromXml(parser, userId);
                                ret.put(shortcuts.mPackageName, shortcuts);
                                continue;
                        }
                        break;
                    }
                }
                throwForInvalidTag(depth, tag);
            }
            return ret;
@@ -731,14 +706,14 @@ public class ShortcutService extends IShortcutService.Stub {
    /** Return the per-user state. */
    @GuardedBy("mLock")
    @NonNull
    private ArrayMap<String, PackageShortcuts> getUserShortcutsLocked(@UserIdInt int userId) {
        ArrayMap<String, PackageShortcuts> userPackages = mShortcuts.get(userId);
    private UserShortcuts getUserShortcutsLocked(@UserIdInt int userId) {
        UserShortcuts userPackages = mUsers.get(userId);
        if (userPackages == null) {
            userPackages = loadUserLocked(userId);
            if (userPackages == null) {
                userPackages = new ArrayMap<>();
                userPackages = new UserShortcuts(userId);
            }
            mShortcuts.put(userId, userPackages);
            mUsers.put(userId, userPackages);
        }
        return userPackages;
    }
@@ -748,11 +723,11 @@ public class ShortcutService extends IShortcutService.Stub {
    @NonNull
    private PackageShortcuts getPackageShortcutsLocked(
            @NonNull String packageName, @UserIdInt int userId) {
        final ArrayMap<String, PackageShortcuts> userPackages = getUserShortcutsLocked(userId);
        PackageShortcuts shortcuts = userPackages.get(packageName);
        final UserShortcuts userPackages = getUserShortcutsLocked(userId);
        PackageShortcuts shortcuts = userPackages.getPackages().get(packageName);
        if (shortcuts == null) {
            shortcuts = new PackageShortcuts(userId, packageName);
            userPackages.put(packageName, shortcuts);
            userPackages.getPackages().put(packageName, shortcuts);
        }
        return shortcuts;
    }
@@ -1335,7 +1310,7 @@ public class ShortcutService extends IShortcutService.Stub {
                            userId, ret, cloneFlag);
                } else {
                    final ArrayMap<String, PackageShortcuts> packages =
                            getUserShortcutsLocked(userId);
                            getUserShortcutsLocked(userId).getPackages();
                    for (int i = packages.size() - 1; i >= 0; i--) {
                        getShortcutsInnerLocked(
                                packages.keyAt(i),
@@ -1512,36 +1487,12 @@ public class ShortcutService extends IShortcutService.Stub {
            pw.print(mIconPersistQuality);
            pw.println();

            pw.println();

            for (int i = 0; i < mShortcuts.size(); i++) {
                dumpUserLocked(pw, mShortcuts.keyAt(i));
            }
        }
    }

    private void dumpUserLocked(PrintWriter pw, int userId) {
        pw.print("  User: ");
        pw.print(userId);
        pw.println();

        final ArrayMap<String, PackageShortcuts> packages = mShortcuts.get(userId);
        if (packages == null) {
            return;
        }
        for (int j = 0; j < packages.size(); j++) {
            dumpPackageLocked(pw, userId, packages.keyAt(j));
        }
            for (int i = 0; i < mUsers.size(); i++) {
                pw.println();
                mUsers.valueAt(i).dump(this, pw, "  ");
            }

    private void dumpPackageLocked(PrintWriter pw, int userId, String packageName) {
        final PackageShortcuts packageShortcuts = mShortcuts.get(userId).get(packageName);
        if (packageShortcuts == null) {
            return;
        }

        packageShortcuts.dump(this, pw, "    ");
    }

    static String formatTime(long time) {
@@ -1694,8 +1645,8 @@ public class ShortcutService extends IShortcutService.Stub {
    }

    @VisibleForTesting
    SparseArray<ArrayMap<String, PackageShortcuts>> getShortcutsForTest() {
        return mShortcuts;
    SparseArray<UserShortcuts> getShortcutsForTest() {
        return mUsers;
    }

    @VisibleForTesting
@@ -1736,6 +1687,73 @@ public class ShortcutService extends IShortcutService.Stub {
    }
}

class UserShortcuts {
    private static final String TAG = ShortcutService.TAG;

    @UserIdInt
    final int mUserId;

    private final ArrayMap<String, PackageShortcuts> mPackages = new ArrayMap<>();

    public UserShortcuts(int userId) {
        mUserId = userId;
    }

    public ArrayMap<String, PackageShortcuts> getPackages() {
        return mPackages;
    }

    public void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
        out.startTag(null, ShortcutService.TAG_USER);

        for (int i = 0; i < mPackages.size(); i++) {
            final String packageName = mPackages.keyAt(i);
            final PackageShortcuts packageShortcuts = mPackages.valueAt(i);

            packageShortcuts.saveToXml(out);
        }

        out.endTag(null, ShortcutService.TAG_USER);
    }

    public static UserShortcuts loadFromXml(XmlPullParser parser, int userId)
            throws IOException, XmlPullParserException {
        final UserShortcuts ret = new UserShortcuts(userId);

        final int outerDepth = parser.getDepth();
        int type;
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
            if (type != XmlPullParser.START_TAG) {
                continue;
            }
            final int depth = parser.getDepth();
            final String tag = parser.getName();
            switch (tag) {
                case ShortcutService.TAG_PACKAGE:
                    final PackageShortcuts shortcuts = PackageShortcuts.loadFromXml(parser, userId);

                    // Don't use addShortcut(), we don't need to save the icon.
                    ret.getPackages().put(shortcuts.mPackageName, shortcuts);
                    continue;
            }
            throw ShortcutService.throwForInvalidTag(depth, tag);
        }
        return ret;
    }

    public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) {
        pw.print("  ");
        pw.print("User: ");
        pw.print(mUserId);
        pw.println();

        for (int i = 0; i < mPackages.size(); i++) {
            mPackages.valueAt(i).dump(s, pw, prefix + "  ");
        }
    }
}

/**
 * All the information relevant to shortcuts from a single package (per-user).
 */