Loading services/core/java/com/android/server/pm/ShareTargetInfo.java +92 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } } services/core/java/com/android/server/pm/ShortcutPackage.java +12 −1 Original line number Diff line number Diff line Loading @@ -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"; Loading Loading @@ -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. } Loading @@ -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); } Loading Loading @@ -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); Loading services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +75 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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]); } } } } Loading
services/core/java/com/android/server/pm/ShareTargetInfo.java +92 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } }
services/core/java/com/android/server/pm/ShortcutPackage.java +12 −1 Original line number Diff line number Diff line Loading @@ -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"; Loading Loading @@ -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. } Loading @@ -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); } Loading Loading @@ -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); Loading
services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +75 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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]); } } } }