IntentSender.java revision 7f2054392e9957d3ba8579ef08c29cfb27df564e
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.content.Context;
20import android.content.Intent;
21import android.content.IIntentSender;
22import android.content.IIntentReceiver;
23import android.os.Bundle;
24import android.os.RemoteException;
25import android.os.Handler;
26import android.os.IBinder;
27import android.os.Parcel;
28import android.os.Parcelable;
29import android.util.AndroidException;
30
31
32/**
33 * A description of an Intent and target action to perform with it.
34 * The returned object can be
35 * handed to other applications so that they can perform the action you
36 * described on your behalf at a later time.
37 *
38 * <p>By giving a IntentSender to another application,
39 * you are granting it the right to perform the operation you have specified
40 * as if the other application was yourself (with the same permissions and
41 * identity).  As such, you should be careful about how you build the IntentSender:
42 * often, for example, the base Intent you supply will have the component
43 * name explicitly set to one of your own components, to ensure it is ultimately
44 * sent there and nowhere else.
45 *
46 * <p>A IntentSender itself is simply a reference to a token maintained by
47 * the system describing the original data used to retrieve it.  This means
48 * that, even if its owning application's process is killed, the
49 * IntentSender itself will remain usable from other processes that
50 * have been given it.  If the creating application later re-retrieves the
51 * same kind of IntentSender (same operation, same Intent action, data,
52 * categories, and components, and same flags), it will receive a IntentSender
53 * representing the same token if that is still valid.
54 *
55 * <p>Instances of this class can not be made directly, but rather must be
56 * created from an existing {@link android.app.PendingIntent} with
57 * {@link android.app.PendingIntent#getIntentSender() PendingIntent.getIntentSender()}.
58 */
59public class IntentSender implements Parcelable {
60    private final IIntentSender mTarget;
61
62    /**
63     * Exception thrown when trying to send through a PendingIntent that
64     * has been canceled or is otherwise no longer able to execute the request.
65     */
66    public static class SendIntentException extends AndroidException {
67        public SendIntentException() {
68        }
69
70        public SendIntentException(String name) {
71            super(name);
72        }
73
74        public SendIntentException(Exception cause) {
75            super(cause);
76        }
77    }
78
79    /**
80     * Callback interface for discovering when a send operation has
81     * completed.  Primarily for use with a IntentSender that is
82     * performing a broadcast, this provides the same information as
83     * calling {@link Context#sendOrderedBroadcast(Intent, String,
84     * android.content.BroadcastReceiver, Handler, int, String, Bundle)
85     * Context.sendBroadcast()} with a final BroadcastReceiver.
86     */
87    public interface OnFinished {
88        /**
89         * Called when a send operation as completed.
90         *
91         * @param IntentSender The IntentSender this operation was sent through.
92         * @param intent The original Intent that was sent.
93         * @param resultCode The final result code determined by the send.
94         * @param resultData The final data collected by a broadcast.
95         * @param resultExtras The final extras collected by a broadcast.
96         */
97        void onSendFinished(IntentSender IntentSender, Intent intent,
98                int resultCode, String resultData, Bundle resultExtras);
99    }
100
101    private static class FinishedDispatcher extends IIntentReceiver.Stub
102            implements Runnable {
103        private final IntentSender mIntentSender;
104        private final OnFinished mWho;
105        private final Handler mHandler;
106        private Intent mIntent;
107        private int mResultCode;
108        private String mResultData;
109        private Bundle mResultExtras;
110        FinishedDispatcher(IntentSender pi, OnFinished who, Handler handler) {
111            mIntentSender = pi;
112            mWho = who;
113            mHandler = handler;
114        }
115        public void performReceive(Intent intent, int resultCode,
116                String data, Bundle extras, boolean serialized) {
117            mIntent = intent;
118            mResultCode = resultCode;
119            mResultData = data;
120            mResultExtras = extras;
121            if (mHandler == null) {
122                run();
123            } else {
124                mHandler.post(this);
125            }
126        }
127        public void run() {
128            mWho.onSendFinished(mIntentSender, mIntent, mResultCode,
129                    mResultData, mResultExtras);
130        }
131    }
132
133    /**
134     * Perform the operation associated with this IntentSender, allowing the
135     * caller to specify information about the Intent to use and be notified
136     * when the send has completed.
137     *
138     * @param context The Context of the caller.  This may be null if
139     * <var>intent</var> is also null.
140     * @param code Result code to supply back to the IntentSender's target.
141     * @param intent Additional Intent data.  See {@link Intent#fillIn
142     * Intent.fillIn()} for information on how this is applied to the
143     * original Intent.  Use null to not modify the original Intent.
144     * @param onFinished The object to call back on when the send has
145     * completed, or null for no callback.
146     * @param handler Handler identifying the thread on which the callback
147     * should happen.  If null, the callback will happen from the thread
148     * pool of the process.
149     *
150     *
151     * @throws SendIntentException Throws CanceledIntentException if the IntentSender
152     * is no longer allowing more intents to be sent through it.
153     */
154    public void sendIntent(Context context, int code, Intent intent,
155            OnFinished onFinished, Handler handler) throws SendIntentException {
156        try {
157            String resolvedType = intent != null ?
158                    intent.resolveTypeIfNeeded(context.getContentResolver())
159                    : null;
160            int res = mTarget.send(code, intent, resolvedType,
161                    onFinished != null
162                    ? new FinishedDispatcher(this, onFinished, handler)
163                    : null);
164            if (res < 0) {
165                throw new SendIntentException();
166            }
167        } catch (RemoteException e) {
168            throw new SendIntentException();
169        }
170    }
171
172    /**
173     * Comparison operator on two IntentSender objects, such that true
174     * is returned then they both represent the same operation from the
175     * same package.
176     */
177    @Override
178    public boolean equals(Object otherObj) {
179        if (otherObj instanceof IntentSender) {
180            return mTarget.asBinder().equals(((IntentSender)otherObj)
181                    .mTarget.asBinder());
182        }
183        return false;
184    }
185
186    @Override
187    public int hashCode() {
188        return mTarget.asBinder().hashCode();
189    }
190
191    @Override
192    public String toString() {
193        StringBuilder sb = new StringBuilder(128);
194        sb.append("IntentSender{");
195        sb.append(Integer.toHexString(System.identityHashCode(this)));
196        sb.append(": ");
197        sb.append(mTarget != null ? mTarget.asBinder() : null);
198        sb.append('}');
199        return sb.toString();
200    }
201
202    public int describeContents() {
203        return 0;
204    }
205
206    public void writeToParcel(Parcel out, int flags) {
207        out.writeStrongBinder(mTarget.asBinder());
208    }
209
210    public static final Parcelable.Creator<IntentSender> CREATOR
211            = new Parcelable.Creator<IntentSender>() {
212        public IntentSender createFromParcel(Parcel in) {
213            IBinder target = in.readStrongBinder();
214            return target != null ? new IntentSender(target) : null;
215        }
216
217        public IntentSender[] newArray(int size) {
218            return new IntentSender[size];
219        }
220    };
221
222    /**
223     * Convenience function for writing either a IntentSender or null pointer to
224     * a Parcel.  You must use this with {@link #readIntentSenderOrNullFromParcel}
225     * for later reading it.
226     *
227     * @param sender The IntentSender to write, or null.
228     * @param out Where to write the IntentSender.
229     */
230    public static void writeIntentSenderOrNullToParcel(IntentSender sender,
231            Parcel out) {
232        out.writeStrongBinder(sender != null ? sender.mTarget.asBinder()
233                : null);
234    }
235
236    /**
237     * Convenience function for reading either a Messenger or null pointer from
238     * a Parcel.  You must have previously written the Messenger with
239     * {@link #writeIntentSenderOrNullToParcel}.
240     *
241     * @param in The Parcel containing the written Messenger.
242     *
243     * @return Returns the Messenger read from the Parcel, or null if null had
244     * been written.
245     */
246    public static IntentSender readIntentSenderOrNullFromParcel(Parcel in) {
247        IBinder b = in.readStrongBinder();
248        return b != null ? new IntentSender(b) : null;
249    }
250
251    /** @hide */
252    public IntentSender(IIntentSender target) {
253        mTarget = target;
254    }
255
256    /** @hide */
257    public IntentSender(IBinder target) {
258        mTarget = IIntentSender.Stub.asInterface(target);
259    }
260}
261