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.annotation.Nullable; 20 import android.app.ActivityManager; 21 import android.app.ActivityManager.PendingIntentInfo; 22 import android.app.ActivityOptions; 23 import android.compat.annotation.UnsupportedAppUsage; 24 import android.os.Bundle; 25 import android.os.Handler; 26 import android.os.IBinder; 27 import android.os.Parcel; 28 import android.os.Parcelable; 29 import android.os.RemoteException; 30 import android.os.UserHandle; 31 import android.util.AndroidException; 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 @UnsupportedAppUsage 62 private final IIntentSender mTarget; 63 IBinder mWhitelistToken; 64 65 // cached pending intent information 66 private @Nullable PendingIntentInfo mCachedInfo; 67 68 /** 69 * Exception thrown when trying to send through a PendingIntent that 70 * has been canceled or is otherwise no longer able to execute the request. 71 */ 72 public static class SendIntentException extends AndroidException { SendIntentException()73 public SendIntentException() { 74 } 75 SendIntentException(String name)76 public SendIntentException(String name) { 77 super(name); 78 } 79 SendIntentException(Exception cause)80 public SendIntentException(Exception cause) { 81 super(cause); 82 } 83 } 84 85 /** 86 * Callback interface for discovering when a send operation has 87 * completed. Primarily for use with a IntentSender that is 88 * performing a broadcast, this provides the same information as 89 * calling {@link Context#sendOrderedBroadcast(Intent, String, 90 * android.content.BroadcastReceiver, Handler, int, String, Bundle) 91 * Context.sendBroadcast()} with a final BroadcastReceiver. 92 */ 93 public interface OnFinished { 94 /** 95 * Called when a send operation as completed. 96 * 97 * @param IntentSender The IntentSender this operation was sent through. 98 * @param intent The original Intent that was sent. 99 * @param resultCode The final result code determined by the send. 100 * @param resultData The final data collected by a broadcast. 101 * @param resultExtras The final extras collected by a broadcast. 102 */ onSendFinished(IntentSender IntentSender, Intent intent, int resultCode, String resultData, Bundle resultExtras)103 void onSendFinished(IntentSender IntentSender, Intent intent, 104 int resultCode, String resultData, Bundle resultExtras); 105 } 106 107 private static class FinishedDispatcher extends IIntentReceiver.Stub 108 implements Runnable { 109 private final IntentSender mIntentSender; 110 private final OnFinished mWho; 111 private final Handler mHandler; 112 private Intent mIntent; 113 private int mResultCode; 114 private String mResultData; 115 private Bundle mResultExtras; FinishedDispatcher(IntentSender pi, OnFinished who, Handler handler)116 FinishedDispatcher(IntentSender pi, OnFinished who, Handler handler) { 117 mIntentSender = pi; 118 mWho = who; 119 mHandler = handler; 120 } performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean serialized, boolean sticky, int sendingUser)121 public void performReceive(Intent intent, int resultCode, String data, 122 Bundle extras, boolean serialized, boolean sticky, int sendingUser) { 123 mIntent = intent; 124 mResultCode = resultCode; 125 mResultData = data; 126 mResultExtras = extras; 127 if (mHandler == null) { 128 run(); 129 } else { 130 mHandler.post(this); 131 } 132 } run()133 public void run() { 134 mWho.onSendFinished(mIntentSender, mIntent, mResultCode, 135 mResultData, mResultExtras); 136 } 137 } 138 139 /** 140 * Perform the operation associated with this IntentSender, allowing the 141 * caller to specify information about the Intent to use and be notified 142 * when the send has completed. 143 * 144 * @param context The Context of the caller. This may be null if 145 * <var>intent</var> is also null. 146 * @param code Result code to supply back to the IntentSender's target. 147 * @param intent Additional Intent data. See {@link Intent#fillIn 148 * Intent.fillIn()} for information on how this is applied to the 149 * original Intent. Use null to not modify the original Intent. 150 * @param onFinished The object to call back on when the send has 151 * completed, or null for no callback. 152 * @param handler Handler identifying the thread on which the callback 153 * should happen. If null, the callback will happen from the thread 154 * pool of the process. 155 * 156 * 157 * @throws SendIntentException Throws CanceledIntentException if the IntentSender 158 * is no longer allowing more intents to be sent through it. 159 */ sendIntent(Context context, int code, Intent intent, OnFinished onFinished, Handler handler)160 public void sendIntent(Context context, int code, Intent intent, 161 OnFinished onFinished, Handler handler) throws SendIntentException { 162 sendIntent(context, code, intent, onFinished, handler, null, null /* options */); 163 } 164 165 /** 166 * Perform the operation associated with this IntentSender, allowing the 167 * caller to specify information about the Intent to use and be notified 168 * when the send has completed. 169 * 170 * @param context The Context of the caller. This may be null if 171 * <var>intent</var> is also null. 172 * @param code Result code to supply back to the IntentSender's target. 173 * @param intent Additional Intent data. See {@link Intent#fillIn 174 * Intent.fillIn()} for information on how this is applied to the 175 * original Intent. Use null to not modify the original Intent. 176 * @param onFinished The object to call back on when the send has 177 * completed, or null for no callback. 178 * @param handler Handler identifying the thread on which the callback 179 * should happen. If null, the callback will happen from the thread 180 * pool of the process. 181 * @param requiredPermission Name of permission that a recipient of the PendingIntent 182 * is required to hold. This is only valid for broadcast intents, and 183 * corresponds to the permission argument in 184 * {@link Context#sendBroadcast(Intent, String) Context.sendOrderedBroadcast(Intent, String)}. 185 * If null, no permission is required. 186 * 187 * 188 * @throws SendIntentException Throws CanceledIntentException if the IntentSender 189 * is no longer allowing more intents to be sent through it. 190 */ sendIntent(Context context, int code, Intent intent, OnFinished onFinished, Handler handler, String requiredPermission)191 public void sendIntent(Context context, int code, Intent intent, 192 OnFinished onFinished, Handler handler, String requiredPermission) 193 throws SendIntentException { 194 sendIntent(context, code, intent, onFinished, handler, requiredPermission, 195 null /* options */); 196 } 197 198 /** 199 * Perform the operation associated with this IntentSender, allowing the 200 * caller to specify information about the Intent to use and be notified 201 * when the send has completed. 202 * 203 * @param context The Context of the caller. This may be null if 204 * <var>intent</var> is also null. 205 * @param code Result code to supply back to the IntentSender's target. 206 * @param intent Additional Intent data. See {@link Intent#fillIn 207 * Intent.fillIn()} for information on how this is applied to the 208 * original Intent. Use null to not modify the original Intent. 209 * @param onFinished The object to call back on when the send has 210 * completed, or null for no callback. 211 * @param handler Handler identifying the thread on which the callback 212 * should happen. If null, the callback will happen from the thread 213 * pool of the process. 214 * @param requiredPermission Name of permission that a recipient of the PendingIntent 215 * is required to hold. This is only valid for broadcast intents, and 216 * corresponds to the permission argument in 217 * {@link Context#sendBroadcast(Intent, String) Context.sendOrderedBroadcast(Intent, String)}. 218 * If null, no permission is required. 219 * @param options Additional options the caller would like to provide to modify the sending 220 * behavior. May be built from an {@link ActivityOptions} to apply to an activity start. 221 * 222 * @throws SendIntentException Throws CanceledIntentException if the IntentSender 223 * is no longer allowing more intents to be sent through it. 224 * @hide 225 */ sendIntent(Context context, int code, Intent intent, OnFinished onFinished, Handler handler, String requiredPermission, @Nullable Bundle options)226 public void sendIntent(Context context, int code, Intent intent, 227 OnFinished onFinished, Handler handler, String requiredPermission, 228 @Nullable Bundle options) 229 throws SendIntentException { 230 try { 231 String resolvedType = intent != null ? 232 intent.resolveTypeIfNeeded(context.getContentResolver()) 233 : null; 234 int res = ActivityManager.getService().sendIntentSender(mTarget, mWhitelistToken, 235 code, intent, resolvedType, 236 onFinished != null 237 ? new FinishedDispatcher(this, onFinished, handler) 238 : null, 239 requiredPermission, options); 240 if (res < 0) { 241 throw new SendIntentException(); 242 } 243 } catch (RemoteException e) { 244 throw new SendIntentException(); 245 } 246 } 247 248 /** 249 * @deprecated Renamed to {@link #getCreatorPackage()}. 250 */ 251 @Deprecated getTargetPackage()252 public String getTargetPackage() { 253 return getCreatorPackage(); 254 } 255 256 /** 257 * Return the package name of the application that created this 258 * IntentSender, that is the identity under which you will actually be 259 * sending the Intent. The returned string is supplied by the system, so 260 * that an application can not spoof its package. 261 * 262 * @return The package name of the PendingIntent, or null if there is 263 * none associated with it. 264 */ getCreatorPackage()265 public String getCreatorPackage() { 266 return getCachedInfo().getCreatorPackage(); 267 } 268 269 /** 270 * Return the uid of the application that created this 271 * PendingIntent, that is the identity under which you will actually be 272 * sending the Intent. The returned integer is supplied by the system, so 273 * that an application can not spoof its uid. 274 * 275 * @return The uid of the PendingIntent, or -1 if there is 276 * none associated with it. 277 */ getCreatorUid()278 public int getCreatorUid() { 279 return getCachedInfo().getCreatorUid(); 280 } 281 282 /** 283 * Return the user handle of the application that created this 284 * PendingIntent, that is the user under which you will actually be 285 * sending the Intent. The returned UserHandle is supplied by the system, so 286 * that an application can not spoof its user. See 287 * {@link android.os.Process#myUserHandle() Process.myUserHandle()} for 288 * more explanation of user handles. 289 * 290 * @return The user handle of the PendingIntent, or null if there is 291 * none associated with it. 292 */ getCreatorUserHandle()293 public UserHandle getCreatorUserHandle() { 294 int uid = getCachedInfo().getCreatorUid(); 295 return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null; 296 } 297 298 /** 299 * Comparison operator on two IntentSender objects, such that true 300 * is returned then they both represent the same operation from the 301 * same package. 302 */ 303 @Override equals(@ullable Object otherObj)304 public boolean equals(@Nullable Object otherObj) { 305 if (otherObj instanceof IntentSender) { 306 return mTarget.asBinder().equals(((IntentSender)otherObj) 307 .mTarget.asBinder()); 308 } 309 return false; 310 } 311 312 @Override hashCode()313 public int hashCode() { 314 return mTarget.asBinder().hashCode(); 315 } 316 317 @Override toString()318 public String toString() { 319 StringBuilder sb = new StringBuilder(128); 320 sb.append("IntentSender{"); 321 sb.append(Integer.toHexString(System.identityHashCode(this))); 322 sb.append(": "); 323 sb.append(mTarget != null ? mTarget.asBinder() : null); 324 sb.append('}'); 325 return sb.toString(); 326 } 327 describeContents()328 public int describeContents() { 329 return 0; 330 } 331 writeToParcel(Parcel out, int flags)332 public void writeToParcel(Parcel out, int flags) { 333 out.writeStrongBinder(mTarget.asBinder()); 334 } 335 336 public static final @android.annotation.NonNull Parcelable.Creator<IntentSender> CREATOR 337 = new Parcelable.Creator<IntentSender>() { 338 public IntentSender createFromParcel(Parcel in) { 339 IBinder target = in.readStrongBinder(); 340 return target != null ? new IntentSender(target) : null; 341 } 342 343 public IntentSender[] newArray(int size) { 344 return new IntentSender[size]; 345 } 346 }; 347 348 /** 349 * Convenience function for writing either a IntentSender or null pointer to 350 * a Parcel. You must use this with {@link #readIntentSenderOrNullFromParcel} 351 * for later reading it. 352 * 353 * @param sender The IntentSender to write, or null. 354 * @param out Where to write the IntentSender. 355 */ writeIntentSenderOrNullToParcel(IntentSender sender, Parcel out)356 public static void writeIntentSenderOrNullToParcel(IntentSender sender, 357 Parcel out) { 358 out.writeStrongBinder(sender != null ? sender.mTarget.asBinder() 359 : null); 360 } 361 362 /** 363 * Convenience function for reading either a Messenger or null pointer from 364 * a Parcel. You must have previously written the Messenger with 365 * {@link #writeIntentSenderOrNullToParcel}. 366 * 367 * @param in The Parcel containing the written Messenger. 368 * 369 * @return Returns the Messenger read from the Parcel, or null if null had 370 * been written. 371 */ readIntentSenderOrNullFromParcel(Parcel in)372 public static IntentSender readIntentSenderOrNullFromParcel(Parcel in) { 373 IBinder b = in.readStrongBinder(); 374 return b != null ? new IntentSender(b) : null; 375 } 376 377 /** @hide */ 378 @UnsupportedAppUsage getTarget()379 public IIntentSender getTarget() { 380 return mTarget; 381 } 382 383 /** @hide */ getWhitelistToken()384 public IBinder getWhitelistToken() { 385 return mWhitelistToken; 386 } 387 388 /** @hide */ 389 @UnsupportedAppUsage IntentSender(IIntentSender target)390 public IntentSender(IIntentSender target) { 391 mTarget = target; 392 } 393 394 /** @hide */ IntentSender(IIntentSender target, IBinder whitelistToken)395 public IntentSender(IIntentSender target, IBinder whitelistToken) { 396 mTarget = target; 397 mWhitelistToken = whitelistToken; 398 } 399 400 /** @hide */ IntentSender(IBinder target)401 public IntentSender(IBinder target) { 402 mTarget = IIntentSender.Stub.asInterface(target); 403 } 404 getCachedInfo()405 private PendingIntentInfo getCachedInfo() { 406 if (mCachedInfo == null) { 407 try { 408 mCachedInfo = ActivityManager.getService().getInfoForIntentSender(mTarget); 409 } catch (RemoteException e) { 410 throw e.rethrowFromSystemServer(); 411 } 412 } 413 414 return mCachedInfo; 415 } 416 } 417