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