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