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 * Retrieve the current graphical icon associated with this resolution. This 226 * will call back on the given PackageManager to load the icon from 227 * the application. 228 * 229 * @param pm A PackageManager from which the icon can be loaded; usually 230 * the PackageManager from which you originally retrieved this item. 231 * 232 * @return Returns a Drawable containing the resolution's icon. If the 233 * item does not have an icon, the default activity icon is returned. 234 */ loadIcon(PackageManager pm)235 public Drawable loadIcon(PackageManager pm) { 236 Drawable dr = null; 237 if (resolvePackageName != null && iconResourceId != 0) { 238 dr = pm.getDrawable(resolvePackageName, iconResourceId, null); 239 } 240 ComponentInfo ci = getComponentInfo(); 241 if (dr == null && iconResourceId != 0) { 242 ApplicationInfo ai = ci.applicationInfo; 243 dr = pm.getDrawable(ci.packageName, iconResourceId, ai); 244 } 245 if (dr != null) { 246 return pm.getUserBadgedIcon(dr, new UserHandle(UserHandle.myUserId())); 247 } 248 return ci.loadIcon(pm); 249 } 250 251 /** 252 * Return the icon resource identifier to use for this match. If the 253 * match defines an icon, that is used; else if the activity defines 254 * an icon, that is used; else, the application icon is used. 255 * This function does not check noResourceId flag. 256 * 257 * @return The icon associated with this match. 258 */ getIconResourceInternal()259 final int getIconResourceInternal() { 260 if (iconResourceId != 0) return iconResourceId; 261 final ComponentInfo ci = getComponentInfo(); 262 if (ci != null) { 263 return ci.getIconResource(); 264 } 265 return 0; 266 } 267 268 /** 269 * Return the icon resource identifier to use for this match. If the 270 * match defines an icon, that is used; else if the activity defines 271 * an icon, that is used; else, the application icon is used. 272 * 273 * @return The icon associated with this match. 274 */ getIconResource()275 public final int getIconResource() { 276 if (noResourceId) return 0; 277 return getIconResourceInternal(); 278 } 279 dump(Printer pw, String prefix)280 public void dump(Printer pw, String prefix) { 281 dump(pw, prefix, PackageItemInfo.DUMP_FLAG_ALL); 282 } 283 284 /** @hide */ dump(Printer pw, String prefix, int flags)285 public void dump(Printer pw, String prefix, int flags) { 286 if (filter != null) { 287 pw.println(prefix + "Filter:"); 288 filter.dump(pw, prefix + " "); 289 } 290 pw.println(prefix + "priority=" + priority 291 + " preferredOrder=" + preferredOrder 292 + " match=0x" + Integer.toHexString(match) 293 + " specificIndex=" + specificIndex 294 + " isDefault=" + isDefault); 295 if (resolvePackageName != null) { 296 pw.println(prefix + "resolvePackageName=" + resolvePackageName); 297 } 298 if (labelRes != 0 || nonLocalizedLabel != null || icon != 0) { 299 pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes) 300 + " nonLocalizedLabel=" + nonLocalizedLabel 301 + " icon=0x" + Integer.toHexString(icon)); 302 } 303 if (activityInfo != null) { 304 pw.println(prefix + "ActivityInfo:"); 305 activityInfo.dump(pw, prefix + " ", flags); 306 } else if (serviceInfo != null) { 307 pw.println(prefix + "ServiceInfo:"); 308 serviceInfo.dump(pw, prefix + " ", flags); 309 } else if (providerInfo != null) { 310 pw.println(prefix + "ProviderInfo:"); 311 providerInfo.dump(pw, prefix + " ", flags); 312 } 313 } 314 ResolveInfo()315 public ResolveInfo() { 316 targetUserId = UserHandle.USER_CURRENT; 317 } 318 ResolveInfo(ResolveInfo orig)319 public ResolveInfo(ResolveInfo orig) { 320 activityInfo = orig.activityInfo; 321 serviceInfo = orig.serviceInfo; 322 providerInfo = orig.providerInfo; 323 filter = orig.filter; 324 priority = orig.priority; 325 preferredOrder = orig.preferredOrder; 326 match = orig.match; 327 specificIndex = orig.specificIndex; 328 labelRes = orig.labelRes; 329 nonLocalizedLabel = orig.nonLocalizedLabel; 330 icon = orig.icon; 331 resolvePackageName = orig.resolvePackageName; 332 noResourceId = orig.noResourceId; 333 iconResourceId = orig.iconResourceId; 334 system = orig.system; 335 targetUserId = orig.targetUserId; 336 handleAllWebDataURI = orig.handleAllWebDataURI; 337 isInstantAppAvailable = orig.isInstantAppAvailable; 338 instantAppAvailable = isInstantAppAvailable; 339 } 340 toString()341 public String toString() { 342 final ComponentInfo ci = getComponentInfo(); 343 StringBuilder sb = new StringBuilder(128); 344 sb.append("ResolveInfo{"); 345 sb.append(Integer.toHexString(System.identityHashCode(this))); 346 sb.append(' '); 347 ComponentName.appendShortString(sb, ci.packageName, ci.name); 348 if (priority != 0) { 349 sb.append(" p="); 350 sb.append(priority); 351 } 352 if (preferredOrder != 0) { 353 sb.append(" o="); 354 sb.append(preferredOrder); 355 } 356 sb.append(" m=0x"); 357 sb.append(Integer.toHexString(match)); 358 if (targetUserId != UserHandle.USER_CURRENT) { 359 sb.append(" targetUserId="); 360 sb.append(targetUserId); 361 } 362 sb.append('}'); 363 return sb.toString(); 364 } 365 describeContents()366 public int describeContents() { 367 return 0; 368 } 369 writeToParcel(Parcel dest, int parcelableFlags)370 public void writeToParcel(Parcel dest, int parcelableFlags) { 371 if (activityInfo != null) { 372 dest.writeInt(1); 373 activityInfo.writeToParcel(dest, parcelableFlags); 374 } else if (serviceInfo != null) { 375 dest.writeInt(2); 376 serviceInfo.writeToParcel(dest, parcelableFlags); 377 } else if (providerInfo != null) { 378 dest.writeInt(3); 379 providerInfo.writeToParcel(dest, parcelableFlags); 380 } else { 381 dest.writeInt(0); 382 } 383 if (filter != null) { 384 dest.writeInt(1); 385 filter.writeToParcel(dest, parcelableFlags); 386 } else { 387 dest.writeInt(0); 388 } 389 dest.writeInt(priority); 390 dest.writeInt(preferredOrder); 391 dest.writeInt(match); 392 dest.writeInt(specificIndex); 393 dest.writeInt(labelRes); 394 TextUtils.writeToParcel(nonLocalizedLabel, dest, parcelableFlags); 395 dest.writeInt(icon); 396 dest.writeString(resolvePackageName); 397 dest.writeInt(targetUserId); 398 dest.writeInt(system ? 1 : 0); 399 dest.writeInt(noResourceId ? 1 : 0); 400 dest.writeInt(iconResourceId); 401 dest.writeInt(handleAllWebDataURI ? 1 : 0); 402 dest.writeInt(isInstantAppAvailable ? 1 : 0); 403 } 404 405 public static final Creator<ResolveInfo> CREATOR 406 = new Creator<ResolveInfo>() { 407 public ResolveInfo createFromParcel(Parcel source) { 408 return new ResolveInfo(source); 409 } 410 public ResolveInfo[] newArray(int size) { 411 return new ResolveInfo[size]; 412 } 413 }; 414 ResolveInfo(Parcel source)415 private ResolveInfo(Parcel source) { 416 activityInfo = null; 417 serviceInfo = null; 418 providerInfo = null; 419 switch (source.readInt()) { 420 case 1: 421 activityInfo = ActivityInfo.CREATOR.createFromParcel(source); 422 break; 423 case 2: 424 serviceInfo = ServiceInfo.CREATOR.createFromParcel(source); 425 break; 426 case 3: 427 providerInfo = ProviderInfo.CREATOR.createFromParcel(source); 428 break; 429 default: 430 Slog.w(TAG, "Missing ComponentInfo!"); 431 break; 432 } 433 if (source.readInt() != 0) { 434 filter = IntentFilter.CREATOR.createFromParcel(source); 435 } 436 priority = source.readInt(); 437 preferredOrder = source.readInt(); 438 match = source.readInt(); 439 specificIndex = source.readInt(); 440 labelRes = source.readInt(); 441 nonLocalizedLabel 442 = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 443 icon = source.readInt(); 444 resolvePackageName = source.readString(); 445 targetUserId = source.readInt(); 446 system = source.readInt() != 0; 447 noResourceId = source.readInt() != 0; 448 iconResourceId = source.readInt(); 449 handleAllWebDataURI = source.readInt() != 0; 450 instantAppAvailable = isInstantAppAvailable = source.readInt() != 0; 451 } 452 453 public static class DisplayNameComparator 454 implements Comparator<ResolveInfo> { DisplayNameComparator(PackageManager pm)455 public DisplayNameComparator(PackageManager pm) { 456 mPM = pm; 457 mCollator.setStrength(Collator.PRIMARY); 458 } 459 compare(ResolveInfo a, ResolveInfo b)460 public final int compare(ResolveInfo a, ResolveInfo b) { 461 // We want to put the one targeted to another user at the end of the dialog. 462 if (a.targetUserId != UserHandle.USER_CURRENT) { 463 return 1; 464 } 465 if (b.targetUserId != UserHandle.USER_CURRENT) { 466 return -1; 467 } 468 CharSequence sa = a.loadLabel(mPM); 469 if (sa == null) sa = a.activityInfo.name; 470 CharSequence sb = b.loadLabel(mPM); 471 if (sb == null) sb = b.activityInfo.name; 472 473 return mCollator.compare(sa.toString(), sb.toString()); 474 } 475 476 private final Collator mCollator = Collator.getInstance(); 477 private PackageManager mPM; 478 } 479 } 480