1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.server.pm; 17 18 import android.annotation.NonNull; 19 import android.text.TextUtils; 20 21 import org.xmlpull.v1.XmlPullParser; 22 import org.xmlpull.v1.XmlPullParserException; 23 import org.xmlpull.v1.XmlSerializer; 24 25 import java.io.IOException; 26 import java.util.ArrayList; 27 28 /** 29 * Represents a Share Target definition, read from the application's manifest (shortcuts.xml) 30 */ 31 class ShareTargetInfo { 32 33 private static final String TAG_SHARE_TARGET = "share-target"; 34 private static final String ATTR_TARGET_CLASS = "targetClass"; 35 36 private static final String TAG_DATA = "data"; 37 private static final String ATTR_SCHEME = "scheme"; 38 private static final String ATTR_HOST = "host"; 39 private static final String ATTR_PORT = "port"; 40 private static final String ATTR_PATH = "path"; 41 private static final String ATTR_PATH_PATTERN = "pathPattern"; 42 private static final String ATTR_PATH_PREFIX = "pathPrefix"; 43 private static final String ATTR_MIME_TYPE = "mimeType"; 44 45 private static final String TAG_CATEGORY = "category"; 46 private static final String ATTR_NAME = "name"; 47 48 static class TargetData { 49 final String mScheme; 50 final String mHost; 51 final String mPort; 52 final String mPath; 53 final String mPathPattern; 54 final String mPathPrefix; 55 final String mMimeType; 56 TargetData(String scheme, String host, String port, String path, String pathPattern, String pathPrefix, String mimeType)57 TargetData(String scheme, String host, String port, String path, String pathPattern, 58 String pathPrefix, String mimeType) { 59 mScheme = scheme; 60 mHost = host; 61 mPort = port; 62 mPath = path; 63 mPathPattern = pathPattern; 64 mPathPrefix = pathPrefix; 65 mMimeType = mimeType; 66 } 67 toStringInner(StringBuilder strBuilder)68 public void toStringInner(StringBuilder strBuilder) { 69 if (!TextUtils.isEmpty(mScheme)) { 70 strBuilder.append(" scheme=").append(mScheme); 71 } 72 if (!TextUtils.isEmpty(mHost)) { 73 strBuilder.append(" host=").append(mHost); 74 } 75 if (!TextUtils.isEmpty(mPort)) { 76 strBuilder.append(" port=").append(mPort); 77 } 78 if (!TextUtils.isEmpty(mPath)) { 79 strBuilder.append(" path=").append(mPath); 80 } 81 if (!TextUtils.isEmpty(mPathPattern)) { 82 strBuilder.append(" pathPattern=").append(mPathPattern); 83 } 84 if (!TextUtils.isEmpty(mPathPrefix)) { 85 strBuilder.append(" pathPrefix=").append(mPathPrefix); 86 } 87 if (!TextUtils.isEmpty(mMimeType)) { 88 strBuilder.append(" mimeType=").append(mMimeType); 89 } 90 } 91 92 @Override toString()93 public String toString() { 94 StringBuilder strBuilder = new StringBuilder(); 95 toStringInner(strBuilder); 96 return strBuilder.toString(); 97 } 98 } 99 100 final TargetData[] mTargetData; 101 final String mTargetClass; 102 final String[] mCategories; 103 ShareTargetInfo(TargetData[] data, String targetClass, String[] categories)104 ShareTargetInfo(TargetData[] data, String targetClass, String[] categories) { 105 mTargetData = data; 106 mTargetClass = targetClass; 107 mCategories = categories; 108 } 109 110 @Override toString()111 public String toString() { 112 StringBuilder strBuilder = new StringBuilder(); 113 strBuilder.append("targetClass=").append(mTargetClass); 114 for (int i = 0; i < mTargetData.length; i++) { 115 strBuilder.append(" data={"); 116 mTargetData[i].toStringInner(strBuilder); 117 strBuilder.append("}"); 118 } 119 for (int i = 0; i < mCategories.length; i++) { 120 strBuilder.append(" category=").append(mCategories[i]); 121 } 122 123 return strBuilder.toString(); 124 } 125 saveToXml(@onNull XmlSerializer out)126 void saveToXml(@NonNull XmlSerializer out) throws IOException { 127 out.startTag(null, TAG_SHARE_TARGET); 128 129 ShortcutService.writeAttr(out, ATTR_TARGET_CLASS, mTargetClass); 130 131 for (int i = 0; i < mTargetData.length; i++) { 132 out.startTag(null, TAG_DATA); 133 ShortcutService.writeAttr(out, ATTR_SCHEME, mTargetData[i].mScheme); 134 ShortcutService.writeAttr(out, ATTR_HOST, mTargetData[i].mHost); 135 ShortcutService.writeAttr(out, ATTR_PORT, mTargetData[i].mPort); 136 ShortcutService.writeAttr(out, ATTR_PATH, mTargetData[i].mPath); 137 ShortcutService.writeAttr(out, ATTR_PATH_PATTERN, mTargetData[i].mPathPattern); 138 ShortcutService.writeAttr(out, ATTR_PATH_PREFIX, mTargetData[i].mPathPrefix); 139 ShortcutService.writeAttr(out, ATTR_MIME_TYPE, mTargetData[i].mMimeType); 140 out.endTag(null, TAG_DATA); 141 } 142 143 for (int i = 0; i < mCategories.length; i++) { 144 out.startTag(null, TAG_CATEGORY); 145 ShortcutService.writeAttr(out, ATTR_NAME, mCategories[i]); 146 out.endTag(null, TAG_CATEGORY); 147 } 148 149 out.endTag(null, TAG_SHARE_TARGET); 150 } 151 loadFromXml(XmlPullParser parser)152 static ShareTargetInfo loadFromXml(XmlPullParser parser) 153 throws IOException, XmlPullParserException { 154 final String targetClass = ShortcutService.parseStringAttribute(parser, ATTR_TARGET_CLASS); 155 final ArrayList<ShareTargetInfo.TargetData> targetData = new ArrayList<>(); 156 final ArrayList<String> categories = new ArrayList<>(); 157 158 int type; 159 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { 160 if (type == XmlPullParser.START_TAG) { 161 switch (parser.getName()) { 162 case TAG_DATA: 163 targetData.add(parseTargetData(parser)); 164 break; 165 case TAG_CATEGORY: 166 categories.add(ShortcutService.parseStringAttribute(parser, ATTR_NAME)); 167 break; 168 } 169 } else if (type == XmlPullParser.END_TAG && parser.getName().equals(TAG_SHARE_TARGET)) { 170 break; 171 } 172 } 173 if (targetData.isEmpty() || targetClass == null || categories.isEmpty()) { 174 return null; 175 } 176 return new ShareTargetInfo( 177 targetData.toArray(new ShareTargetInfo.TargetData[targetData.size()]), 178 targetClass, categories.toArray(new String[categories.size()])); 179 } 180 parseTargetData(XmlPullParser parser)181 private static ShareTargetInfo.TargetData parseTargetData(XmlPullParser parser) { 182 final String scheme = ShortcutService.parseStringAttribute(parser, ATTR_SCHEME); 183 final String host = ShortcutService.parseStringAttribute(parser, ATTR_HOST); 184 final String port = ShortcutService.parseStringAttribute(parser, ATTR_PORT); 185 final String path = ShortcutService.parseStringAttribute(parser, ATTR_PATH); 186 final String pathPattern = ShortcutService.parseStringAttribute(parser, ATTR_PATH_PATTERN); 187 final String pathPrefix = ShortcutService.parseStringAttribute(parser, ATTR_PATH_PREFIX); 188 final String mimeType = ShortcutService.parseStringAttribute(parser, ATTR_MIME_TYPE); 189 190 return new ShareTargetInfo.TargetData(scheme, host, port, path, pathPattern, pathPrefix, 191 mimeType); 192 } 193 } 194