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