Home | History | Annotate | Download | only in content
      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 
     17 package android.content;
     18 
     19 import android.app.ActivityManagerNative;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.IIntentSender;
     23 import android.content.IIntentReceiver;
     24 import android.os.Bundle;
     25 import android.os.RemoteException;
     26 import android.os.Handler;
     27 import android.os.IBinder;
     28 import android.os.Parcel;
     29 import android.os.Parcelable;
     30 import 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  */
     60 public 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         try {
    158             String resolvedType = intent != null ?
    159                     intent.resolveTypeIfNeeded(context.getContentResolver())
    160                     : null;
    161             int res = mTarget.send(code, intent, resolvedType,
    162                     onFinished != null
    163                     ? new FinishedDispatcher(this, onFinished, handler)
    164                     : null);
    165             if (res < 0) {
    166                 throw new SendIntentException();
    167             }
    168         } catch (RemoteException e) {
    169             throw new SendIntentException();
    170         }
    171     }
    172 
    173     /**
    174      * Return the package name of the application that created this
    175      * IntentSender, that is the identity under which you will actually be
    176      * sending the Intent.  The returned string is supplied by the system, so
    177      * that an application can not spoof its package.
    178      *
    179      * @return The package name of the PendingIntent, or null if there is
    180      * none associated with it.
    181      */
    182     public String getTargetPackage() {
    183         try {
    184             return ActivityManagerNative.getDefault()
    185                 .getPackageForIntentSender(mTarget);
    186         } catch (RemoteException e) {
    187             // Should never happen.
    188             return null;
    189         }
    190     }
    191 
    192     /**
    193      * Comparison operator on two IntentSender objects, such that true
    194      * is returned then they both represent the same operation from the
    195      * same package.
    196      */
    197     @Override
    198     public boolean equals(Object otherObj) {
    199         if (otherObj instanceof IntentSender) {
    200             return mTarget.asBinder().equals(((IntentSender)otherObj)
    201                     .mTarget.asBinder());
    202         }
    203         return false;
    204     }
    205 
    206     @Override
    207     public int hashCode() {
    208         return mTarget.asBinder().hashCode();
    209     }
    210 
    211     @Override
    212     public String toString() {
    213         StringBuilder sb = new StringBuilder(128);
    214         sb.append("IntentSender{");
    215         sb.append(Integer.toHexString(System.identityHashCode(this)));
    216         sb.append(": ");
    217         sb.append(mTarget != null ? mTarget.asBinder() : null);
    218         sb.append('}');
    219         return sb.toString();
    220     }
    221 
    222     public int describeContents() {
    223         return 0;
    224     }
    225 
    226     public void writeToParcel(Parcel out, int flags) {
    227         out.writeStrongBinder(mTarget.asBinder());
    228     }
    229 
    230     public static final Parcelable.Creator<IntentSender> CREATOR
    231             = new Parcelable.Creator<IntentSender>() {
    232         public IntentSender createFromParcel(Parcel in) {
    233             IBinder target = in.readStrongBinder();
    234             return target != null ? new IntentSender(target) : null;
    235         }
    236 
    237         public IntentSender[] newArray(int size) {
    238             return new IntentSender[size];
    239         }
    240     };
    241 
    242     /**
    243      * Convenience function for writing either a IntentSender or null pointer to
    244      * a Parcel.  You must use this with {@link #readIntentSenderOrNullFromParcel}
    245      * for later reading it.
    246      *
    247      * @param sender The IntentSender to write, or null.
    248      * @param out Where to write the IntentSender.
    249      */
    250     public static void writeIntentSenderOrNullToParcel(IntentSender sender,
    251             Parcel out) {
    252         out.writeStrongBinder(sender != null ? sender.mTarget.asBinder()
    253                 : null);
    254     }
    255 
    256     /**
    257      * Convenience function for reading either a Messenger or null pointer from
    258      * a Parcel.  You must have previously written the Messenger with
    259      * {@link #writeIntentSenderOrNullToParcel}.
    260      *
    261      * @param in The Parcel containing the written Messenger.
    262      *
    263      * @return Returns the Messenger read from the Parcel, or null if null had
    264      * been written.
    265      */
    266     public static IntentSender readIntentSenderOrNullFromParcel(Parcel in) {
    267         IBinder b = in.readStrongBinder();
    268         return b != null ? new IntentSender(b) : null;
    269     }
    270 
    271     /** @hide */
    272     public IIntentSender getTarget() {
    273         return mTarget;
    274     }
    275 
    276     /** @hide */
    277     public IntentSender(IIntentSender target) {
    278         mTarget = target;
    279     }
    280 
    281     /** @hide */
    282     public IntentSender(IBinder target) {
    283         mTarget = IIntentSender.Stub.asInterface(target);
    284     }
    285 }
    286