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