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.text.TextUtils; 25 import android.util.Printer; 26 import android.util.Slog; 27 28 import java.text.Collator; 29 import java.util.Comparator; 30 31 /** 32 * Information that is returned from resolving an intent 33 * against an IntentFilter. This partially corresponds to 34 * information collected from the AndroidManifest.xml's 35 * <intent> tags. 36 */ 37 public class ResolveInfo implements Parcelable { 38 private static final String TAG = "ResolveInfo"; 39 40 /** 41 * The activity or broadcast receiver that corresponds to this resolution 42 * match, if this resolution is for an activity or broadcast receiver. 43 * Exactly one of {@link #activityInfo}, {@link #serviceInfo}, or 44 * {@link #providerInfo} will be non-null. 45 */ 46 public ActivityInfo activityInfo; 47 48 /** 49 * The service that corresponds to this resolution match, if this resolution 50 * is for a service. Exactly one of {@link #activityInfo}, 51 * {@link #serviceInfo}, or {@link #providerInfo} will be non-null. 52 */ 53 public ServiceInfo serviceInfo; 54 55 /** 56 * The provider that corresponds to this resolution match, if this 57 * resolution is for a provider. Exactly one of {@link #activityInfo}, 58 * {@link #serviceInfo}, or {@link #providerInfo} will be non-null. 59 */ 60 public ProviderInfo providerInfo; 61 62 /** 63 * The IntentFilter that was matched for this ResolveInfo. 64 */ 65 public IntentFilter filter; 66 67 /** 68 * The declared priority of this match. Comes from the "priority" 69 * attribute or, if not set, defaults to 0. Higher values are a higher 70 * priority. 71 */ 72 public int priority; 73 74 /** 75 * Order of result according to the user's preference. If the user 76 * has not set a preference for this result, the value is 0; higher 77 * values are a higher priority. 78 */ 79 public int preferredOrder; 80 81 /** 82 * The system's evaluation of how well the activity matches the 83 * IntentFilter. This is a match constant, a combination of 84 * {@link IntentFilter#MATCH_CATEGORY_MASK IntentFilter.MATCH_CATEGORY_MASK} 85 * and {@link IntentFilter#MATCH_ADJUSTMENT_MASK IntentFiler.MATCH_ADJUSTMENT_MASK}. 86 */ 87 public int match; 88 89 /** 90 * Only set when returned by 91 * {@link PackageManager#queryIntentActivityOptions}, this tells you 92 * which of the given specific intents this result came from. 0 is the 93 * first in the list, < 0 means it came from the generic Intent query. 94 */ 95 public int specificIndex = -1; 96 97 /** 98 * This filter has specified the Intent.CATEGORY_DEFAULT, meaning it 99 * would like to be considered a default action that the user can 100 * perform on this data. 101 */ 102 public boolean isDefault; 103 104 /** 105 * A string resource identifier (in the package's resources) of this 106 * match's label. From the "label" attribute or, if not set, 0. 107 */ 108 public int labelRes; 109 110 /** 111 * The actual string retrieve from <var>labelRes</var> or null if none 112 * was provided. 113 */ 114 public CharSequence nonLocalizedLabel; 115 116 /** 117 * A drawable resource identifier (in the package's resources) of this 118 * match's icon. From the "icon" attribute or, if not set, 0. 119 */ 120 public int icon; 121 122 /** 123 * Optional -- if non-null, the {@link #labelRes} and {@link #icon} 124 * resources will be loaded from this package, rather than the one 125 * containing the resolved component. 126 */ 127 public String resolvePackageName; 128 129 /** 130 * @hide Target comes from system process? 131 */ 132 public boolean system; 133 134 private ComponentInfo getComponentInfo() { 135 if (activityInfo != null) return activityInfo; 136 if (serviceInfo != null) return serviceInfo; 137 if (providerInfo != null) return providerInfo; 138 throw new IllegalStateException("Missing ComponentInfo!"); 139 } 140 141 /** 142 * Retrieve the current textual label associated with this resolution. This 143 * will call back on the given PackageManager to load the label from 144 * the application. 145 * 146 * @param pm A PackageManager from which the label can be loaded; usually 147 * the PackageManager from which you originally retrieved this item. 148 * 149 * @return Returns a CharSequence containing the resolutions's label. If the 150 * item does not have a label, its name is returned. 151 */ 152 public CharSequence loadLabel(PackageManager pm) { 153 if (nonLocalizedLabel != null) { 154 return nonLocalizedLabel; 155 } 156 CharSequence label; 157 if (resolvePackageName != null && labelRes != 0) { 158 label = pm.getText(resolvePackageName, labelRes, null); 159 if (label != null) { 160 return label.toString().trim(); 161 } 162 } 163 ComponentInfo ci = getComponentInfo(); 164 ApplicationInfo ai = ci.applicationInfo; 165 if (labelRes != 0) { 166 label = pm.getText(ci.packageName, labelRes, ai); 167 if (label != null) { 168 return label.toString().trim(); 169 } 170 } 171 172 CharSequence data = ci.loadLabel(pm); 173 // Make the data safe 174 if (data != null) data = data.toString().trim(); 175 return data; 176 } 177 178 /** 179 * Retrieve the current graphical icon associated with this resolution. This 180 * will call back on the given PackageManager to load the icon from 181 * the application. 182 * 183 * @param pm A PackageManager from which the icon can be loaded; usually 184 * the PackageManager from which you originally retrieved this item. 185 * 186 * @return Returns a Drawable containing the resolution's icon. If the 187 * item does not have an icon, the default activity icon is returned. 188 */ 189 public Drawable loadIcon(PackageManager pm) { 190 Drawable dr; 191 if (resolvePackageName != null && icon != 0) { 192 dr = pm.getDrawable(resolvePackageName, icon, null); 193 if (dr != null) { 194 return dr; 195 } 196 } 197 ComponentInfo ci = getComponentInfo(); 198 ApplicationInfo ai = ci.applicationInfo; 199 if (icon != 0) { 200 dr = pm.getDrawable(ci.packageName, icon, ai); 201 if (dr != null) { 202 return dr; 203 } 204 } 205 return ci.loadIcon(pm); 206 } 207 208 /** 209 * Return the icon resource identifier to use for this match. If the 210 * match defines an icon, that is used; else if the activity defines 211 * an icon, that is used; else, the application icon is used. 212 * 213 * @return The icon associated with this match. 214 */ 215 public final int getIconResource() { 216 if (icon != 0) return icon; 217 final ComponentInfo ci = getComponentInfo(); 218 if (ci != null) return ci.getIconResource(); 219 return 0; 220 } 221 222 public void dump(Printer pw, String prefix) { 223 if (filter != null) { 224 pw.println(prefix + "Filter:"); 225 filter.dump(pw, prefix + " "); 226 } 227 pw.println(prefix + "priority=" + priority 228 + " preferredOrder=" + preferredOrder 229 + " match=0x" + Integer.toHexString(match) 230 + " specificIndex=" + specificIndex 231 + " isDefault=" + isDefault); 232 if (resolvePackageName != null) { 233 pw.println(prefix + "resolvePackageName=" + resolvePackageName); 234 } 235 if (labelRes != 0 || nonLocalizedLabel != null || icon != 0) { 236 pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes) 237 + " nonLocalizedLabel=" + nonLocalizedLabel 238 + " icon=0x" + Integer.toHexString(icon)); 239 } 240 if (activityInfo != null) { 241 pw.println(prefix + "ActivityInfo:"); 242 activityInfo.dump(pw, prefix + " "); 243 } else if (serviceInfo != null) { 244 pw.println(prefix + "ServiceInfo:"); 245 serviceInfo.dump(pw, prefix + " "); 246 } else if (providerInfo != null) { 247 pw.println(prefix + "ProviderInfo:"); 248 providerInfo.dump(pw, prefix + " "); 249 } 250 } 251 252 public ResolveInfo() { 253 } 254 255 public ResolveInfo(ResolveInfo orig) { 256 activityInfo = orig.activityInfo; 257 serviceInfo = orig.serviceInfo; 258 providerInfo = orig.providerInfo; 259 filter = orig.filter; 260 priority = orig.priority; 261 preferredOrder = orig.preferredOrder; 262 match = orig.match; 263 specificIndex = orig.specificIndex; 264 labelRes = orig.labelRes; 265 nonLocalizedLabel = orig.nonLocalizedLabel; 266 icon = orig.icon; 267 resolvePackageName = orig.resolvePackageName; 268 system = orig.system; 269 } 270 271 public String toString() { 272 final ComponentInfo ci = getComponentInfo(); 273 StringBuilder sb = new StringBuilder(128); 274 sb.append("ResolveInfo{"); 275 sb.append(Integer.toHexString(System.identityHashCode(this))); 276 sb.append(' '); 277 ComponentName.appendShortString(sb, ci.packageName, ci.name); 278 if (priority != 0) { 279 sb.append(" p="); 280 sb.append(priority); 281 } 282 if (preferredOrder != 0) { 283 sb.append(" o="); 284 sb.append(preferredOrder); 285 } 286 sb.append(" m=0x"); 287 sb.append(Integer.toHexString(match)); 288 sb.append('}'); 289 return sb.toString(); 290 } 291 292 public int describeContents() { 293 return 0; 294 } 295 296 public void writeToParcel(Parcel dest, int parcelableFlags) { 297 if (activityInfo != null) { 298 dest.writeInt(1); 299 activityInfo.writeToParcel(dest, parcelableFlags); 300 } else if (serviceInfo != null) { 301 dest.writeInt(2); 302 serviceInfo.writeToParcel(dest, parcelableFlags); 303 } else if (providerInfo != null) { 304 dest.writeInt(3); 305 providerInfo.writeToParcel(dest, parcelableFlags); 306 } else { 307 dest.writeInt(0); 308 } 309 if (filter != null) { 310 dest.writeInt(1); 311 filter.writeToParcel(dest, parcelableFlags); 312 } else { 313 dest.writeInt(0); 314 } 315 dest.writeInt(priority); 316 dest.writeInt(preferredOrder); 317 dest.writeInt(match); 318 dest.writeInt(specificIndex); 319 dest.writeInt(labelRes); 320 TextUtils.writeToParcel(nonLocalizedLabel, dest, parcelableFlags); 321 dest.writeInt(icon); 322 dest.writeString(resolvePackageName); 323 dest.writeInt(system ? 1 : 0); 324 } 325 326 public static final Creator<ResolveInfo> CREATOR 327 = new Creator<ResolveInfo>() { 328 public ResolveInfo createFromParcel(Parcel source) { 329 return new ResolveInfo(source); 330 } 331 public ResolveInfo[] newArray(int size) { 332 return new ResolveInfo[size]; 333 } 334 }; 335 336 private ResolveInfo(Parcel source) { 337 activityInfo = null; 338 serviceInfo = null; 339 providerInfo = null; 340 switch (source.readInt()) { 341 case 1: 342 activityInfo = ActivityInfo.CREATOR.createFromParcel(source); 343 break; 344 case 2: 345 serviceInfo = ServiceInfo.CREATOR.createFromParcel(source); 346 break; 347 case 3: 348 providerInfo = ProviderInfo.CREATOR.createFromParcel(source); 349 break; 350 default: 351 Slog.w(TAG, "Missing ComponentInfo!"); 352 break; 353 } 354 if (source.readInt() != 0) { 355 filter = IntentFilter.CREATOR.createFromParcel(source); 356 } 357 priority = source.readInt(); 358 preferredOrder = source.readInt(); 359 match = source.readInt(); 360 specificIndex = source.readInt(); 361 labelRes = source.readInt(); 362 nonLocalizedLabel 363 = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 364 icon = source.readInt(); 365 resolvePackageName = source.readString(); 366 system = source.readInt() != 0; 367 } 368 369 public static class DisplayNameComparator 370 implements Comparator<ResolveInfo> { 371 public DisplayNameComparator(PackageManager pm) { 372 mPM = pm; 373 mCollator.setStrength(Collator.PRIMARY); 374 } 375 376 public final int compare(ResolveInfo a, ResolveInfo b) { 377 CharSequence sa = a.loadLabel(mPM); 378 if (sa == null) sa = a.activityInfo.name; 379 CharSequence sb = b.loadLabel(mPM); 380 if (sb == null) sb = b.activityInfo.name; 381 382 return mCollator.compare(sa.toString(), sb.toString()); 383 } 384 385 private final Collator mCollator = Collator.getInstance(); 386 private PackageManager mPM; 387 } 388 } 389