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

Commit ffdf5b56 authored by Mehdi Alizadeh's avatar Mehdi Alizadeh Committed by Android (Google) Code Review
Browse files

Merge "Persists share targets after reading from Apps xml resource" into qt-dev

parents 16128cc7 abec3191
Loading
Loading
Loading
Loading
+92 −0
Original line number Diff line number Diff line
@@ -15,12 +15,36 @@
 */
package com.android.server.pm;

import android.annotation.NonNull;
import android.text.TextUtils;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;

import java.io.IOException;
import java.util.ArrayList;

/**
 * Represents a Share Target definition, read from the application's manifest (shortcuts.xml)
 */
class ShareTargetInfo {

    private static final String TAG_SHARE_TARGET = "share-target";
    private static final String ATTR_TARGET_CLASS = "targetClass";

    private static final String TAG_DATA = "data";
    private static final String ATTR_SCHEME = "scheme";
    private static final String ATTR_HOST = "host";
    private static final String ATTR_PORT = "port";
    private static final String ATTR_PATH = "path";
    private static final String ATTR_PATH_PATTERN = "pathPattern";
    private static final String ATTR_PATH_PREFIX = "pathPrefix";
    private static final String ATTR_MIME_TYPE = "mimeType";

    private static final String TAG_CATEGORY = "category";
    private static final String ATTR_NAME = "name";

    static class TargetData {
        final String mScheme;
        final String mHost;
@@ -98,4 +122,72 @@ class ShareTargetInfo {

        return strBuilder.toString();
    }

    void saveToXml(@NonNull XmlSerializer out) throws IOException {
        out.startTag(null, TAG_SHARE_TARGET);

        ShortcutService.writeAttr(out, ATTR_TARGET_CLASS, mTargetClass);

        for (int i = 0; i < mTargetData.length; i++) {
            out.startTag(null, TAG_DATA);
            ShortcutService.writeAttr(out, ATTR_SCHEME, mTargetData[i].mScheme);
            ShortcutService.writeAttr(out, ATTR_HOST, mTargetData[i].mHost);
            ShortcutService.writeAttr(out, ATTR_PORT, mTargetData[i].mPort);
            ShortcutService.writeAttr(out, ATTR_PATH, mTargetData[i].mPath);
            ShortcutService.writeAttr(out, ATTR_PATH_PATTERN, mTargetData[i].mPathPattern);
            ShortcutService.writeAttr(out, ATTR_PATH_PREFIX, mTargetData[i].mPathPrefix);
            ShortcutService.writeAttr(out, ATTR_MIME_TYPE, mTargetData[i].mMimeType);
            out.endTag(null, TAG_DATA);
        }

        for (int i = 0; i < mCategories.length; i++) {
            out.startTag(null, TAG_CATEGORY);
            ShortcutService.writeAttr(out, ATTR_NAME, mCategories[i]);
            out.endTag(null, TAG_CATEGORY);
        }

        out.endTag(null, TAG_SHARE_TARGET);
    }

    static ShareTargetInfo loadFromXml(XmlPullParser parser)
            throws IOException, XmlPullParserException {
        final String targetClass = ShortcutService.parseStringAttribute(parser, ATTR_TARGET_CLASS);
        final ArrayList<ShareTargetInfo.TargetData> targetData = new ArrayList<>();
        final ArrayList<String> categories = new ArrayList<>();

        int type;
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
            if (type == XmlPullParser.START_TAG) {
                switch (parser.getName()) {
                    case TAG_DATA:
                        targetData.add(parseTargetData(parser));
                        break;
                    case TAG_CATEGORY:
                        categories.add(ShortcutService.parseStringAttribute(parser, ATTR_NAME));
                        break;
                }
            } else if (type == XmlPullParser.END_TAG && parser.getName().equals(TAG_SHARE_TARGET)) {
                break;
            }
        }
        if (targetData.isEmpty() || targetClass == null || categories.isEmpty()) {
            return null;
        }
        return new ShareTargetInfo(
                targetData.toArray(new ShareTargetInfo.TargetData[targetData.size()]),
                targetClass, categories.toArray(new String[categories.size()]));
    }

