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

Commit 71a1c2a2 authored by Mehdi Alizadeh's avatar Mehdi Alizadeh Committed by android-build-merger
Browse files

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

am: ffdf5b56

Change-Id: I5621dabde0db72cea7f8b1c3335801e78ab5a2c5
parents 4f7f78cc ffdf5b56
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]);
            }
        }
    }
}