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