PendingIntent.java revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
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.app; 18 19import android.content.Context; 20import android.content.Intent; 21import android.os.Bundle; 22import android.os.RemoteException; 23import android.os.Handler; 24import android.os.IBinder; 25import android.os.Parcel; 26import android.os.Parcelable; 27import android.util.AndroidException; 28 29/** 30 * A description of an Intent and target action to perform with it. Instances 31 * of this class are created with {@link #getActivity}, 32 * {@link #getBroadcast}, {@link #getService}; the returned object can be 33 * handed to other applications so that they can perform the action you 34 * described on your behalf at a later time. 35 * 36 * <p>By giving a PendingIntent to another application, 37 * you are granting it the right to perform the operation you have specified 38 * as if the other application was yourself (with the same permissions and 39 * identity). As such, you should be careful about how you build the PendingIntent: 40 * often, for example, the base Intent you supply will have the component 41 * name explicitly set to one of your own components, to ensure it is ultimately 42 * sent there and nowhere else. 43 * 44 * <p>A PendingIntent itself is simply a reference to a token maintained by 45 * the system describing the original data used to retrieve it. This means 46 * that, even if its owning application's process is killed, the 47 * PendingIntent itself will remain usable from other processes that 48 * have been given it. If the creating application later re-retrieves the 49 * same kind of PendingIntent (same operation, same Intent action, data, 50 * categories, and components, and same flags), it will receive a PendingIntent 51 * representing the same token if that is still valid, and can thus call 52 * {@link #cancel} to remove it. 53 */ 54public final class PendingIntent implements Parcelable { 55 private final IIntentSender mTarget; 56 57 /** 58 * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and 59 * {@link #getService}: this 60 * PendingIntent can only be used once. If set, after 61 * {@link #send()} is called on it, it will be automatically 62 * canceled for you and any future attempt to send through it will fail. 63 */ 64 public static final int FLAG_ONE_SHOT = 1<<30; 65 /** 66 * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and 67 * {@link #getService}: if the described PendingIntent does not already 68 * exist, then simply return null instead of creating it. 69 */ 70 public static final int FLAG_NO_CREATE = 1<<29; 71 /** 72 * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and 73 * {@link #getService}: if the described PendingIntent already exists, 74 * the current one is canceled before generating a new one. You can use 75 * this to retrieve a new PendingIntent when you are only changing the 76 * extra data in the Intent; by canceling the previous pending intent, 77 * this ensures that only entities given the new data will be able to 78 * launch it. If this assurance is not an issue, consider 79 * {@link #FLAG_UPDATE_CURRENT}. 80 */ 81 public static final int FLAG_CANCEL_CURRENT = 1<<28; 82 /** 83 * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and 84 * {@link #getService}: if the described PendingIntent already exists, 85 * then keep it but its replace its extra data with what is in this new 86 * Intent. This can be used if you are creating intents where only the 87 * extras change, and don't care that any entities that received your 88 * previous PendingIntent will be able to launch it with your new 89 * extras even if they are not explicitly given to it. 90 */ 91 public static final int FLAG_UPDATE_CURRENT = 1<<27; 92 93 /** 94 * Exception thrown when trying to send through a PendingIntent that 95 * has been canceled or is otherwise no longer able to execute the request. 96 */ 97 public static class CanceledException extends AndroidException { 98 public CanceledException() { 99 } 100 101 public CanceledException(String name) { 102 super(name); 103 } 104 105 public CanceledException(Exception cause) { 106 super(cause); 107 } 108 }; 109 110 /** 111 * Callback interface for discovering when a send operation has 112 * completed. Primarily for use with a PendingIntent that is 113 * performing a broadcast, this provides the same information as 114 * calling {@link Context#sendOrderedBroadcast(Intent, String, 115 * android.content.BroadcastReceiver, Handler, int, String, Bundle) 116 * Context.sendBroadcast()} with a final BroadcastReceiver. 117 */ 118 public interface OnFinished { 119 /** 120 * Called when a send operation as completed. 121 * 122 * @param pendingIntent The PendingIntent this operation was sent through. 123 * @param intent The original Intent that was sent. 124 * @param resultCode The final result code determined by the send. 125 * @param resultData The final data collected by a broadcast. 126 * @param resultExtras The final extras collected by a broadcast. 127 */ 128 void onSendFinished(PendingIntent pendingIntent, Intent intent, 129 int resultCode, String resultData, Bundle resultExtras); 130 } 131 132 private static class FinishedDispatcher extends IIntentReceiver.Stub 133 implements Runnable { 134 private final PendingIntent mPendingIntent; 135 private final OnFinished mWho; 136 private final Handler mHandler; 137 private Intent mIntent; 138 private int mResultCode; 139 private String mResultData; 140 private Bundle mResultExtras; 141 FinishedDispatcher(PendingIntent pi, OnFinished who, Handler handler) { 142 mPendingIntent = pi; 143 mWho = who; 144 mHandler = handler; 145 } 146 public void performReceive(Intent intent, int resultCode, 147 String data, Bundle extras, boolean serialized) { 148 mIntent = intent; 149 mResultCode = resultCode; 150 mResultData = data; 151 mResultExtras = extras; 152 if (mHandler == null) { 153 run(); 154 } else { 155 mHandler.post(this); 156 } 157 } 158 public void run() { 159 mWho.onSendFinished(mPendingIntent, mIntent, mResultCode, 160 mResultData, mResultExtras); 161 } 162 } 163 164 /** 165 * Retrieve a PendingIntent that will start a new activity, like calling 166 * {@link Context#startActivity(Intent) Context.startActivity(Intent)}. 167 * Note that the activity will be started outside of the context of an 168 * existing activity, so you must use the {@link Intent#FLAG_ACTIVITY_NEW_TASK 169 * Intent.FLAG_ACTIVITY_NEW_TASK} launch flag in the Intent. 170 * 171 * @param context The Context in which this PendingIntent should start 172 * the activity. 173 * @param requestCode Private request code for the sender (currently 174 * not used). 175 * @param intent Intent of the activity to be launched. 176 * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE}, 177 * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT}, 178 * or any of the flags as supported by 179 * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts 180 * of the intent that can be supplied when the actual send happens. 181 * 182 * @return Returns an existing or new PendingIntent matching the given 183 * parameters. May return null only if {@link #FLAG_NO_CREATE} has been 184 * supplied. 185 */ 186 public static PendingIntent getActivity(Context context, int requestCode, 187 Intent intent, int flags) { 188 String packageName = context.getPackageName(); 189 String resolvedType = intent != null ? intent.resolveTypeIfNeeded( 190 context.getContentResolver()) : null; 191 try { 192 IIntentSender target = 193 ActivityManagerNative.getDefault().getIntentSender( 194 IActivityManager.INTENT_SENDER_ACTIVITY, packageName, 195 null, null, requestCode, intent, resolvedType, flags); 196 return target != null ? new PendingIntent(target) : null; 197 } catch (RemoteException e) { 198 } 199 return null; 200 } 201 202 /** 203 * Retrieve a PendingIntent that will perform a broadcast, like calling 204 * {@link Context#sendBroadcast(Intent) Context.sendBroadcast()}. 205 * 206 * @param context The Context in which this PendingIntent should perform 207 * the broadcast. 208 * @param requestCode Private request code for the sender (currently 209 * not used). 210 * @param intent The Intent to be broadcast. 211 * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE}, 212 * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT}, 213 * or any of the flags as supported by 214 * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts 215 * of the intent that can be supplied when the actual send happens. 216 * 217 * @return Returns an existing or new PendingIntent matching the given 218 * parameters. May return null only if {@link #FLAG_NO_CREATE} has been 219 * supplied. 220 */ 221 public static PendingIntent getBroadcast(Context context, int requestCode, 222 Intent intent, int flags) { 223 String packageName = context.getPackageName(); 224 String resolvedType = intent != null ? intent.resolveTypeIfNeeded( 225 context.getContentResolver()) : null; 226 try { 227 IIntentSender target = 228 ActivityManagerNative.getDefault().getIntentSender( 229 IActivityManager.INTENT_SENDER_BROADCAST, packageName, 230 null, null, requestCode, intent, resolvedType, flags); 231 return target != null ? new PendingIntent(target) : null; 232 } catch (RemoteException e) { 233 } 234 return null; 235 } 236 237 /** 238 * Retrieve a PendingIntent that will start a service, like calling 239 * {@link Context#startService Context.startService()}. The start 240 * arguments given to the service will come from the extras of the Intent. 241 * 242 * @param context The Context in which this PendingIntent should start 243 * the service. 244 * @param requestCode Private request code for the sender (currently 245 * not used). 246 * @param intent An Intent describing the service to be started. 247 * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE}, 248 * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT}, 249 * or any of the flags as supported by 250 * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts 251 * of the intent that can be supplied when the actual send happens. 252 * 253 * @return Returns an existing or new PendingIntent matching the given 254 * parameters. May return null only if {@link #FLAG_NO_CREATE} has been 255 * supplied. 256 */ 257 public static PendingIntent getService(Context context, int requestCode, 258 Intent intent, int flags) { 259 String packageName = context.getPackageName(); 260 String resolvedType = intent != null ? intent.resolveTypeIfNeeded( 261 context.getContentResolver()) : null; 262 try { 263 IIntentSender target = 264 ActivityManagerNative.getDefault().getIntentSender( 265 IActivityManager.INTENT_SENDER_SERVICE, packageName, 266 null, null, requestCode, intent, resolvedType, flags); 267 return target != null ? new PendingIntent(target) : null; 268 } catch (RemoteException e) { 269 } 270 return null; 271 } 272 273 /** 274 * Cancel a currently active PendingIntent. Only the original application 275 * owning an PendingIntent can cancel it. 276 */ 277 public void cancel() { 278 try { 279 ActivityManagerNative.getDefault().cancelIntentSender(mTarget); 280 } catch (RemoteException e) { 281 } 282 } 283 284 /** 285 * Perform the operation associated with this PendingIntent. 286 * 287 * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler) 288 * 289 * @throws CanceledException Throws CanceledException if the PendingIntent 290 * is no longer allowing more intents to be sent through it. 291 */ 292 public void send() throws CanceledException { 293 send(null, 0, null, null, null); 294 } 295 296 /** 297 * Perform the operation associated with this PendingIntent. 298 * 299 * @param code Result code to supply back to the PendingIntent's target. 300 * 301 * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler) 302 * 303 * @throws CanceledException Throws CanceledException if the PendingIntent 304 * is no longer allowing more intents to be sent through it. 305 */ 306 public void send(int code) throws CanceledException { 307 send(null, code, null, null, null); 308 } 309 310 /** 311 * Perform the operation associated with this PendingIntent, allowing the 312 * caller to specify information about the Intent to use. 313 * 314 * @param context The Context of the caller. 315 * @param code Result code to supply back to the PendingIntent's target. 316 * @param intent Additional Intent data. See {@link Intent#fillIn 317 * Intent.fillIn()} for information on how this is applied to the 318 * original Intent. 319 * 320 * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler) 321 * 322 * @throws CanceledException Throws CanceledException if the PendingIntent 323 * is no longer allowing more intents to be sent through it. 324 */ 325 public void send(Context context, int code, Intent intent) 326 throws CanceledException { 327 send(context, code, intent, null, null); 328 } 329 330 /** 331 * Perform the operation associated with this PendingIntent, allowing the 332 * caller to be notified when the send has completed. 333 * 334 * @param code Result code to supply back to the PendingIntent's target. 335 * @param onFinished The object to call back on when the send has 336 * completed, or null for no callback. 337 * @param handler Handler identifying the thread on which the callback 338 * should happen. If null, the callback will happen from the thread 339 * pool of the process. 340 * 341 * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler) 342 * 343 * @throws CanceledException Throws CanceledException if the PendingIntent 344 * is no longer allowing more intents to be sent through it. 345 */ 346 public void send(int code, OnFinished onFinished, Handler handler) 347 throws CanceledException { 348 send(null, code, null, onFinished, handler); 349 } 350 351 /** 352 * Perform the operation associated with this PendingIntent, allowing the 353 * caller to specify information about the Intent to use and be notified 354 * when the send has completed. 355 * 356 * <p>For the intent parameter, a PendingIntent 357 * often has restrictions on which fields can be supplied here, based on 358 * how the PendingIntent was retrieved in {@link #getActivity}, 359 * {@link #getBroadcast}, or {@link #getService}. 360 * 361 * @param context The Context of the caller. This may be null if 362 * <var>intent</var> is also null. 363 * @param code Result code to supply back to the PendingIntent's target. 364 * @param intent Additional Intent data. See {@link Intent#fillIn 365 * Intent.fillIn()} for information on how this is applied to the 366 * original Intent. Use null to not modify the original Intent. 367 * @param onFinished The object to call back on when the send has 368 * completed, or null for no callback. 369 * @param handler Handler identifying the thread on which the callback 370 * should happen. If null, the callback will happen from the thread 371 * pool of the process. 372 * 373 * @see #send() 374 * @see #send(int) 375 * @see #send(Context, int, Intent) 376 * @see #send(int, android.app.PendingIntent.OnFinished, Handler) 377 * 378 * @throws CanceledException Throws CanceledException if the PendingIntent 379 * is no longer allowing more intents to be sent through it. 380 */ 381 public void send(Context context, int code, Intent intent, 382 OnFinished onFinished, Handler handler) throws CanceledException { 383 try { 384 String resolvedType = intent != null ? 385 intent.resolveTypeIfNeeded(context.getContentResolver()) 386 : null; 387 int res = mTarget.send(code, intent, resolvedType, 388 onFinished != null 389 ? new FinishedDispatcher(this, onFinished, handler) 390 : null); 391 if (res < 0) { 392 throw new CanceledException(); 393 } 394 } catch (RemoteException e) { 395 throw new CanceledException(e); 396 } 397 } 398 399 /** 400 * Return the package name of the application that created this 401 * PendingIntent, that is the identity under which you will actually be 402 * sending the Intent. The returned string is supplied by the system, so 403 * that an application can not spoof its package. 404 * 405 * @return The package name of the PendingIntent, or null if there is 406 * none associated with it. 407 */ 408 public String getTargetPackage() { 409 try { 410 return ActivityManagerNative.getDefault() 411 .getPackageForIntentSender(mTarget); 412 } catch (RemoteException e) { 413 // Should never happen. 414 return null; 415 } 416 } 417 418 /** 419 * Comparison operator on two PendingIntent objects, such that true 420 * is returned then they both represent the same operation from the 421 * same package. This allows you to use {@link #getActivity}, 422 * {@link #getBroadcast}, or {@link #getService} multiple times (even 423 * across a process being killed), resulting in different PendingIntent 424 * objects but whose equals() method identifies them as being the same 425 * operation. 426 */ 427 @Override 428 public boolean equals(Object otherObj) { 429 if (otherObj instanceof PendingIntent) { 430 return mTarget.asBinder().equals(((PendingIntent)otherObj) 431 .mTarget.asBinder()); 432 } 433 return false; 434 } 435 436 @Override 437 public int hashCode() { 438 return mTarget.asBinder().hashCode(); 439 } 440 441 @Override 442 public String toString() { 443 return "PendingIntent{" 444 + Integer.toHexString(System.identityHashCode(this)) 445 + " target " + (mTarget != null ? mTarget.asBinder() : null) + "}"; 446 } 447 448 public int describeContents() { 449 return 0; 450 } 451 452 public void writeToParcel(Parcel out, int flags) { 453 out.writeStrongBinder(mTarget.asBinder()); 454 } 455 456 public static final Parcelable.Creator<PendingIntent> CREATOR 457 = new Parcelable.Creator<PendingIntent>() { 458 public PendingIntent createFromParcel(Parcel in) { 459 IBinder target = in.readStrongBinder(); 460 return target != null ? new PendingIntent(target) : null; 461 } 462 463 public PendingIntent[] newArray(int size) { 464 return new PendingIntent[size]; 465 } 466 }; 467 468 /** 469 * Convenience function for writing either a PendingIntent or null pointer to 470 * a Parcel. You must use this with {@link #readPendingIntentOrNullFromParcel} 471 * for later reading it. 472 * 473 * @param sender The PendingIntent to write, or null. 474 * @param out Where to write the PendingIntent. 475 */ 476 public static void writePendingIntentOrNullToParcel(PendingIntent sender, 477 Parcel out) { 478 out.writeStrongBinder(sender != null ? sender.mTarget.asBinder() 479 : null); 480 } 481 482 /** 483 * Convenience function for reading either a Messenger or null pointer from 484 * a Parcel. You must have previously written the Messenger with 485 * {@link #writePendingIntentOrNullToParcel}. 486 * 487 * @param in The Parcel containing the written Messenger. 488 * 489 * @return Returns the Messenger read from the Parcel, or null if null had 490 * been written. 491 */ 492 public static PendingIntent readPendingIntentOrNullFromParcel(Parcel in) { 493 IBinder b = in.readStrongBinder(); 494 return b != null ? new PendingIntent(b) : null; 495 } 496 497 /*package*/ PendingIntent(IIntentSender target) { 498 mTarget = target; 499 } 500 501 /*package*/ PendingIntent(IBinder target) { 502 mTarget = IIntentSender.Stub.asInterface(target); 503 } 504 505 /*package*/ IIntentSender getTarget() { 506 return mTarget; 507 } 508} 509