blob: 19295fcf20f6f3d770a4e1fcc522e192ccdab4f0 [file] [log] [blame]
Dianne Hackborn1040dc42010-08-26 22:11:06 -07001/**
2 * Copyright (c) 2010, 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
17package android.content;
18
19import android.os.Parcel;
20import android.os.Parcelable;
Vladislav Kaznacheevddb4bde2015-11-24 11:24:12 -080021import android.os.PersistableBundle;
Dianne Hackborn1040dc42010-08-26 22:11:06 -070022import android.text.TextUtils;
Sudheer Shanka09971be2017-01-18 13:37:02 -080023import android.util.TimeUtils;
Kweku Adams85f2fbc2017-12-18 12:04:12 -080024import android.util.proto.ProtoOutputStream;
Dianne Hackborn1040dc42010-08-26 22:11:06 -070025
26import java.util.ArrayList;
Vladislav Kaznacheev8e7b9402016-11-23 15:31:13 -080027import java.util.Arrays;
Dianne Hackborn1040dc42010-08-26 22:11:06 -070028
29/**
Dianne Hackbornf6d952b2010-08-27 15:41:13 -070030 * Meta-data describing the contents of a {@link ClipData}. Provides enough
Dianne Hackborn1040dc42010-08-26 22:11:06 -070031 * information to know if you can handle the ClipData, but not the data
32 * itself.
Joe Fernandez3aef8e1d2011-12-20 10:38:34 -080033 *
34 * <div class="special reference">
35 * <h3>Developer Guides</h3>
36 * <p>For more information about using the clipboard framework, read the
37 * <a href="{@docRoot}guide/topics/clipboard/copy-paste.html">Copy and Paste</a>
38 * developer guide.</p>
39 * </div>
Dianne Hackborn1040dc42010-08-26 22:11:06 -070040 */
41public class ClipDescription implements Parcelable {
42 /**
43 * The MIME type for a clip holding plain text.
44 */
45 public static final String MIMETYPE_TEXT_PLAIN = "text/plain";
46
47 /**
Dianne Hackbornacb69bb2012-04-13 15:36:06 -070048 * The MIME type for a clip holding HTML text.
49 */
50 public static final String MIMETYPE_TEXT_HTML = "text/html";
51
52 /**
Dianne Hackborn1040dc42010-08-26 22:11:06 -070053 * The MIME type for a clip holding one or more URIs. This should be
54 * used for URIs that are meaningful to a user (such as an http: URI).
55 * It should <em>not</em> be used for a content: URI that references some
56 * other piece of data; in that case the MIME type should be the type
57 * of the referenced data.
58 */
59 public static final String MIMETYPE_TEXT_URILIST = "text/uri-list";
60
61 /**
62 * The MIME type for a clip holding an Intent.
63 */
64 public static final String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent";
65
Vladislav Kaznacheevddb4bde2015-11-24 11:24:12 -080066 /**
67 * The name of the extra used to define a component name when copying/dragging
68 * an app icon from Launcher.
69 * <p>
70 * Type: String
71 * </p>
72 * <p>
73 * Use {@link ComponentName#unflattenFromString(String)}
74 * and {@link ComponentName#flattenToString()} to convert the extra value
75 * to/from {@link ComponentName}.
76 * </p>
Vladislav Kaznacheev5d196672016-04-05 17:12:25 -070077 * @hide
Vladislav Kaznacheevddb4bde2015-11-24 11:24:12 -080078 */
79 public static final String EXTRA_TARGET_COMPONENT_NAME =
80 "android.content.extra.TARGET_COMPONENT_NAME";
81
82 /**
83 * The name of the extra used to define a user serial number when copying/dragging
84 * an app icon from Launcher.
85 * <p>
86 * Type: long
87 * </p>
Vladislav Kaznacheev5d196672016-04-05 17:12:25 -070088 * @hide
Vladislav Kaznacheevddb4bde2015-11-24 11:24:12 -080089 */
90 public static final String EXTRA_USER_SERIAL_NUMBER =
91 "android.content.extra.USER_SERIAL_NUMBER";
92
93
Dianne Hackborn1040dc42010-08-26 22:11:06 -070094 final CharSequence mLabel;
Vladislav Kaznacheev8e7b9402016-11-23 15:31:13 -080095 private final ArrayList<String> mMimeTypes;
Vladislav Kaznacheevddb4bde2015-11-24 11:24:12 -080096 private PersistableBundle mExtras;
Sudheer Shanka09971be2017-01-18 13:37:02 -080097 private long mTimeStamp;
Dianne Hackborn1040dc42010-08-26 22:11:06 -070098
99 /**
100 * Create a new clip.
101 *
102 * @param label Label to show to the user describing this clip.
103 * @param mimeTypes An array of MIME types this data is available as.
104 */
105 public ClipDescription(CharSequence label, String[] mimeTypes) {
106 if (mimeTypes == null) {
107 throw new NullPointerException("mimeTypes is null");
108 }
109 mLabel = label;
Vladislav Kaznacheev8e7b9402016-11-23 15:31:13 -0800110 mMimeTypes = new ArrayList<String>(Arrays.asList(mimeTypes));
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700111 }
112
113 /**
114 * Create a copy of a ClipDescription.
115 */
116 public ClipDescription(ClipDescription o) {
117 mLabel = o.mLabel;
Vladislav Kaznacheev8e7b9402016-11-23 15:31:13 -0800118 mMimeTypes = new ArrayList<String>(o.mMimeTypes);
Sudheer Shanka09971be2017-01-18 13:37:02 -0800119 mTimeStamp = o.mTimeStamp;
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700120 }
121
122 /**
123 * Helper to compare two MIME types, where one may be a pattern.
124 * @param concreteType A fully-specified MIME type.
John Spurlock33900182014-01-02 11:04:18 -0500125 * @param desiredType A desired MIME type that may be a pattern such as *&#47;*.
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700126 * @return Returns true if the two MIME types match.
127 */
128 public static boolean compareMimeTypes(String concreteType, String desiredType) {
129 final int typeLength = desiredType.length();
130 if (typeLength == 3 && desiredType.equals("*/*")) {
131 return true;
132 }
133
134 final int slashpos = desiredType.indexOf('/');
135 if (slashpos > 0) {
136 if (typeLength == slashpos+2 && desiredType.charAt(slashpos+1) == '*') {
137 if (desiredType.regionMatches(0, concreteType, 0, slashpos+1)) {
138 return true;
139 }
140 } else if (desiredType.equals(concreteType)) {
141 return true;
142 }
143 }
144
145 return false;
146 }
147
148 /**
Sudheer Shanka09971be2017-01-18 13:37:02 -0800149 * Used for setting the timestamp at which the associated {@link ClipData} is copied to
150 * global clipboard.
151 *
Sudheer Shankae9ee7f22017-04-20 18:54:08 -0700152 * @param timeStamp at which the associated {@link ClipData} is copied to clipboard in
Sudheer Shankac8201912017-04-20 11:30:48 -0700153 * {@link System#currentTimeMillis()} time base.
Sudheer Shanka09971be2017-01-18 13:37:02 -0800154 * @hide
155 */
156 public void setTimestamp(long timeStamp) {
157 mTimeStamp = timeStamp;
158 }
159
160 /**
161 * Return the timestamp at which the associated {@link ClipData} is copied to global clipboard
Sudheer Shankac8201912017-04-20 11:30:48 -0700162 * in the {@link System#currentTimeMillis()} time base.
Sudheer Shanka09971be2017-01-18 13:37:02 -0800163 *
164 * @return timestamp at which the associated {@link ClipData} is copied to global clipboard
165 * or {@code 0} if it is not copied to clipboard.
166 */
167 public long getTimestamp() {
168 return mTimeStamp;
169 }
170
171 /**
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700172 * Return the label for this clip.
173 */
174 public CharSequence getLabel() {
175 return mLabel;
176 }
177
178 /**
179 * Check whether the clip description contains the given MIME type.
180 *
181 * @param mimeType The desired MIME type. May be a pattern.
182 * @return Returns true if one of the MIME types in the clip description
183 * matches the desired MIME type, else false.
184 */
185 public boolean hasMimeType(String mimeType) {
Vladislav Kaznacheev8e7b9402016-11-23 15:31:13 -0800186 final int size = mMimeTypes.size();
187 for (int i=0; i<size; i++) {
188 if (compareMimeTypes(mMimeTypes.get(i), mimeType)) {
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700189 return true;
190 }
191 }
192 return false;
193 }
194
195 /**
196 * Filter the clip description MIME types by the given MIME type. Returns
197 * all MIME types in the clip that match the given MIME type.
198 *
199 * @param mimeType The desired MIME type. May be a pattern.
200 * @return Returns an array of all matching MIME types. If there are no
201 * matching MIME types, null is returned.
202 */
203 public String[] filterMimeTypes(String mimeType) {
204 ArrayList<String> array = null;
Vladislav Kaznacheev8e7b9402016-11-23 15:31:13 -0800205 final int size = mMimeTypes.size();
206 for (int i=0; i<size; i++) {
207 if (compareMimeTypes(mMimeTypes.get(i), mimeType)) {
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700208 if (array == null) {
209 array = new ArrayList<String>();
210 }
Vladislav Kaznacheev8e7b9402016-11-23 15:31:13 -0800211 array.add(mMimeTypes.get(i));
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700212 }
213 }
214 if (array == null) {
215 return null;
216 }
217 String[] rawArray = new String[array.size()];
218 array.toArray(rawArray);
219 return rawArray;
220 }
221
222 /**
223 * Return the number of MIME types the clip is available in.
224 */
225 public int getMimeTypeCount() {
Vladislav Kaznacheev8e7b9402016-11-23 15:31:13 -0800226 return mMimeTypes.size();
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700227 }
228
229 /**
230 * Return one of the possible clip MIME types.
231 */
232 public String getMimeType(int index) {
Vladislav Kaznacheev8e7b9402016-11-23 15:31:13 -0800233 return mMimeTypes.get(index);
234 }
235
236 /**
237 * Add MIME types to the clip description.
238 */
239 void addMimeTypes(String[] mimeTypes) {
240 for (int i=0; i!=mimeTypes.length; i++) {
241 final String mimeType = mimeTypes[i];
242 if (!mMimeTypes.contains(mimeType)) {
243 mMimeTypes.add(mimeType);
244 }
245 }
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700246 }
247
Vladislav Kaznacheevddb4bde2015-11-24 11:24:12 -0800248 /**
249 * Retrieve extended data from the clip description.
250 *
251 * @return the bundle containing extended data previously set with
252 * {@link #setExtras(PersistableBundle)}, or null if no extras have been set.
253 *
254 * @see #setExtras(PersistableBundle)
255 */
256 public PersistableBundle getExtras() {
257 return mExtras;
258 }
259
260 /**
261 * Add extended data to the clip description.
262 *
263 * @see #getExtras()
264 */
265 public void setExtras(PersistableBundle extras) {
266 mExtras = new PersistableBundle(extras);
267 }
268
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700269 /** @hide */
270 public void validate() {
271 if (mMimeTypes == null) {
272 throw new NullPointerException("null mime types");
273 }
Vladislav Kaznacheev8e7b9402016-11-23 15:31:13 -0800274 final int size = mMimeTypes.size();
275 if (size <= 0) {
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700276 throw new IllegalArgumentException("must have at least 1 mime type");
277 }
Vladislav Kaznacheev8e7b9402016-11-23 15:31:13 -0800278 for (int i=0; i<size; i++) {
279 if (mMimeTypes.get(i) == null) {
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700280 throw new NullPointerException("mime type at " + i + " is null");
281 }
282 }
283 }
284
285 @Override
Dianne Hackborn21c241e2012-03-08 13:57:23 -0800286 public String toString() {
287 StringBuilder b = new StringBuilder(128);
288
289 b.append("ClipDescription { ");
290 toShortString(b);
291 b.append(" }");
292
293 return b.toString();
294 }
295
296 /** @hide */
297 public boolean toShortString(StringBuilder b) {
Dianne Hackbornae498722015-08-14 13:29:47 -0700298 boolean first = !toShortStringTypesOnly(b);
Dianne Hackborn21c241e2012-03-08 13:57:23 -0800299 if (mLabel != null) {
300 if (!first) {
301 b.append(' ');
302 }
303 first = false;
304 b.append('"');
305 b.append(mLabel);
306 b.append('"');
307 }
Vladislav Kaznacheevddb4bde2015-11-24 11:24:12 -0800308 if (mExtras != null) {
309 if (!first) {
310 b.append(' ');
311 }
312 first = false;
313 b.append(mExtras.toString());
314 }
Sudheer Shanka09971be2017-01-18 13:37:02 -0800315 if (mTimeStamp > 0) {
316 if (!first) {
317 b.append(' ');
318 }
319 first = false;
Sudheer Shankac8201912017-04-20 11:30:48 -0700320 b.append('<');
321 b.append(TimeUtils.logTimeOfDay(mTimeStamp));
322 b.append('>');
Sudheer Shanka09971be2017-01-18 13:37:02 -0800323 }
Dianne Hackborn21c241e2012-03-08 13:57:23 -0800324 return !first;
325 }
326
Dianne Hackbornae498722015-08-14 13:29:47 -0700327 /** @hide */
328 public boolean toShortStringTypesOnly(StringBuilder b) {
329 boolean first = true;
Vladislav Kaznacheev8e7b9402016-11-23 15:31:13 -0800330 final int size = mMimeTypes.size();
331 for (int i=0; i<size; i++) {
Dianne Hackbornae498722015-08-14 13:29:47 -0700332 if (!first) {
333 b.append(' ');
334 }
335 first = false;
Vladislav Kaznacheev8e7b9402016-11-23 15:31:13 -0800336 b.append(mMimeTypes.get(i));
Dianne Hackbornae498722015-08-14 13:29:47 -0700337 }
338 return !first;
339 }
340
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800341 /** @hide */
342 public void writeToProto(ProtoOutputStream proto, long fieldId) {
343 final long token = proto.start(fieldId);
344
345 final int size = mMimeTypes.size();
346 for (int i = 0; i < size; i++) {
347 proto.write(ClipDescriptionProto.MIME_TYPES, mMimeTypes.get(i));
348 }
349
350 if (mLabel != null) {
351 proto.write(ClipDescriptionProto.LABEL, mLabel.toString());
352 }
353 if (mExtras != null) {
354 mExtras.writeToProto(proto, ClipDescriptionProto.EXTRAS);
355 }
356 if (mTimeStamp > 0) {
357 proto.write(ClipDescriptionProto.TIMESTAMP_MS, mTimeStamp);
358 }
359
360 proto.end(token);
361 }
362
Dianne Hackborn21c241e2012-03-08 13:57:23 -0800363 @Override
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700364 public int describeContents() {
365 return 0;
366 }
367
368 @Override
369 public void writeToParcel(Parcel dest, int flags) {
370 TextUtils.writeToParcel(mLabel, dest, flags);
Vladislav Kaznacheev8e7b9402016-11-23 15:31:13 -0800371 dest.writeStringList(mMimeTypes);
Vladislav Kaznacheevddb4bde2015-11-24 11:24:12 -0800372 dest.writePersistableBundle(mExtras);
Sudheer Shanka09971be2017-01-18 13:37:02 -0800373 dest.writeLong(mTimeStamp);
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700374 }
375
376 ClipDescription(Parcel in) {
377 mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
Vladislav Kaznacheev8e7b9402016-11-23 15:31:13 -0800378 mMimeTypes = in.createStringArrayList();
Vladislav Kaznacheevddb4bde2015-11-24 11:24:12 -0800379 mExtras = in.readPersistableBundle();
Sudheer Shanka09971be2017-01-18 13:37:02 -0800380 mTimeStamp = in.readLong();
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700381 }
382
383 public static final Parcelable.Creator<ClipDescription> CREATOR =
384 new Parcelable.Creator<ClipDescription>() {
385
386 public ClipDescription createFromParcel(Parcel source) {
387 return new ClipDescription(source);
388 }
389
390 public ClipDescription[] newArray(int size) {
391 return new ClipDescription[size];
392 }
393 };
394}