IntentSender.java revision 6c418d585e0a91054b168fde3130188afd006c98
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.content;
18
19import android.app.ActivityManagerNative;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IIntentSender;
23import android.content.IIntentReceiver;
24import 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/**
34 * A description of an Intent and target action to perform with it.
35 * 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 IntentSender 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 IntentSender:
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 IntentSender 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 * IntentSender 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 IntentSender (same operation, same Intent action, data,
53 * categories, and components, and same flags), it will receive a IntentSender
54 * representing the same token if that is still valid.
55 *
56 * <p>Instances of this class can not be made directly, but rather must be
57 * created from an existing {@link android.app.PendingIntent} with
58 * {@link android.app.PendingIntent#getIntentSender() PendingIntent.getIntentSender()}.
59 */
60public class IntentSender implements Parcelable {
61    private final IIntentSender mTarget;
62
63    /**
64     * Exception thrown when trying to send through a PendingIntent that
65     * has been canceled or is otherwise no longer able to execute the request.
66     */
67    public static class SendIntentException extends AndroidException {
68        public SendIntentException() {
69        }
70
71        public SendIntentException(String name) {
72            super(name);
73        }
74
75        public SendIntentException(Exception cause) {
76            super(cause);
77        }
78    }
79
80    /**
81     * Callback interface for discovering when a send operation has
82     * completed.  Primarily for use with a IntentSender that is
83     * performing a broadcast, this provides the same information as
84     * calling {@link Context#sendOrderedBroadcast(Intent, String,
85     * android.content.BroadcastReceiver, Handler, int, String, Bundle)
86     * Context.sendBroadcast()} with a final BroadcastReceiver.
87     */
88    public interface OnFinished {
89        /**
90         * Called when a send operation as completed.
91         *
92         * @param IntentSender The IntentSender this operation was sent through.
93         * @param intent The original Intent that was sent.
94         * @param resultCode The final result code determined by the send.
95         * @param resultData The final data collected by a broadcast.
96         * @param resultExtras The final extras collected by a broadcast.
97         */
98        void onSendFinished(IntentSender IntentSender, Intent intent,
99                int resultCode, String resultData, Bundle resultExtras);
100    }
101
102    private static class FinishedDispatcher extends IIntentReceiver.Stub
103            implements Runnable {
104        private final IntentSender mIntentSender;
105        private final OnFinished mWho;
106        private final Handler mHandler;
107        private Intent mIntent;
108        private int mResultCode;
109        private String mResultData;
110        private Bundle mResultExtras;
111        FinishedDispatcher(IntentSender pi, OnFinished who, Handler handler) {
112            mIntentSender = pi;
113            mWho = who;
114            mHandler = handler;
115        }
116        public void performReceive(Intent intent, int resultCode,
117                String data, Bundle extras, boolean serialized, boolean sticky) {
118            mIntent = intent;
119            mResultCode = resultCode;
120            mResultData = data;
121            mResultExtras = extras;
122            if (mHandler == null) {
123                run();
124            } else {
125                mHandler.post(this);
126            }
127        }
128        public void run() {
129            mWho.onSendFinished(mIntentSender, mIntent, mResultCode,
130                    mResultData, mResultExtras);
131        }
132    }
133
134    /**
135     * Perform the operation associated with this IntentSender, allowing the
136     * caller to specify information about the Intent to use and be notified
137     * when the send has completed.
138     *
139     * @param context The Context of the caller.  This may be null if
140     * <var>intent</var> is also null.
141     * @param code Result code to supply back to the IntentSender's target.
142     * @param intent Additional Intent data.  See {@link Intent#fillIn
143     * Intent.fillIn()} for information on how this is applied to the
144     * original Intent.  Use null to not modify the original Intent.
145     * @param onFinished The object to call back on when the send has
146     * completed, or null for no callback.
147     * @param handler Handler identifying the thread on which the callback
148     * should happen.  If null, the callback will happen from the thread
149     * pool of the process.
150     *
151     *
152     * @throws SendIntentException Throws CanceledIntentException if the IntentSender
153     * is no longer allowing more intents to be sent through it.
154     */
155    public void sendIntent(Context context, int code, Intent intent,
156            OnFinished onFinished, Handler handler) throws SendIntentException {
157        sendIntent(context, code, intent, onFinished, handler, null);
158    }
159
160    /**
161     * Perform the operation associated with this IntentSender, allowing the
162     * caller to specify information about the Intent to use and be notified
163     * when the send has completed.
164     *
165     * @param context The Context of the caller.  This may be null if
166     * <var>intent</var> is also null.
167     * @param code Result code to supply back to the IntentSender's target.
168     * @param intent Additional Intent data.  See {@link Intent#fillIn
169     * Intent.fillIn()} for information on how this is applied to the
170     * original Intent.  Use null to not modify the original Intent.
171     * @param onFinished The object to call back on when the send has
172     * completed, or null for no callback.
173     * @param handler Handler identifying the thread on which the callback
174     * should happen.  If null, the callback will happen from the thread
175     * pool of the process.
176     * @param requiredPermission Name of permission that a recipient of the PendingIntent
177     * is required to hold.  This is only valid for broadcast intents, and
178     * corresponds to the permission argument in
179     * {@link Context#sendBroadcast(Intent, String) Context.sendOrderedBroadcast(Intent, String)}.
180     * If null, no permission is required.
181     *
182     *
183     * @throws SendIntentException Throws CanceledIntentException if the IntentSender
184     * is no longer allowing more intents to be sent through it.
185     */
186    public void sendIntent(Context context, int code, Intent intent,
187            OnFinished onFinished, Handler handler, String requiredPermission)
188            throws SendIntentException {
189        try {
190            String resolvedType = intent != null ?
191                    intent.resolveTypeIfNeeded(context.getContentResolver())
192                    : null;
193            int res = mTarget.send(code, intent, resolvedType,
194                    onFinished != null
195                            ? new FinishedDispatcher(this, onFinished, handler)
196                            : null,
197                    requiredPermission);
198            if (res < 0) {
199                throw new SendIntentException();
200            }
201        } catch (RemoteException e) {
202            throw new SendIntentException();
203        }
204    }
205
206    /**
207     * Return the package name of the application that created this
208     * IntentSender, that is the identity under which you will actually be
209     * sending the Intent.  The returned string is supplied by the system, so
210     * that an application can not spoof its package.
211     *
212     * @return The package name of the PendingIntent, or null if there is
213     * none associated with it.
214     */
215    public String getTargetPackage() {
216        try {
217            return ActivityManagerNative.getDefault()
218                .getPackageForIntentSender(mTarget);
219        } catch (RemoteException e) {
220            // Should never happen.
221            return null;
222        }
223    }
224
225    /**
226     * Comparison operator on two IntentSender objects, such that true
227     * is returned then they both represent the same operation from the
228     * same package.
229     */
230    @Override
231    public boolean equals(Object otherObj) {
232        if (otherObj instanceof IntentSender) {
233            return mTarget.asBinder().equals(((IntentSender)otherObj)
234                    .mTarget.asBinder());
235        }
236        return false;
237    }
238
239    @Override
240    public int hashCode() {
241        return mTarget.asBinder().hashCode();
242    }
243
244    @Override
245    public String toString() {
246        StringBuilder sb = new StringBuilder(128);
247        sb.append("IntentSender{");
248        sb.append(Integer.toHexString(System.identityHashCode(this)));
249        sb.append(": ");
250        sb.append(mTarget != null ? mTarget.asBinder() : null);
251        sb.append('}');
252        return sb.toString();
253    }
254
255    public int describeContents() {
256        return 0;
257    }
258
259    public void writeToParcel(Parcel out, int flags) {
260        out.writeStrongBinder(mTarget.asBinder());
261    }
262
263    public static final Parcelable.Creator<IntentSender> CREATOR
264            = new Parcelable.Creator<IntentSender>() {
265        public IntentSender createFromParcel(Parcel in) {
266            IBinder target = in.readStrongBinder();
267            return target != null ? new IntentSender(target) : null;
268        }
269
270        public IntentSender[] newArray(int size) {
271            return new IntentSender[size];
272        }
273    };
274
275    /**
276     * Convenience function for writing either a IntentSender or null pointer to
277     * a Parcel.  You must use this with {@link #readIntentSenderOrNullFromParcel}
278     * for later reading it.
279     *
280     * @param sender The IntentSender to write, or null.
281     * @param out Where to write the IntentSender.
282     */
283    public static void writeIntentSenderOrNullToParcel(IntentSender sender,
284            Parcel out) {
285        out.writeStrongBinder(sender != null ? sender.mTarget.asBinder()
286                : null);
287    }
288
289    /**
290     * Convenience function for reading either a Messenger or null pointer from
291     * a Parcel.  You must have previously written the Messenger with
292     * {@link #writeIntentSenderOrNullToParcel}.
293     *
294     * @param in The Parcel containing the written Messenger.
295     *
296     * @return Returns the Messenger read from the Parcel, or null if null had
297     * been written.
298     */
299    public static IntentSender readIntentSenderOrNullFromParcel(Parcel in) {
300        IBinder b = in.readStrongBinder();
301        return b != null ? new IntentSender(b) : null;
302    }
303
304    /** @hide */
305    public IIntentSender getTarget() {
306        return mTarget;
307    }
308
309    /** @hide */
310    public IntentSender(IIntentSender target) {
311        mTarget = target;
312    }
313
314    /** @hide */
315    public IntentSender(IBinder target) {
316        mTarget = IIntentSender.Stub.asInterface(target);
317    }
318}
319