1 /* 2 * Copyright (C) 2007 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.pm; 18 19 import android.annotation.SystemApi; 20 import android.compat.annotation.UnsupportedAppUsage; 21 import android.content.ComponentName; 22 import android.content.IntentFilter; 23 import android.graphics.drawable.Drawable; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 import android.os.UserHandle; 27 import android.text.TextUtils; 28 import android.util.Printer; 29 import android.util.Slog; 30 31 import java.text.Collator; 32 import java.util.Comparator; 33 34 /** 35 * Information that is returned from resolving an intent 36 * against an IntentFilter. This partially corresponds to 37 * information collected from the AndroidManifest.xml's 38 * <intent> tags. 39 */ 40 public class ResolveInfo implements Parcelable { 41 private static final String TAG = "ResolveInfo"; 42 43 /** 44 * The activity or broadcast receiver that corresponds to this resolution 45 * match, if this resolution is for an activity or broadcast receiver. 46 * Exactly one of {@link #activityInfo}, {@link #serviceInfo}, or 47 * {@link #providerInfo} will be non-null. 48 */ 49 public ActivityInfo activityInfo; 50 51 /** 52 * The service that corresponds to this resolution match, if this resolution 53 * is for a service. Exactly one of {@link #activityInfo}, 54 * {@link #serviceInfo}, or {@link #providerInfo} will be non-null. 55 */ 56 public ServiceInfo serviceInfo; 57 58 /** 59 * The provider that corresponds to this resolution match, if this 60 * resolution is for a provider. Exactly one of {@link #activityInfo}, 61 * {@link #serviceInfo}, or {@link #providerInfo} will be non-null. 62 */ 63 public ProviderInfo providerInfo; 64 65 /** 66 * An auxiliary response that may modify the resolved information. This is 67 * only set under certain circumstances; such as when resolving instant apps 68 * or components defined in un-installed splits. 69 * @hide 70 */ 71 public AuxiliaryResolveInfo auxiliaryInfo; 72 73 /** 74 * Whether or not an instant app is available for the resolved intent. 75 */ 76 public boolean isInstantAppAvailable; 77 78 /** @removed */ 79 @Deprecated 80 public boolean instantAppAvailable; 81 82 /** 83 * The IntentFilter that was matched for this ResolveInfo. 84 */ 85 public IntentFilter filter; 86 87 /** 88 * The declared priority of this match. Comes from the "priority" 89 * attribute or, if not set, defaults to 0. Higher values are a higher 90 * priority. 91 */ 92 public int priority; 93 94 /** 95 * Order of result according to the user's preference. If the user 96 * has not set a preference for this result, the value is 0; higher 97 * values are a higher priority. 98 */ 99 public int preferredOrder; 100 101 /** 102 * The system's evaluation of how well the activity matches the 103 * IntentFilter. This is a match constant, a combination of 104 * {@link IntentFilter#MATCH_CATEGORY_MASK IntentFilter.MATCH_CATEGORY_MASK} 105 * and {@link IntentFilter#MATCH_ADJUSTMENT_MASK IntentFiler.MATCH_ADJUSTMENT_MASK}. 106 */ 107 public int match; 108 109 /** 110 * Only set when returned by 111 * {@link PackageManager#queryIntentActivityOptions}, this tells you 112 * which of the given specific intents this result came from. 0 is the 113 * first in the list, < 0 means it came from the generic Intent query. 114 */ 115 public int specificIndex = -1; 116 117 /** 118 * This filter has specified the Intent.CATEGORY_DEFAULT, meaning it 119 * would like to be considered a default action that the user can 120 * perform on this data. 121 */ 122 public boolean isDefault; 123 124 /** 125 * A string resource identifier (in the package's resources) of this 126 * match's label. From the "label" attribute or, if not set, 0. 127 */ 128 public int labelRes; 129 130 /** 131 * The actual string retrieve from <var>labelRes</var> or null if none 132 * was provided. 133 */ 134 public CharSequence nonLocalizedLabel; 135 136 /** 137 * A drawable resource identifier (in the package's resources) of this 138 * match's icon. From the "icon" attribute or, if not set, 0. It is 139 * set only if the icon can be obtained by resource id alone. 140 */ 141 public int icon; 142 143 /** 144 * Optional -- if non-null, the {@link #labelRes} and {@link #icon} 145 * resources will be loaded from this package, rather than the one 146 * containing the resolved component. 147 */ 148 public String resolvePackageName; 149 150 /** 151 * If not equal to UserHandle.USER_CURRENT, then the intent will be forwarded to this user. 152 * @hide 153 */ 154 @UnsupportedAppUsage 155 public int targetUserId; 156 157 /** 158 * Set to true if the icon cannot be obtained by resource ids alone. 159 * It is set to true for ResolveInfos from the managed profile: They need to 160 * have their icon badged, so it cannot be obtained by resource ids alone. 161 * @hide 162 */ 163 public boolean noResourceId; 164 165 /** 166 * Same as {@link #icon} but it will always correspond to "icon" attribute 167 * regardless of {@link #noResourceId} value. 168 * @hide 169 */ 170 public int iconResourceId; 171 172 /** 173 * @hide Target comes from system process? 174 */ 175 @UnsupportedAppUsage 176 public boolean system; 177 178 /** 179 * Will be set to {@code true} if the {@link IntentFilter} responsible for intent 180 * resolution is classified as a "browser". 181 * 182 * @hide 183 */ 184 @SystemApi 185 public boolean handleAllWebDataURI; 186 187 /** {@hide} */ 188 @UnsupportedAppUsage getComponentInfo()189 public ComponentInfo getComponentInfo() { 190 if (activityInfo != null) return activityInfo; 191 if (serviceInfo != null) return serviceInfo; 192 if (providerInfo != null) return providerInfo; 193 throw new IllegalStateException("Missing ComponentInfo!"); 194 } 195 196 /** 197 * Retrieve the current textual label associated with this resolution. This 198 * will call back on the given PackageManager to load the label from 199 * the application. 200 * 201 * @param pm A PackageManager from which the label can be loaded; usually 202 * the PackageManager from which you originally retrieved this item. 203 * 204 * @return Returns a CharSequence containing the resolutions's label. If the 205 * item does not have a label, its name is returned. 206 */ loadLabel(PackageManager pm)207 public CharSequence loadLabel(PackageManager pm) { 208 if (nonLocalizedLabel != null) { 209 return nonLocalizedLabel; 210 } 211 CharSequence label; 212 if (resolvePackageName != null && labelRes != 0) { 213 label = pm.getText(resolvePackageName, labelRes, null); 214 if (label != null) { 215 return label.toString().trim(); 216 } 217 } 218 ComponentInfo ci = getComponentInfo(); 219 ApplicationInfo ai = ci.applicationInfo; 220 if (labelRes != 0) { 221 label = pm.getText(ci.packageName, labelRes, ai); 222 if (label != null) { 223 return label.toString().trim(); 224 } 225 } 226 227 CharSequence data = ci.loadLabel(pm); 228 // Make the data safe 229 if (data != null) data = data.toString().trim(); 230 return data; 231 } 232 233 /** 234 * @return The resource that would be used when loading 235 * the label for this resolve info. 236 * 237 * @hide 238 */ resolveLabelResId()239 public int resolveLabelResId() { 240 if (labelRes != 0) { 241 return labelRes; 242 } 243 final ComponentInfo componentInfo = getComponentInfo(); 244 if (componentInfo.labelRes != 0) { 245 return componentInfo.labelRes; 246 } 247 return componentInfo.applicationInfo.labelRes; 248 } 249 250 /** 251 * @return The resource that would be used when loading 252 * the icon for this resolve info. 253 * 254 * @hide 255 */ resolveIconResId()256 public int resolveIconResId() { 257 if (icon != 0) { 258 return icon; 259 } 260 final ComponentInfo componentInfo = getComponentInfo(); 261 if (componentInfo.icon != 0) { 262 return componentInfo.icon; 263 } 264 return componentInfo.applicationInfo.icon; 265 } 266 267 /** 268 * Retrieve the current graphical icon associated with this resolution. This 269 * will call back on the given PackageManager to load the icon from 270 * the application. 271 * 272 * @param pm A PackageManager from which the icon can be loaded; usually 273 * the PackageManager from which you originally retrieved this item. 274 * 275 * @return Returns a Drawable containing the resolution's icon. If the 276 * item does not have an icon, the default activity icon is returned. 277 */ loadIcon(PackageManager pm)278 public Drawable loadIcon(PackageManager pm) { 279 Drawable dr = null; 280 if (resolvePackageName != null && iconResourceId != 0) { 281 dr = pm.getDrawable(resolvePackageName, iconResourceId, null); 282 } 283 ComponentInfo ci = getComponentInfo(); 284 if (dr == null && iconResourceId != 0) { 285 ApplicationInfo ai = ci.applicationInfo; 286 dr = pm.getDrawable(ci.packageName, iconResourceId, ai); 287 } 288 if (dr != null) { 289 return pm.getUserBadgedIcon(dr, new UserHandle(pm.getUserId())); 290 } 291 return ci.loadIcon(pm); 292 } 293 294 /** 295 * Return the icon resource identifier to use for this match. If the 296 * match defines an icon, that is used; else if the activity defines 297 * an icon, that is used; else, the application icon is used. 298 * This function does not check noResourceId flag. 299 * 300 * @return The icon associated with this match. 301 */ getIconResourceInternal()302 final int getIconResourceInternal() { 303 if (iconResourceId != 0) return iconResourceId; 304 final ComponentInfo ci = getComponentInfo(); 305 if (ci != null) { 306 return ci.getIconResource(); 307 } 308 return 0; 309 } 310 311 /** 312 * Return the icon resource identifier to use for this match. If the 313 * match defines an icon, that is used; else if the activity defines 314 * an icon, that is used; else, the application icon is used. 315 * 316 * @return The icon associated with this match. 317 */ getIconResource()318 public final int getIconResource() { 319 if (noResourceId) return 0; 320 return getIconResourceInternal(); 321 } 322 dump(Printer pw, String prefix)323 public void dump(Printer pw, String prefix) { 324 dump(pw, prefix, PackageItemInfo.DUMP_FLAG_ALL); 325 } 326 327 /** @hide */ dump(Printer pw, String prefix, int dumpFlags)328 public void dump(Printer pw, String prefix, int dumpFlags) { 329 if (filter != null) { 330 pw.println(prefix + "Filter:"); 331 filter.dump(pw, prefix + " "); 332 } 333 pw.println(prefix + "priority=" + priority 334 + " preferredOrder=" + preferredOrder 335 + " match=0x" + Integer.toHexString(match) 336 + " specificIndex=" + specificIndex 337 + " isDefault=" + isDefault); 338 if (resolvePackageName != null) { 339 pw.println(prefix + "resolvePackageName=" + resolvePackageName); 340 } 341 if (labelRes != 0 || nonLocalizedLabel != null || icon != 0) { 342 pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes) 343 + " nonLocalizedLabel=" + nonLocalizedLabel 344 + " icon=0x" + Integer.toHexString(icon)); 345 } 346 if (activityInfo != null) { 347 pw.println(prefix + "ActivityInfo:"); 348 activityInfo.dump(pw, prefix + " ", dumpFlags); 349 } else if (serviceInfo != null) { 350 pw.println(prefix + "ServiceInfo:"); 351 serviceInfo.dump(pw, prefix + " ", dumpFlags); 352 } else if (providerInfo != null) { 353 pw.println(prefix + "ProviderInfo:"); 354 providerInfo.dump(pw, prefix + " ", dumpFlags); 355 } 356 } 357 ResolveInfo()358 public ResolveInfo() { 359 targetUserId = UserHandle.USER_CURRENT; 360 } 361 ResolveInfo(ResolveInfo orig)362 public ResolveInfo(ResolveInfo orig) { 363 activityInfo = orig.activityInfo; 364 serviceInfo = orig.serviceInfo; 365 providerInfo = orig.providerInfo; 366 filter = orig.filter; 367 priority = orig.priority; 368 preferredOrder = orig.preferredOrder; 369 match = orig.match; 370 specificIndex = orig.specificIndex; 371 labelRes = orig.labelRes; 372 nonLocalizedLabel = orig.nonLocalizedLabel; 373 icon = orig.icon; 374 resolvePackageName = orig.resolvePackageName; 375 noResourceId = orig.noResourceId; 376 iconResourceId = orig.iconResourceId; 377 system = orig.system; 378 targetUserId = orig.targetUserId; 379 handleAllWebDataURI = orig.handleAllWebDataURI; 380 isInstantAppAvailable = orig.isInstantAppAvailable; 381 instantAppAvailable = isInstantAppAvailable; 382 } 383 toString()384 public String toString() { 385 final ComponentInfo ci = getComponentInfo(); 386 StringBuilder sb = new StringBuilder(128); 387 sb.append("ResolveInfo{"); 388 sb.append(Integer.toHexString(System.identityHashCode(this))); 389 sb.append(' '); 390 ComponentName.appendShortString(sb, ci.packageName, ci.name); 391 if (priority != 0) { 392 sb.append(" p="); 393 sb.append(priority); 394 } 395 if (preferredOrder != 0) { 396 sb.append(" o="); 397 sb.append(preferredOrder); 398 } 399 sb.append(" m=0x"); 400 sb.append(Integer.toHexString(match)); 401 if (targetUserId != UserHandle.USER_CURRENT) { 402 sb.append(" targetUserId="); 403 sb.append(targetUserId); 404 } 405 sb.append('}'); 406 return sb.toString(); 407 } 408 describeContents()409 public int describeContents() { 410 return 0; 411 } 412 writeToParcel(Parcel dest, int parcelableFlags)413 public void writeToParcel(Parcel dest, int parcelableFlags) { 414 if (activityInfo != null) { 415 dest.writeInt(1); 416 activityInfo.writeToParcel(dest, parcelableFlags); 417 } else if (serviceInfo != null) { 418 dest.writeInt(2); 419 serviceInfo.writeToParcel(dest, parcelableFlags); 420 } else if (providerInfo != null) { 421 dest.writeInt(3); 422 providerInfo.writeToParcel(dest, parcelableFlags); 423 } else { 424 dest.writeInt(0); 425 } 426 if (filter != null) { 427 dest.writeInt(1); 428 filter.writeToParcel(dest, parcelableFlags); 429 } else { 430 dest.writeInt(0); 431 } 432 dest.writeInt(priority); 433 dest.writeInt(preferredOrder); 434 dest.writeInt(match); 435 dest.writeInt(specificIndex); 436 dest.writeInt(labelRes); 437 TextUtils.writeToParcel(nonLocalizedLabel, dest, parcelableFlags); 438 dest.writeInt(icon); 439 dest.writeString(resolvePackageName); 440 dest.writeInt(targetUserId); 441 dest.writeInt(system ? 1 : 0); 442 dest.writeInt(noResourceId ? 1 : 0); 443 dest.writeInt(iconResourceId); 444 dest.writeInt(handleAllWebDataURI ? 1 : 0); 445 dest.writeInt(isInstantAppAvailable ? 1 : 0); 446 } 447 448 public static final @android.annotation.NonNull Creator<ResolveInfo> CREATOR 449 = new Creator<ResolveInfo>() { 450 public ResolveInfo createFromParcel(Parcel source) { 451 return new ResolveInfo(source); 452 } 453 public ResolveInfo[] newArray(int size) { 454 return new ResolveInfo[size]; 455 } 456 }; 457 ResolveInfo(Parcel source)458 private ResolveInfo(Parcel source) { 459 activityInfo = null; 460 serviceInfo = null; 461 providerInfo = null; 462 switch (source.readInt()) { 463 case 1: 464 activityInfo = ActivityInfo.CREATOR.createFromParcel(source); 465 break; 466 case 2: 467 serviceInfo = ServiceInfo.CREATOR.createFromParcel(source); 468 break; 469 case 3: 470 providerInfo = ProviderInfo.CREATOR.createFromParcel(source); 471 break; 472 default: 473 Slog.w(TAG, "Missing ComponentInfo!"); 474 break; 475 } 476 if (source.readInt() != 0) { 477 filter = IntentFilter.CREATOR.createFromParcel(source); 478 } 479 priority = source.readInt(); 480 preferredOrder = source.readInt(); 481 match = source.readInt(); 482 specificIndex = source.readInt(); 483 labelRes = source.readInt(); 484 nonLocalizedLabel 485 = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 486 icon = source.readInt(); 487 resolvePackageName = source.readString(); 488 targetUserId = source.readInt(); 489 system = source.readInt() != 0; 490 noResourceId = source.readInt() != 0; 491 iconResourceId = source.readInt(); 492 handleAllWebDataURI = source.readInt() != 0; 493 instantAppAvailable = isInstantAppAvailable = source.readInt() != 0; 494 } 495 496 public static class DisplayNameComparator 497 implements Comparator<ResolveInfo> { DisplayNameComparator(PackageManager pm)498 public DisplayNameComparator(PackageManager pm) { 499 mPM = pm; 500 mCollator.setStrength(Collator.PRIMARY); 501 } 502 compare(ResolveInfo a, ResolveInfo b)503 public final int compare(ResolveInfo a, ResolveInfo b) { 504 // We want to put the one targeted to another user at the end of the dialog. 505 if (a.targetUserId != UserHandle.USER_CURRENT) { 506 return 1; 507 } 508 if (b.targetUserId != UserHandle.USER_CURRENT) { 509 return -1; 510 } 511 CharSequence sa = a.loadLabel(mPM); 512 if (sa == null) sa = a.activityInfo.name; 513 CharSequence sb = b.loadLabel(mPM); 514 if (sb == null) sb = b.activityInfo.name; 515 516 return mCollator.compare(sa.toString(), sb.toString()); 517 } 518 519 private final Collator mCollator = Collator.getInstance(); 520 private PackageManager mPM; 521 } 522 } 523