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