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