SliceXml.java revision 3ec422a2e2a46b51d4cc6926fcaa35caacbdf98d
1901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk/*
2901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk * Copyright 2017 The Android Open Source Project
3901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk *
4901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk * Licensed under the Apache License, Version 2.0 (the "License");
5901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk * you may not use this file except in compliance with the License.
6901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk * You may obtain a copy of the License at
7901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk *
8901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk *      http://www.apache.org/licenses/LICENSE-2.0
9901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk *
10901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk * Unless required by applicable law or agreed to in writing, software
11901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk * distributed under the License is distributed on an "AS IS" BASIS,
12901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk * See the License for the specific language governing permissions and
14901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk * limitations under the License.
15901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk */
16901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
1785ef1446b82c8783a50af92c4cb1389fe0d0e907Aurimas Liutikaspackage androidx.slice;
18901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
19901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkimport static org.xmlpull.v1.XmlPullParser.START_TAG;
20901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkimport static org.xmlpull.v1.XmlPullParser.TEXT;
21901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
22901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkimport android.annotation.SuppressLint;
23901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkimport android.content.Context;
24901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkimport android.graphics.Bitmap;
25901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkimport android.graphics.drawable.Drawable;
26901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkimport android.net.Uri;
27901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkimport android.text.Html;
28901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkimport android.text.Spanned;
29901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkimport android.text.TextUtils;
30901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
313ec422a2e2a46b51d4cc6926fcaa35caacbdf98dJason Monkimport androidx.annotation.RestrictTo;
323ec422a2e2a46b51d4cc6926fcaa35caacbdf98dJason Monkimport androidx.core.graphics.drawable.IconCompat;
333ec422a2e2a46b51d4cc6926fcaa35caacbdf98dJason Monk
34901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkimport org.xmlpull.v1.XmlPullParser;
35901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkimport org.xmlpull.v1.XmlPullParserException;
36901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkimport org.xmlpull.v1.XmlPullParserFactory;
37901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkimport org.xmlpull.v1.XmlSerializer;
38901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
39901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkimport java.io.IOException;
40901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkimport java.io.InputStream;
41901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkimport java.io.OutputStream;
42901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkimport java.util.List;
43901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
44901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk/**
45901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk * @hide
46901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk */
47901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk@RestrictTo(RestrictTo.Scope.LIBRARY)
48901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monkclass SliceXml {
49901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
50901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    private static final String NAMESPACE = null;
51901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
52901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    private static final String TAG_SLICE = "slice";
53901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    private static final String TAG_ITEM = "item";
54901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
55901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    private static final String ATTR_URI = "uri";
56901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    private static final String ATTR_FORMAT = "format";
57901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    private static final String ATTR_SUBTYPE = "subtype";
58901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    private static final String ATTR_HINTS = "hints";
59901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
60901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    public static Slice parseSlice(InputStream input, String encoding) throws IOException {
61901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        try {
62901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
63901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            parser.setInput(input, encoding);
64901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
65901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            int outerDepth = parser.getDepth();
66901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            int type;
67901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            Slice s = null;
68901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
69901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
70901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                if (type != START_TAG) {
71901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                    continue;
72901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                }
73901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                s = parseSlice(parser);
74901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            }
75901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            return s;
76901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        } catch (XmlPullParserException e) {
77901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            throw new IOException("Unable to init XML Serialization", e);
78901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        }
79901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    }
80901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
81901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    @SuppressLint("WrongConstant")
82901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    private static Slice parseSlice(XmlPullParser parser)
83901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            throws IOException, XmlPullParserException {
84901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        if (!TAG_SLICE.equals(parser.getName())) {
85901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            throw new IOException("Unexpected tag " + parser.getName());
86901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        }
87901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        int outerDepth = parser.getDepth();
88901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        int type;
89901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        String uri = parser.getAttributeValue(NAMESPACE, ATTR_URI);
90901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        Slice.Builder b = new Slice.Builder(Uri.parse(uri));
91901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        String[] hints = hints(parser.getAttributeValue(NAMESPACE, ATTR_HINTS));
92901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        b.addHints(hints);
93901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
94901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
95901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
96901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            if (type == START_TAG && TAG_ITEM.equals(parser.getName())) {
97901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                parseItem(b, parser);
98901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            }
99901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        }
100901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        return b.build();
101901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    }
102901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
103901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    @SuppressLint("WrongConstant")
104901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    private static void parseItem(Slice.Builder b, XmlPullParser parser)
105901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            throws IOException, XmlPullParserException {
106901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        int type;
107901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        int outerDepth = parser.getDepth();
108901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        String format = parser.getAttributeValue(NAMESPACE, ATTR_FORMAT);
109901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        String subtype = parser.getAttributeValue(NAMESPACE, ATTR_SUBTYPE);
110901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        String hintStr = parser.getAttributeValue(NAMESPACE, ATTR_HINTS);
111901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        String[] hints = hints(hintStr);
112901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        String v;
113901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
114901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
115901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            if (type == TEXT) {
116901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                switch (format) {
117901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                    case android.app.slice.SliceItem.FORMAT_REMOTE_INPUT:
118901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                        // Nothing for now.
119901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                        break;
120901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                    case android.app.slice.SliceItem.FORMAT_IMAGE:
121901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                        v = parser.getText();
122901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                        if (!TextUtils.isEmpty(v)) {
123901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                            if (android.os.Build.VERSION.SDK_INT
124901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                                    >= android.os.Build.VERSION_CODES.M) {
125901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                                String[] split = v.split(",");
126901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                                int w = Integer.parseInt(split[0]);
127901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                                int h = Integer.parseInt(split[1]);
128901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                                Bitmap image = Bitmap.createBitmap(w, h, Bitmap.Config.ALPHA_8);
1293ec422a2e2a46b51d4cc6926fcaa35caacbdf98dJason Monk                                b.addIcon(IconCompat.createWithBitmap(image), subtype, hints);
130901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                            }
131901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                        }
132901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                        break;
133901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                    case android.app.slice.SliceItem.FORMAT_INT:
134901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                        v = parser.getText();
135901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                        b.addInt(Integer.parseInt(v), subtype, hints);
136901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                        break;
137901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                    case android.app.slice.SliceItem.FORMAT_TEXT:
138901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                        v = parser.getText();
139901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                        b.addText(Html.fromHtml(v), subtype, hints);
140901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                        break;
141901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                    case android.app.slice.SliceItem.FORMAT_TIMESTAMP:
142901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                        v = parser.getText();
143901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                        b.addTimestamp(Long.parseLong(v), subtype, hints);
144901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                        break;
145901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                    default:
146901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                        throw new IllegalArgumentException("Unrecognized format " + format);
147901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                }
148901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            } else if (type == START_TAG && TAG_SLICE.equals(parser.getName())) {
149901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                b.addSubSlice(parseSlice(parser), subtype);
150901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            }
151901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        }
152901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    }
153901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
154901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    private static String[] hints(String hintStr) {
155901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        return TextUtils.isEmpty(hintStr) ? new String[0] : hintStr.split(",");
156901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    }
157901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
158901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    public static void serializeSlice(Slice s, Context context, OutputStream output,
159901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            String encoding, SliceUtils.SerializeOptions options) throws IOException {
160901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        try {
161901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            XmlSerializer serializer = XmlPullParserFactory.newInstance().newSerializer();
162901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            serializer.setOutput(output, encoding);
163901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            serializer.startDocument(encoding, null);
164901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
165901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            serialize(s, context, options, serializer);
166901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
167901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            serializer.endDocument();
168901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            serializer.flush();
169901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        } catch (XmlPullParserException e) {
170901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            throw new IOException("Unable to init XML Serialization", e);
171901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        }
172901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    }
173901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
174901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    private static void serialize(Slice s, Context context, SliceUtils.SerializeOptions options,
175901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            XmlSerializer serializer) throws IOException {
176901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        serializer.startTag(NAMESPACE, TAG_SLICE);
177901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        serializer.attribute(NAMESPACE, ATTR_URI, s.getUri().toString());
178901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        if (!s.getHints().isEmpty()) {
179901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            serializer.attribute(NAMESPACE, ATTR_HINTS, hintStr(s.getHints()));
180901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        }
181901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        for (SliceItem item : s.getItems()) {
182901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            serialize(item, context, options, serializer);
183901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        }
184901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
185901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        serializer.endTag(NAMESPACE, TAG_SLICE);
186901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    }
187901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
188901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    private static void serialize(SliceItem item, Context context,
189901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            SliceUtils.SerializeOptions options, XmlSerializer serializer) throws IOException {
190901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        String format = item.getFormat();
191901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        options.checkThrow(format);
192901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
193901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        serializer.startTag(NAMESPACE, TAG_ITEM);
194901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        serializer.attribute(NAMESPACE, ATTR_FORMAT, format);
195901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        if (item.getSubType() != null) {
196901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            serializer.attribute(NAMESPACE, ATTR_SUBTYPE, item.getSubType());
197901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        }
198901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        if (!item.getHints().isEmpty()) {
199901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            serializer.attribute(NAMESPACE, ATTR_HINTS, hintStr(item.getHints()));
200901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        }
201901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
202901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        switch (format) {
203901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            case android.app.slice.SliceItem.FORMAT_ACTION:
204901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                if (options.getActionMode() == SliceUtils.SerializeOptions.MODE_DISABLE) {
205901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                    serialize(item.getSlice(), context, options, serializer);
206901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                }
207901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                break;
208901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            case android.app.slice.SliceItem.FORMAT_REMOTE_INPUT:
209901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                // Nothing for now.
210901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                break;
211901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            case android.app.slice.SliceItem.FORMAT_IMAGE:
212901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                if (options.getImageMode() == SliceUtils.SerializeOptions.MODE_DISABLE) {
213901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
214901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                        Drawable d = item.getIcon().loadDrawable(context);
215901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                        serializer.text(String.format("%d,%d",
216901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                                d.getIntrinsicWidth(), d.getIntrinsicHeight()));
217901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                    }
218901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                }
219901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                break;
220901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            case android.app.slice.SliceItem.FORMAT_INT:
221901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                serializer.text(String.valueOf(item.getInt()));
222901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                break;
223901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            case android.app.slice.SliceItem.FORMAT_SLICE:
224901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                serialize(item.getSlice(), context, options, serializer);
225901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                break;
226901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            case android.app.slice.SliceItem.FORMAT_TEXT:
227901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                if (item.getText() instanceof Spanned) {
228901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                    serializer.text(Html.toHtml((Spanned) item.getText()));
229901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                } else {
230901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                    serializer.text(String.valueOf(item.getText()));
231901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                }
232901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                break;
233901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            case android.app.slice.SliceItem.FORMAT_TIMESTAMP:
234901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                serializer.text(String.valueOf(item.getTimestamp()));
235901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                break;
236901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk            default:
237901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk                throw new IllegalArgumentException("Unrecognized format " + format);
238901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        }
239901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        serializer.endTag(NAMESPACE, TAG_ITEM);
240901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    }
241901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk
242901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    private static String hintStr(List<String> hints) {
243901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk        return TextUtils.join(",", hints);
244901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk    }
245901e2a634a8fce0c5e5acaa369e4e69326980b96Jason Monk}
246