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