blob: 5b43b650abb1b8065fcc8ba80cd9288335878449 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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.app;
18
19import android.content.Context;
20import android.content.Intent;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070021import android.content.IIntentReceiver;
22import android.content.IIntentSender;
23import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.os.Bundle;
25import android.os.RemoteException;
26import android.os.Handler;
27import android.os.IBinder;
28import android.os.Parcel;
29import android.os.Parcelable;
30import android.util.AndroidException;
31
32/**
33 * A description of an Intent and target action to perform with it. Instances
34 * of this class are created with {@link #getActivity},
35 * {@link #getBroadcast}, {@link #getService}; the returned object can be
36 * handed to other applications so that they can perform the action you
37 * described on your behalf at a later time.
38 *
39 * <p>By giving a PendingIntent to another application,
40 * you are granting it the right to perform the operation you have specified
41 * as if the other application was yourself (with the same permissions and
42 * identity). As such, you should be careful about how you build the PendingIntent:
43 * often, for example, the base Intent you supply will have the component
44 * name explicitly set to one of your own components, to ensure it is ultimately
45 * sent there and nowhere else.
46 *
47 * <p>A PendingIntent itself is simply a reference to a token maintained by
48 * the system describing the original data used to retrieve it. This means
49 * that, even if its owning application's process is killed, the
50 * PendingIntent itself will remain usable from other processes that
51 * have been given it. If the creating application later re-retrieves the
52 * same kind of PendingIntent (same operation, same Intent action, data,
53 * categories, and components, and same flags), it will receive a PendingIntent
54 * representing the same token if that is still valid, and can thus call
55 * {@link #cancel} to remove it.
56 */
57public final class PendingIntent implements Parcelable {
58 private final IIntentSender mTarget;
59
60 /**
61 * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and
62 * {@link #getService}: this
63 * PendingIntent can only be used once. If set, after
64 * {@link #send()} is called on it, it will be automatically
65 * canceled for you and any future attempt to send through it will fail.
66 */
67 public static final int FLAG_ONE_SHOT = 1<<30;
68 /**
69 * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and
70 * {@link #getService}: if the described PendingIntent does not already
71 * exist, then simply return null instead of creating it.
72 */
73 public static final int FLAG_NO_CREATE = 1<<29;
74 /**
75 * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and
76 * {@link #getService}: if the described PendingIntent already exists,
77 * the current one is canceled before generating a new one. You can use
78 * this to retrieve a new PendingIntent when you are only changing the
79 * extra data in the Intent; by canceling the previous pending intent,
80 * this ensures that only entities given the new data will be able to
81 * launch it. If this assurance is not an issue, consider
82 * {@link #FLAG_UPDATE_CURRENT}.
83 */
84 public static final int FLAG_CANCEL_CURRENT = 1<<28;
85 /**
86 * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and
87 * {@link #getService}: if the described PendingIntent already exists,
88 * then keep it but its replace its extra data with what is in this new
89 * Intent. This can be used if you are creating intents where only the
90 * extras change, and don't care that any entities that received your
91 * previous PendingIntent will be able to launch it with your new
92 * extras even if they are not explicitly given to it.
93 */
94 public static final int FLAG_UPDATE_CURRENT = 1<<27;
95
96 /**
97 * Exception thrown when trying to send through a PendingIntent that
98 * has been canceled or is otherwise no longer able to execute the request.
99 */
100 public static class CanceledException extends AndroidException {
101 public CanceledException() {
102 }
103
104 public CanceledException(String name) {
105 super(name);
106 }
107
108 public CanceledException(Exception cause) {
109 super(cause);
110 }
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -0700111 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112
113 /**
114 * Callback interface for discovering when a send operation has
115 * completed. Primarily for use with a PendingIntent that is
116 * performing a broadcast, this provides the same information as
117 * calling {@link Context#sendOrderedBroadcast(Intent, String,
118 * android.content.BroadcastReceiver, Handler, int, String, Bundle)
119 * Context.sendBroadcast()} with a final BroadcastReceiver.
120 */
121 public interface OnFinished {
122 /**
123 * Called when a send operation as completed.
124 *
125 * @param pendingIntent The PendingIntent this operation was sent through.
126 * @param intent The original Intent that was sent.
127 * @param resultCode The final result code determined by the send.
128 * @param resultData The final data collected by a broadcast.
129 * @param resultExtras The final extras collected by a broadcast.
130 */
131 void onSendFinished(PendingIntent pendingIntent, Intent intent,
132 int resultCode, String resultData, Bundle resultExtras);
133 }
134
135 private static class FinishedDispatcher extends IIntentReceiver.Stub
136 implements Runnable {
137 private final PendingIntent mPendingIntent;
138 private final OnFinished mWho;
139 private final Handler mHandler;
140 private Intent mIntent;
141 private int mResultCode;
142 private String mResultData;
143 private Bundle mResultExtras;
144 FinishedDispatcher(PendingIntent pi, OnFinished who, Handler handler) {
145 mPendingIntent = pi;
146 mWho = who;
147 mHandler = handler;
148 }
149 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -0700150 String data, Bundle extras, boolean serialized, boolean sticky) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 mIntent = intent;
152 mResultCode = resultCode;
153 mResultData = data;
154 mResultExtras = extras;
155 if (mHandler == null) {
156 run();
157 } else {
158 mHandler.post(this);
159 }
160 }
161 public void run() {
162 mWho.onSendFinished(mPendingIntent, mIntent, mResultCode,
163 mResultData, mResultExtras);
164 }
165 }
166
167 /**
168 * Retrieve a PendingIntent that will start a new activity, like calling
169 * {@link Context#startActivity(Intent) Context.startActivity(Intent)}.
170 * Note that the activity will be started outside of the context of an
171 * existing activity, so you must use the {@link Intent#FLAG_ACTIVITY_NEW_TASK
172 * Intent.FLAG_ACTIVITY_NEW_TASK} launch flag in the Intent.
173 *
174 * @param context The Context in which this PendingIntent should start
175 * the activity.
176 * @param requestCode Private request code for the sender (currently
177 * not used).
178 * @param intent Intent of the activity to be launched.
179 * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE},
180 * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT},
181 * or any of the flags as supported by
182 * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts
183 * of the intent that can be supplied when the actual send happens.
184 *
185 * @return Returns an existing or new PendingIntent matching the given
186 * parameters. May return null only if {@link #FLAG_NO_CREATE} has been
187 * supplied.
188 */
189 public static PendingIntent getActivity(Context context, int requestCode,
190 Intent intent, int flags) {
191 String packageName = context.getPackageName();
192 String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
193 context.getContentResolver()) : null;
194 try {
195 IIntentSender target =
196 ActivityManagerNative.getDefault().getIntentSender(
197 IActivityManager.INTENT_SENDER_ACTIVITY, packageName,
Dianne Hackborn621e17d2010-11-22 15:59:56 -0800198 null, null, requestCode, new Intent[] { intent },
199 resolvedType != null ? new String[] { resolvedType } : null, flags);
200 return target != null ? new PendingIntent(target) : null;
201 } catch (RemoteException e) {
202 }
203 return null;
204 }
205
206 /**
207 * Like {@link #getActivity(Context, int, Intent, int)}, but allows an
208 * array of Intents to be supplied. The first Intent in the array is
209 * taken as the primary key for the PendingIntent, like the single Intent
210 * given to {@link #getActivity(Context, int, Intent, int)}. Upon sending
211 * the resulting PendingIntent, all of the Intents are started in the same
212 * way as they would be by passing them to {@link Context#startActivities(Intent[])}.
213 *
214 * <p class="note">
215 * The <em>first</em> intent in the array will be started outside of the context of an
216 * existing activity, so you must use the {@link Intent#FLAG_ACTIVITY_NEW_TASK
217 * Intent.FLAG_ACTIVITY_NEW_TASK} launch flag in the Intent. (Activities after
218 * the first in the array are started in the context of the previous activity
219 * in the array, so FLAG_ACTIVITY_NEW_TASK is not needed nor desired for them.)
220 * </p>
221 *
222 * <p class="note">
223 * The <em>last</em> intent in the array represents the key for the
224 * PendingIntent. In other words, it is the significant element for matching
225 * (as done with the single intent given to {@link #getActivity(Context, int, Intent, int)},
226 * its content will be the subject of replacement by
227 * {@link #send(Context, int, Intent)} and {@link #FLAG_UPDATE_CURRENT}, etc.
228 * This is because it is the most specific of the supplied intents, and the
229 * UI the user actually sees when the intents are started.
230 * </p>
231 *
232 * @param context The Context in which this PendingIntent should start
233 * the activity.
234 * @param requestCode Private request code for the sender (currently
235 * not used).
236 * @param intents Array of Intents of the activities to be launched.
237 * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE},
238 * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT},
239 * or any of the flags as supported by
240 * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts
241 * of the intent that can be supplied when the actual send happens.
242 *
243 * @return Returns an existing or new PendingIntent matching the given
244 * parameters. May return null only if {@link #FLAG_NO_CREATE} has been
245 * supplied.
246 */
247 public static PendingIntent getActivities(Context context, int requestCode,
248 Intent[] intents, int flags) {
249 String packageName = context.getPackageName();
250 String[] resolvedTypes = new String[intents.length];
251 for (int i=0; i<intents.length; i++) {
252 resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
253 }
254 try {
255 IIntentSender target =
256 ActivityManagerNative.getDefault().getIntentSender(
257 IActivityManager.INTENT_SENDER_ACTIVITY, packageName,
258 null, null, requestCode, intents, resolvedTypes, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 return target != null ? new PendingIntent(target) : null;
260 } catch (RemoteException e) {
261 }
262 return null;
263 }
264
265 /**
266 * Retrieve a PendingIntent that will perform a broadcast, like calling
267 * {@link Context#sendBroadcast(Intent) Context.sendBroadcast()}.
268 *
269 * @param context The Context in which this PendingIntent should perform
270 * the broadcast.
271 * @param requestCode Private request code for the sender (currently
272 * not used).
273 * @param intent The Intent to be broadcast.
274 * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE},
275 * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT},
276 * or any of the flags as supported by
277 * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts
278 * of the intent that can be supplied when the actual send happens.
279 *
280 * @return Returns an existing or new PendingIntent matching the given
281 * parameters. May return null only if {@link #FLAG_NO_CREATE} has been
282 * supplied.
283 */
284 public static PendingIntent getBroadcast(Context context, int requestCode,
285 Intent intent, int flags) {
286 String packageName = context.getPackageName();
287 String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
288 context.getContentResolver()) : null;
289 try {
290 IIntentSender target =
291 ActivityManagerNative.getDefault().getIntentSender(
292 IActivityManager.INTENT_SENDER_BROADCAST, packageName,
Dianne Hackborn621e17d2010-11-22 15:59:56 -0800293 null, null, requestCode, new Intent[] { intent },
294 resolvedType != null ? new String[] { resolvedType } : null, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295 return target != null ? new PendingIntent(target) : null;
296 } catch (RemoteException e) {
297 }
298 return null;
299 }
300
301 /**
302 * Retrieve a PendingIntent that will start a service, like calling
303 * {@link Context#startService Context.startService()}. The start
304 * arguments given to the service will come from the extras of the Intent.
305 *
306 * @param context The Context in which this PendingIntent should start
307 * the service.
308 * @param requestCode Private request code for the sender (currently
309 * not used).
310 * @param intent An Intent describing the service to be started.
311 * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE},
312 * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT},
313 * or any of the flags as supported by
314 * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts
315 * of the intent that can be supplied when the actual send happens.
316 *
317 * @return Returns an existing or new PendingIntent matching the given
318 * parameters. May return null only if {@link #FLAG_NO_CREATE} has been
319 * supplied.
320 */
321 public static PendingIntent getService(Context context, int requestCode,
322 Intent intent, int flags) {
323 String packageName = context.getPackageName();
324 String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
325 context.getContentResolver()) : null;
326 try {
327 IIntentSender target =
328 ActivityManagerNative.getDefault().getIntentSender(
329 IActivityManager.INTENT_SENDER_SERVICE, packageName,
Dianne Hackborn621e17d2010-11-22 15:59:56 -0800330 null, null, requestCode, new Intent[] { intent },
331 resolvedType != null ? new String[] { resolvedType } : null, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 return target != null ? new PendingIntent(target) : null;
333 } catch (RemoteException e) {
334 }
335 return null;
336 }
337
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -0700338 /**
339 * Retrieve a IntentSender object that wraps the existing sender of the PendingIntent
340 *
341 * @return Returns a IntentSender object that wraps the sender of PendingIntent
342 *
343 */
344 public IntentSender getIntentSender() {
Dianne Hackborn7f205432009-07-28 00:13:47 -0700345 return new IntentSender(mTarget);
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -0700346 }
347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 /**
349 * Cancel a currently active PendingIntent. Only the original application
350 * owning an PendingIntent can cancel it.
351 */
352 public void cancel() {
353 try {
354 ActivityManagerNative.getDefault().cancelIntentSender(mTarget);
355 } catch (RemoteException e) {
356 }
357 }
358
359 /**
360 * Perform the operation associated with this PendingIntent.
361 *
362 * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler)
363 *
364 * @throws CanceledException Throws CanceledException if the PendingIntent
365 * is no longer allowing more intents to be sent through it.
366 */
367 public void send() throws CanceledException {
368 send(null, 0, null, null, null);
369 }
370
371 /**
372 * Perform the operation associated with this PendingIntent.
373 *
374 * @param code Result code to supply back to the PendingIntent's target.
375 *
376 * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler)
377 *
378 * @throws CanceledException Throws CanceledException if the PendingIntent
379 * is no longer allowing more intents to be sent through it.
380 */
381 public void send(int code) throws CanceledException {
382 send(null, code, null, null, null);
383 }
384
385 /**
386 * Perform the operation associated with this PendingIntent, allowing the
387 * caller to specify information about the Intent to use.
388 *
389 * @param context The Context of the caller.
390 * @param code Result code to supply back to the PendingIntent's target.
391 * @param intent Additional Intent data. See {@link Intent#fillIn
392 * Intent.fillIn()} for information on how this is applied to the
393 * original Intent.
394 *
395 * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler)
396 *
397 * @throws CanceledException Throws CanceledException if the PendingIntent
398 * is no longer allowing more intents to be sent through it.
399 */
400 public void send(Context context, int code, Intent intent)
401 throws CanceledException {
402 send(context, code, intent, null, null);
403 }
404
405 /**
406 * Perform the operation associated with this PendingIntent, allowing the
407 * caller to be notified when the send has completed.
408 *
409 * @param code Result code to supply back to the PendingIntent's target.
410 * @param onFinished The object to call back on when the send has
411 * completed, or null for no callback.
412 * @param handler Handler identifying the thread on which the callback
413 * should happen. If null, the callback will happen from the thread
414 * pool of the process.
415 *
416 * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler)
417 *
418 * @throws CanceledException Throws CanceledException if the PendingIntent
419 * is no longer allowing more intents to be sent through it.
420 */
421 public void send(int code, OnFinished onFinished, Handler handler)
422 throws CanceledException {
423 send(null, code, null, onFinished, handler);
424 }
425
426 /**
427 * Perform the operation associated with this PendingIntent, allowing the
428 * caller to specify information about the Intent to use and be notified
429 * when the send has completed.
430 *
431 * <p>For the intent parameter, a PendingIntent
432 * often has restrictions on which fields can be supplied here, based on
433 * how the PendingIntent was retrieved in {@link #getActivity},
434 * {@link #getBroadcast}, or {@link #getService}.
435 *
436 * @param context The Context of the caller. This may be null if
437 * <var>intent</var> is also null.
438 * @param code Result code to supply back to the PendingIntent's target.
439 * @param intent Additional Intent data. See {@link Intent#fillIn
440 * Intent.fillIn()} for information on how this is applied to the
441 * original Intent. Use null to not modify the original Intent.
442 * @param onFinished The object to call back on when the send has
443 * completed, or null for no callback.
444 * @param handler Handler identifying the thread on which the callback
445 * should happen. If null, the callback will happen from the thread
446 * pool of the process.
447 *
448 * @see #send()
449 * @see #send(int)
450 * @see #send(Context, int, Intent)
451 * @see #send(int, android.app.PendingIntent.OnFinished, Handler)
452 *
453 * @throws CanceledException Throws CanceledException if the PendingIntent
454 * is no longer allowing more intents to be sent through it.
455 */
456 public void send(Context context, int code, Intent intent,
457 OnFinished onFinished, Handler handler) throws CanceledException {
458 try {
459 String resolvedType = intent != null ?
460 intent.resolveTypeIfNeeded(context.getContentResolver())
461 : null;
462 int res = mTarget.send(code, intent, resolvedType,
463 onFinished != null
464 ? new FinishedDispatcher(this, onFinished, handler)
465 : null);
466 if (res < 0) {
467 throw new CanceledException();
468 }
469 } catch (RemoteException e) {
470 throw new CanceledException(e);
471 }
472 }
473
474 /**
475 * Return the package name of the application that created this
476 * PendingIntent, that is the identity under which you will actually be
477 * sending the Intent. The returned string is supplied by the system, so
478 * that an application can not spoof its package.
479 *
480 * @return The package name of the PendingIntent, or null if there is
481 * none associated with it.
482 */
483 public String getTargetPackage() {
484 try {
485 return ActivityManagerNative.getDefault()
486 .getPackageForIntentSender(mTarget);
487 } catch (RemoteException e) {
488 // Should never happen.
489 return null;
490 }
491 }
492
493 /**
494 * Comparison operator on two PendingIntent objects, such that true
495 * is returned then they both represent the same operation from the
496 * same package. This allows you to use {@link #getActivity},
497 * {@link #getBroadcast}, or {@link #getService} multiple times (even
498 * across a process being killed), resulting in different PendingIntent
499 * objects but whose equals() method identifies them as being the same
500 * operation.
501 */
502 @Override
503 public boolean equals(Object otherObj) {
504 if (otherObj instanceof PendingIntent) {
505 return mTarget.asBinder().equals(((PendingIntent)otherObj)
506 .mTarget.asBinder());
507 }
508 return false;
509 }
510
511 @Override
512 public int hashCode() {
513 return mTarget.asBinder().hashCode();
514 }
515
516 @Override
517 public String toString() {
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700518 StringBuilder sb = new StringBuilder(128);
519 sb.append("PendingIntent{");
520 sb.append(Integer.toHexString(System.identityHashCode(this)));
521 sb.append(": ");
522 sb.append(mTarget != null ? mTarget.asBinder() : null);
523 sb.append('}');
524 return sb.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525 }
526
527 public int describeContents() {
528 return 0;
529 }
530
531 public void writeToParcel(Parcel out, int flags) {
532 out.writeStrongBinder(mTarget.asBinder());
533 }
534
535 public static final Parcelable.Creator<PendingIntent> CREATOR
536 = new Parcelable.Creator<PendingIntent>() {
537 public PendingIntent createFromParcel(Parcel in) {
538 IBinder target = in.readStrongBinder();
539 return target != null ? new PendingIntent(target) : null;
540 }
541
542 public PendingIntent[] newArray(int size) {
543 return new PendingIntent[size];
544 }
545 };
546
547 /**
548 * Convenience function for writing either a PendingIntent or null pointer to
549 * a Parcel. You must use this with {@link #readPendingIntentOrNullFromParcel}
550 * for later reading it.
551 *
552 * @param sender The PendingIntent to write, or null.
553 * @param out Where to write the PendingIntent.
554 */
555 public static void writePendingIntentOrNullToParcel(PendingIntent sender,
556 Parcel out) {
557 out.writeStrongBinder(sender != null ? sender.mTarget.asBinder()
558 : null);
559 }
560
561 /**
562 * Convenience function for reading either a Messenger or null pointer from
563 * a Parcel. You must have previously written the Messenger with
564 * {@link #writePendingIntentOrNullToParcel}.
565 *
566 * @param in The Parcel containing the written Messenger.
567 *
568 * @return Returns the Messenger read from the Parcel, or null if null had
569 * been written.
570 */
571 public static PendingIntent readPendingIntentOrNullFromParcel(Parcel in) {
572 IBinder b = in.readStrongBinder();
573 return b != null ? new PendingIntent(b) : null;
574 }
575
576 /*package*/ PendingIntent(IIntentSender target) {
577 mTarget = target;
578 }
579
580 /*package*/ PendingIntent(IBinder target) {
581 mTarget = IIntentSender.Stub.asInterface(target);
582 }
583
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -0700584 /** @hide */
585 public IIntentSender getTarget() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 return mTarget;
587 }
588}