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         sendIntent(context, code, intent, onFinished, handler, null);
    158     }
    159 
    160     /**
    161      * Perform the operation associated with this IntentSender, allowing the
    162      * caller to specify information about the Intent to use and be notified
    163      * when the send has completed.
    164      *
    165      * @param context The Context of the caller.  This may be null if
    166      * <var>intent</var> is also null.
    167      * @param code Result code to supply back to the IntentSender's target.
    168      * @param intent Additional Intent data.  See {@link Intent#fillIn
    169      * Intent.fillIn()} for information on how this is applied to the
    170      * original Intent.  Use null to not modify the original Intent.
    171      * @param onFinished The object to call back on when the send has
    172      * completed, or null for no callback.
    173      * @param handler Handler identifying the thread on which the callback
    174      * should happen.  If null, the callback will happen from the thread
    175      * pool of the process.
    176      * @param requiredPermission Name of permission that a recipient of the PendingIntent
    177      * is required to hold.  This is only valid for broadcast intents, and
    178      * corresponds to the permission argument in
    179      * {@link Context#sendBroadcast(Intent, String) Context.sendOrderedBroadcast(Intent, String)}.
    180      * If null, no permission is required.
    181      *
    182      *
    183      * @throws SendIntentException Throws CanceledIntentException if the IntentSender
    184      * is no longer allowing more intents to be sent through it.
    185      */
    186     public void sendIntent(Context context, int code, Intent intent,
    187             OnFinished onFinished, Handler handler, String requiredPermission)
    188             throws SendIntentException {
    189         try {
    190             String resolvedType = intent != null ?
    191                     intent.resolveTypeIfNeeded(context.getContentResolver())
    192                     : null;
    193             int res = mTarget.send(code, intent, resolvedType,
    194                     onFinished != null
    195                             ? new FinishedDispatcher(this, onFinished, handler)
    196                             : null,
    197                     requiredPermission);
    198             if (res < 0) {
    199                 throw new SendIntentException();
    200             }
    201         } catch (RemoteException e) {
    202             throw new SendIntentException();
    203         }
    204     }
    205 
    206     /**
    207      * Return the package name of the application that created this
    208      * IntentSender, that is the identity under which you will actually be
    209      * sending the Intent.  The returned string is supplied by the system, so
    210      * that an application can not spoof its package.
    211      *
    212      * @return The package name of the PendingIntent, or null if there is
    213      * none associated with it.
    214      */
    215     public String getTargetPackage() {
    216         try {
    217             return ActivityManagerNative.getDefault()
    218                 .getPackageForIntentSender(mTarget);
    219         } catch (RemoteException e) {
    220             // Should never happen.
    221             return null;
    222         }
    223     }
    224 
    225     /**
    226      * Comparison operator on two IntentSender objects, such that true
    227      * is returned then they both represent the same operation from the
    228      * same package.
    229      */
    230     @Override
    231     public boolean equals(Object otherObj) {
    232         if (otherObj instanceof IntentSender) {
    233             return mTarget.asBinder().equals(((IntentSender)otherObj)
    234                     .mTarget.asBinder());
    235         }
    236         return false;
    237     }
    238 
    239     @Override
    240     public int hashCode() {
    241         return mTarget.asBinder().hashCode();
    242     }
    243 
    244     @Override
    245     public String toString() {
    246         StringBuilder sb = new StringBuilder(128);
    247         sb.append("IntentSender{");
    248         sb.append(Integer.toHexString(System.identityHashCode(this)));
    249         sb.append(": ");
    250         sb.append(mTarget != null ? mTarget.asBinder() : null);
    251         sb.append('}');
    252         return sb.toString();
    253     }
    254 
    255     public int describeContents() {
    256         return 0;
    257     }
    258 
    259     public void writeToParcel(Parcel out, int flags) {
    260         out.writeStrongBinder(mTarget.asBinder());
    261     }
    262 
    263     public static final Parcelable.Creator<IntentSender> CREATOR
    264             = new Parcelable.Creator<IntentSender>() {
    265         public IntentSender createFromParcel(Parcel in) {
    266             IBinder target = in.readStrongBinder();
    267             return target != null ? new IntentSender(target) : null;
    268         }
    269 
    270         public IntentSender[] newArray(int size) {
    271             return new IntentSender[size];
    272         }
    273     };
    274 
    275     /**
    276      * Convenience function for writing either a IntentSender or null pointer to
    277      * a Parcel.  You must use this with {@link #readIntentSenderOrNullFromParcel}
    278      * for later reading it.
    279      *
    280      * @param sender The IntentSender to write, or null.
    281      * @param out Where to write the IntentSender.
    282      */
    283     public static void writeIntentSenderOrNullToParcel(IntentSender sender,
    284             Parcel out) {
    285         out.writeStrongBinder(sender != null ? sender.mTarget.asBinder()
    286                 : null);
    287     }
    288 
    289     /**
    290      * Convenience function for reading either a Messenger or null pointer from
    291      * a Parcel.  You must have previously written the Messenger with
    292      * {@link #writeIntentSenderOrNullToParcel}.
    293      *
    294      * @param in The Parcel containing the written Messenger.
    295      *
    296      * @return Returns the Messenger read from the Parcel, or null if null had
    297      * been written.
    298      */
    299     public static IntentSender readIntentSenderOrNullFromParcel(Parcel in) {
    300         IBinder b = in.readStrongBinder();
    301         return b != null ? new IntentSender(b) : null;
    302     }
    303 
    304     /** @hide */
    305     public IIntentSender getTarget() {
    306         return mTarget;
    307     }
    308 
    309     /** @hide */
    310     public IntentSender(IIntentSender target) {
    311         mTarget = target;
    312     }
    313 
    314     /** @hide */
    315     public IntentSender(IBinder target) {
    316         mTarget = IIntentSender.Stub.asInterface(target);
    317     }
    318 }
    319