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