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

This commit is contained in:
Mehdi Alizadeh
2019-06-29 04:47:23 +00:00
committed by Android (Google) Code Review
3 changed files with 179 additions and 1 deletions

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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]);
}
}
}
}