diff options
3 files changed, 179 insertions, 1 deletions
diff --git a/services/core/java/com/android/server/pm/ShareTargetInfo.java b/services/core/java/com/android/server/pm/ShareTargetInfo.java index 9e8b73e36f69..fdfee773ea74 100644 --- a/services/core/java/com/android/server/pm/ShareTargetInfo.java +++ b/services/core/java/com/android/server/pm/ShareTargetInfo.java @@ -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); + } } diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index d6e87aab35fe..06c71baade42 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -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); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index 7e6b7da4a058..6c917b7f8636 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -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]); + } + } + } } |