    private static ShareTargetInfo.TargetData parseTargetData(XmlPullParser parser) {
        final String scheme = ShortcutService.parseStringAttribute(parser, ATTR_SCHEME);
        final String host = ShortcutService.parseStringAttribute(parser, ATTR_HOST);
        final String port = ShortcutService.parseStringAttribute(parser, ATTR_PORT);
        final String path = ShortcutService.parseStringAttribute(parser, ATTR_PATH);
        final String pathPattern = ShortcutService.parseStringAttribute(parser, ATTR_PATH_PATTERN);
        final String pathPrefix = ShortcutService.parseStringAttribute(parser, ATTR_PATH_PREFIX);
        final String mimeType = ShortcutService.parseStringAttribute(parser, ATTR_MIME_TYPE);

        return new ShareTargetInfo.TargetData(scheme, host, port, path, pathPattern, pathPrefix,
                mimeType);
    }
}
+12 −1
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ class ShortcutPackage extends ShortcutPackageItem {
    private static final String TAG_INTENT = "intent";
    private static final String TAG_EXTRAS = "extras";
    private static final String TAG_SHORTCUT = "shortcut";
    private static final String TAG_SHARE_TARGET = "share-target";
    private static final String TAG_CATEGORIES = "categories";
    private static final String TAG_PERSON = "person";

@@ -1453,8 +1454,9 @@ class ShortcutPackage extends ShortcutPackageItem {
    public void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
            throws IOException, XmlPullParserException {
        final int size = mShortcuts.size();
        final int shareTargetSize = mShareTargets.size();

        if (size == 0 && mApiCallCount == 0) {
        if (size == 0 && shareTargetSize == 0 && mApiCallCount == 0) {
            return; // nothing to write.
        }

@@ -1470,6 +1472,12 @@ class ShortcutPackage extends ShortcutPackageItem {
                    getPackageInfo().isBackupAllowed());
        }

        if (!forBackup) {
            for (int j = 0; j < shareTargetSize; j++) {
                mShareTargets.get(j).saveToXml(out);
            }
        }

        out.endTag(null, TAG_ROOT);
    }

@@ -1627,6 +1635,9 @@ class ShortcutPackage extends ShortcutPackageItem {
                        // Don't use addShortcut(), we don't need to save the icon.
                        ret.mShortcuts.put(si.getId(), si);
                        continue;
                    case TAG_SHARE_TARGET:
                        ret.mShareTargets.add(ShareTargetInfo.loadFromXml(parser));
                        continue;
                }
            }
            ShortcutService.warnForInvalidTag(depth, tag);
+75 −0
Original line number Diff line number Diff line
@@ -97,16 +97,25 @@ import android.os.UserHandle;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import android.util.SparseArray;
import android.util.Xml;

import com.android.frameworks.servicestests.R;
import com.android.internal.util.FastXmlSerializer;
import com.android.server.pm.ShortcutService.ConfigConstants;
import com.android.server.pm.ShortcutService.FileOutputStreamWithPath;
import com.android.server.pm.ShortcutUser.PackageWithUser;

import org.mockito.ArgumentCaptor;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -8089,4 +8098,70 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
            }
        }
    }

    public void testShareTargetInfo_saveToXml() throws IOException, XmlPullParserException {
        List<ShareTargetInfo> expectedValues = new ArrayList<>();
        expectedValues.add(new ShareTargetInfo(
                new ShareTargetInfo.TargetData[]{new ShareTargetInfo.TargetData(
                        "http", "www.google.com", "1234", "somePath", "somePathPattern",
                        "somePathPrefix", "text/plain")}, "com.test.directshare.TestActivity1",
                new String[]{"com.test.category.CATEGORY1", "com.test.category.CATEGORY2"}));
        expectedValues.add(new ShareTargetInfo(new ShareTargetInfo.TargetData[]{
                new ShareTargetInfo.TargetData(null, null, null, null, null, null, "video/mp4"),
                new ShareTargetInfo.TargetData("content", null, null, null, null, null, "video/*")},
                "com.test.directshare.TestActivity5",
                new String[]{"com.test.category.CATEGORY5", "com.test.category.CATEGORY6"}));

        // Write ShareTargets to Xml
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        final XmlSerializer outXml = new FastXmlSerializer();
        outXml.setOutput(outStream, StandardCharsets.UTF_8.name());
        outXml.startDocument(null, true);
        for (int i = 0; i < expectedValues.size(); i++) {
            expectedValues.get(i).saveToXml(outXml);
        }
        outXml.endDocument();
        outXml.flush();

        // Read ShareTargets from Xml
        ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
        XmlPullParser parser = Xml.newPullParser();
        parser.setInput(new InputStreamReader(inStream));
        List<ShareTargetInfo> shareTargets = new ArrayList<>();
        int type;
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
            if (type == XmlPullParser.START_TAG && parser.getName().equals("share-target")) {
                shareTargets.add(ShareTargetInfo.loadFromXml(parser));
            }
        }

        // Assert two lists are equal
        assertNotNull(shareTargets);
        assertEquals(expectedValues.size(), shareTargets.size());

        for (int i = 0; i < expectedValues.size(); i++) {
            ShareTargetInfo expected = expectedValues.get(i);
            ShareTargetInfo actual = shareTargets.get(i);

            assertEquals(expected.mTargetData.length, actual.mTargetData.length);
            for (int j = 0; j < expected.mTargetData.length; j++) {
                assertEquals(expected.mTargetData[j].mScheme, actual.mTargetData[j].mScheme);
                assertEquals(expected.mTargetData[j].mHost, actual.mTargetData[j].mHost);
                assertEquals(expected.mTargetData[j].mPort, actual.mTargetData[j].mPort);
                assertEquals(expected.mTargetData[j].mPath, actual.mTargetData[j].mPath);
                assertEquals(expected.mTargetData[j].mPathPrefix,
                        actual.mTargetData[j].mPathPrefix);
                assertEquals(expected.mTargetData[j].mPathPattern,
                        actual.mTargetData[j].mPathPattern);
                assertEquals(expected.mTargetData[j].mMimeType, actual.mTargetData[j].mMimeType);
            }

            assertEquals(expected.mTargetClass, actual.mTargetClass);

            assertEquals(expected.mCategories.length, actual.mCategories.length);
            for (int j = 0; j < expected.mCategories.length; j++) {
                assertEquals(expected.mCategories[j], actual.mCategories[j]);
            }
        }
    }
}