Loading core/java/android/content/pm/ILauncherApps.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -103,4 +103,7 @@ interface ILauncherApps { in UserHandle user); void uncacheShortcuts(String callingPackage, String packageName, in List<String> shortcutIds, in UserHandle user); String getShortcutIconUri(String callingPackage, String packageName, String shortcutId, int userId); } core/java/android/content/pm/LauncherApps.java +59 −20 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; Loading @@ -67,8 +68,10 @@ import android.util.DisplayMetrics; import android.util.Log; import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.function.pooled.PooledLambda; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; Loading Loading @@ -1197,6 +1200,35 @@ public class LauncherApps { } } /** * @hide internal/unit tests only */ @VisibleForTesting public ParcelFileDescriptor getUriShortcutIconFd(@NonNull ShortcutInfo shortcut) { return getUriShortcutIconFd(shortcut.getPackage(), shortcut.getId(), shortcut.getUserId()); } private ParcelFileDescriptor getUriShortcutIconFd(@NonNull String packageName, @NonNull String shortcutId, int userId) { String uri = null; try { uri = mService.getShortcutIconUri(mContext.getPackageName(), packageName, shortcutId, userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } if (uri == null) { return null; } try { return mContext.getContentResolver().openFileDescriptor(Uri.parse(uri), "r"); } catch (FileNotFoundException e) { Log.e(TAG, "Icon file not found: " + uri); return null; } } /** * Returns the icon for this shortcut, without any badging for the profile. * Loading @@ -1217,26 +1249,10 @@ public class LauncherApps { public Drawable getShortcutIconDrawable(@NonNull ShortcutInfo shortcut, int density) { if (shortcut.hasIconFile()) { final ParcelFileDescriptor pfd = getShortcutIconFd(shortcut); if (pfd == null) { return null; } try { final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor()); if (bmp != null) { BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp); if (shortcut.hasAdaptiveBitmap()) { return new AdaptiveIconDrawable(null, dr); } else { return dr; } } return null; } finally { try { pfd.close(); } catch (IOException ignore) { } } return loadDrawableFromFileDescriptor(pfd, shortcut.hasAdaptiveBitmap()); } else if (shortcut.hasIconUri()) { final ParcelFileDescriptor pfd = getUriShortcutIconFd(shortcut); return loadDrawableFromFileDescriptor(pfd, shortcut.hasAdaptiveBitmap()); } else if (shortcut.hasIconResource()) { return loadDrawableResourceFromPackage(shortcut.getPackage(), shortcut.getIconResourceId(), shortcut.getUserHandle(), density); Loading @@ -1260,6 +1276,29 @@ public class LauncherApps { } } private Drawable loadDrawableFromFileDescriptor(ParcelFileDescriptor pfd, boolean adaptive) { if (pfd == null) { return null; } try { final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor()); if (bmp != null) { BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp); if (adaptive) { return new AdaptiveIconDrawable(null, dr); } else { return dr; } } return null; } finally { try { pfd.close(); } catch (IOException ignore) { } } } private Drawable loadDrawableResourceFromPackage(String packageName, int resId, UserHandle user, int density) { try { Loading core/java/android/content/pm/ShortcutInfo.java +47 −2 Original line number Diff line number Diff line Loading @@ -122,6 +122,9 @@ public final class ShortcutInfo implements Parcelable { /** @hide */ public static final int FLAG_CACHED = 1 << 14; /** @hide */ public static final int FLAG_HAS_ICON_URI = 1 << 15; /** @hide */ @IntDef(flag = true, prefix = { "FLAG_" }, value = { FLAG_DYNAMIC, Loading @@ -139,6 +142,7 @@ public final class ShortcutInfo implements Parcelable { FLAG_SHADOW, FLAG_LONG_LIVED, FLAG_CACHED, FLAG_HAS_ICON_URI, }) @Retention(RetentionPolicy.SOURCE) public @interface ShortcutFlags {} Loading Loading @@ -400,6 +404,9 @@ public final class ShortcutInfo implements Parcelable { private String mIconResName; // Internal use only. private String mIconUri; // Internal use only. @Nullable private String mBitmapPath; Loading Loading @@ -554,6 +561,7 @@ public final class ShortcutInfo implements Parcelable { if ((cloneFlags & CLONE_REMOVE_ICON) == 0) { mIcon = source.mIcon; mBitmapPath = source.mBitmapPath; mIconUri = source.mIconUri; } mTitle = source.mTitle; Loading Loading @@ -856,6 +864,7 @@ public final class ShortcutInfo implements Parcelable { mIconResId = 0; mIconResName = null; mBitmapPath = null; mIconUri = null; } if (source.mTitle != null) { mTitle = source.mTitle; Loading Loading @@ -916,6 +925,8 @@ public final class ShortcutInfo implements Parcelable { case Icon.TYPE_RESOURCE: case Icon.TYPE_BITMAP: case Icon.TYPE_ADAPTIVE_BITMAP: case Icon.TYPE_URI: case Icon.TYPE_URI_ADAPTIVE_BITMAP: break; // OK default: throw getInvalidIconException(); Loading Loading @@ -1792,6 +1803,15 @@ public final class ShortcutInfo implements Parcelable { return hasFlags(FLAG_HAS_ICON_RES); } /** * Return whether a shortcut's icon is provided via a URI. * * @hide internal/unit tests only */ public boolean hasIconUri() { return hasFlags(FLAG_HAS_ICON_URI); } /** @hide */ public boolean hasStringResources() { return (mTitleResId != 0) || (mTextResId != 0) || (mDisabledMessageResId != 0); Loading Loading @@ -1911,6 +1931,19 @@ public final class ShortcutInfo implements Parcelable { return mIconResId; } /** @hide */ public void setIconUri(String iconUri) { mIconUri = iconUri; } /** * Get the Uri for the icon, valid only when {@link #hasIconUri()} } is true. * @hide internal / tests only. */ public String getIconUri() { return mIconUri; } /** * Bitmap path. Note this will be null even if {@link #hasIconFile()} is set when the save * is pending. Use {@link #isIconPendingSave()} to check it. Loading Loading @@ -2062,6 +2095,7 @@ public final class ShortcutInfo implements Parcelable { mPersons = source.readParcelableArray(cl, Person.class); mLocusId = source.readParcelable(cl); mIconUri = source.readString(); } @Override Loading Loading @@ -2112,6 +2146,7 @@ public final class ShortcutInfo implements Parcelable { dest.writeParcelableArray(mPersons, flags); dest.writeParcelable(mLocusId, flags); dest.writeString(mIconUri); } public static final @android.annotation.NonNull Creator<ShortcutInfo> CREATOR = Loading Loading @@ -2203,6 +2238,12 @@ public final class ShortcutInfo implements Parcelable { if (hasIconResource()) { sb.append("Ic-r"); } if (hasIconUri()) { sb.append("Ic-u"); } if (hasAdaptiveBitmap()) { sb.append("Ic-a"); } if (hasKeyFieldsOnly()) { sb.append("Key"); } Loading Loading @@ -2325,6 +2366,9 @@ public final class ShortcutInfo implements Parcelable { sb.append(", bitmapPath="); sb.append(mBitmapPath); sb.append(", iconUri="); sb.append(mIconUri); } if (mLocusId != null) { Loading @@ -2343,8 +2387,8 @@ public final class ShortcutInfo implements Parcelable { CharSequence disabledMessage, int disabledMessageResId, String disabledMessageResName, Set<String> categories, Intent[] intentsWithExtras, int rank, PersistableBundle extras, long lastChangedTimestamp, int flags, int iconResId, String iconResName, String bitmapPath, int disabledReason, Person[] persons, LocusId locusId) { int flags, int iconResId, String iconResName, String bitmapPath, String iconUri, int disabledReason, Person[] persons, LocusId locusId) { mUserId = userId; mId = id; mPackageName = packageName; Loading @@ -2369,6 +2413,7 @@ public final class ShortcutInfo implements Parcelable { mIconResId = iconResId; mIconResName = iconResName; mBitmapPath = bitmapPath; mIconUri = iconUri; mDisabledReason = disabledReason; mPersons = persons; mLocusId = locusId; Loading core/java/android/content/pm/ShortcutServiceInternal.java +6 −0 Original line number Diff line number Diff line Loading @@ -103,4 +103,10 @@ public abstract class ShortcutServiceInternal { */ public abstract List<ShortcutManager.ShareShortcutInfo> getShareTargets( @NonNull String callingPackage, @NonNull IntentFilter intentFilter, int userId); /** * Returns the icon Uri of the shortcut, and grants Uri read permission to the caller. */ public abstract String getShortcutIconUri(int launcherUserId, @NonNull String launcherPackage, @NonNull String packageName, @NonNull String shortcutId, int userId); } services/core/java/com/android/server/pm/LauncherAppsService.java +12 −0 Original line number Diff line number Diff line Loading @@ -818,6 +818,18 @@ public class LauncherAppsService extends SystemService { callingPackage, packageName, id, targetUserId); } @Override public String getShortcutIconUri(String callingPackage, String packageName, String shortcutId, int userId) { ensureShortcutPermission(callingPackage); if (!canAccessProfile(userId, "Cannot access shortcuts")) { return null; } return mShortcutServiceInternal.getShortcutIconUri(getCallingUserId(), callingPackage, packageName, shortcutId, userId); } @Override public boolean hasShortcutHostPermission(String callingPackage) { verifyCallingPackage(callingPackage); Loading Loading
core/java/android/content/pm/ILauncherApps.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -103,4 +103,7 @@ interface ILauncherApps { in UserHandle user); void uncacheShortcuts(String callingPackage, String packageName, in List<String> shortcutIds, in UserHandle user); String getShortcutIconUri(String callingPackage, String packageName, String shortcutId, int userId); }
core/java/android/content/pm/LauncherApps.java +59 −20 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; Loading @@ -67,8 +68,10 @@ import android.util.DisplayMetrics; import android.util.Log; import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.function.pooled.PooledLambda; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; Loading Loading @@ -1197,6 +1200,35 @@ public class LauncherApps { } } /** * @hide internal/unit tests only */ @VisibleForTesting public ParcelFileDescriptor getUriShortcutIconFd(@NonNull ShortcutInfo shortcut) { return getUriShortcutIconFd(shortcut.getPackage(), shortcut.getId(), shortcut.getUserId()); } private ParcelFileDescriptor getUriShortcutIconFd(@NonNull String packageName, @NonNull String shortcutId, int userId) { String uri = null; try { uri = mService.getShortcutIconUri(mContext.getPackageName(), packageName, shortcutId, userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } if (uri == null) { return null; } try { return mContext.getContentResolver().openFileDescriptor(Uri.parse(uri), "r"); } catch (FileNotFoundException e) { Log.e(TAG, "Icon file not found: " + uri); return null; } } /** * Returns the icon for this shortcut, without any badging for the profile. * Loading @@ -1217,26 +1249,10 @@ public class LauncherApps { public Drawable getShortcutIconDrawable(@NonNull ShortcutInfo shortcut, int density) { if (shortcut.hasIconFile()) { final ParcelFileDescriptor pfd = getShortcutIconFd(shortcut); if (pfd == null) { return null; } try { final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor()); if (bmp != null) { BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp); if (shortcut.hasAdaptiveBitmap()) { return new AdaptiveIconDrawable(null, dr); } else { return dr; } } return null; } finally { try { pfd.close(); } catch (IOException ignore) { } } return loadDrawableFromFileDescriptor(pfd, shortcut.hasAdaptiveBitmap()); } else if (shortcut.hasIconUri()) { final ParcelFileDescriptor pfd = getUriShortcutIconFd(shortcut); return loadDrawableFromFileDescriptor(pfd, shortcut.hasAdaptiveBitmap()); } else if (shortcut.hasIconResource()) { return loadDrawableResourceFromPackage(shortcut.getPackage(), shortcut.getIconResourceId(), shortcut.getUserHandle(), density); Loading @@ -1260,6 +1276,29 @@ public class LauncherApps { } } private Drawable loadDrawableFromFileDescriptor(ParcelFileDescriptor pfd, boolean adaptive) { if (pfd == null) { return null; } try { final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor()); if (bmp != null) { BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp); if (adaptive) { return new AdaptiveIconDrawable(null, dr); } else { return dr; } } return null; } finally { try { pfd.close(); } catch (IOException ignore) { } } } private Drawable loadDrawableResourceFromPackage(String packageName, int resId, UserHandle user, int density) { try { Loading
core/java/android/content/pm/ShortcutInfo.java +47 −2 Original line number Diff line number Diff line Loading @@ -122,6 +122,9 @@ public final class ShortcutInfo implements Parcelable { /** @hide */ public static final int FLAG_CACHED = 1 << 14; /** @hide */ public static final int FLAG_HAS_ICON_URI = 1 << 15; /** @hide */ @IntDef(flag = true, prefix = { "FLAG_" }, value = { FLAG_DYNAMIC, Loading @@ -139,6 +142,7 @@ public final class ShortcutInfo implements Parcelable { FLAG_SHADOW, FLAG_LONG_LIVED, FLAG_CACHED, FLAG_HAS_ICON_URI, }) @Retention(RetentionPolicy.SOURCE) public @interface ShortcutFlags {} Loading Loading @@ -400,6 +404,9 @@ public final class ShortcutInfo implements Parcelable { private String mIconResName; // Internal use only. private String mIconUri; // Internal use only. @Nullable private String mBitmapPath; Loading Loading @@ -554,6 +561,7 @@ public final class ShortcutInfo implements Parcelable { if ((cloneFlags & CLONE_REMOVE_ICON) == 0) { mIcon = source.mIcon; mBitmapPath = source.mBitmapPath; mIconUri = source.mIconUri; } mTitle = source.mTitle; Loading Loading @@ -856,6 +864,7 @@ public final class ShortcutInfo implements Parcelable { mIconResId = 0; mIconResName = null; mBitmapPath = null; mIconUri = null; } if (source.mTitle != null) { mTitle = source.mTitle; Loading Loading @@ -916,6 +925,8 @@ public final class ShortcutInfo implements Parcelable { case Icon.TYPE_RESOURCE: case Icon.TYPE_BITMAP: case Icon.TYPE_ADAPTIVE_BITMAP: case Icon.TYPE_URI: case Icon.TYPE_URI_ADAPTIVE_BITMAP: break; // OK default: throw getInvalidIconException(); Loading Loading @@ -1792,6 +1803,15 @@ public final class ShortcutInfo implements Parcelable { return hasFlags(FLAG_HAS_ICON_RES); } /** * Return whether a shortcut's icon is provided via a URI. * * @hide internal/unit tests only */ public boolean hasIconUri() { return hasFlags(FLAG_HAS_ICON_URI); } /** @hide */ public boolean hasStringResources() { return (mTitleResId != 0) || (mTextResId != 0) || (mDisabledMessageResId != 0); Loading Loading @@ -1911,6 +1931,19 @@ public final class ShortcutInfo implements Parcelable { return mIconResId; } /** @hide */ public void setIconUri(String iconUri) { mIconUri = iconUri; } /** * Get the Uri for the icon, valid only when {@link #hasIconUri()} } is true. * @hide internal / tests only. */ public String getIconUri() { return mIconUri; } /** * Bitmap path. Note this will be null even if {@link #hasIconFile()} is set when the save * is pending. Use {@link #isIconPendingSave()} to check it. Loading Loading @@ -2062,6 +2095,7 @@ public final class ShortcutInfo implements Parcelable { mPersons = source.readParcelableArray(cl, Person.class); mLocusId = source.readParcelable(cl); mIconUri = source.readString(); } @Override Loading Loading @@ -2112,6 +2146,7 @@ public final class ShortcutInfo implements Parcelable { dest.writeParcelableArray(mPersons, flags); dest.writeParcelable(mLocusId, flags); dest.writeString(mIconUri); } public static final @android.annotation.NonNull Creator<ShortcutInfo> CREATOR = Loading Loading @@ -2203,6 +2238,12 @@ public final class ShortcutInfo implements Parcelable { if (hasIconResource()) { sb.append("Ic-r"); } if (hasIconUri()) { sb.append("Ic-u"); } if (hasAdaptiveBitmap()) { sb.append("Ic-a"); } if (hasKeyFieldsOnly()) { sb.append("Key"); } Loading Loading @@ -2325,6 +2366,9 @@ public final class ShortcutInfo implements Parcelable { sb.append(", bitmapPath="); sb.append(mBitmapPath); sb.append(", iconUri="); sb.append(mIconUri); } if (mLocusId != null) { Loading @@ -2343,8 +2387,8 @@ public final class ShortcutInfo implements Parcelable { CharSequence disabledMessage, int disabledMessageResId, String disabledMessageResName, Set<String> categories, Intent[] intentsWithExtras, int rank, PersistableBundle extras, long lastChangedTimestamp, int flags, int iconResId, String iconResName, String bitmapPath, int disabledReason, Person[] persons, LocusId locusId) { int flags, int iconResId, String iconResName, String bitmapPath, String iconUri, int disabledReason, Person[] persons, LocusId locusId) { mUserId = userId; mId = id; mPackageName = packageName; Loading @@ -2369,6 +2413,7 @@ public final class ShortcutInfo implements Parcelable { mIconResId = iconResId; mIconResName = iconResName; mBitmapPath = bitmapPath; mIconUri = iconUri; mDisabledReason = disabledReason; mPersons = persons; mLocusId = locusId; Loading
core/java/android/content/pm/ShortcutServiceInternal.java +6 −0 Original line number Diff line number Diff line Loading @@ -103,4 +103,10 @@ public abstract class ShortcutServiceInternal { */ public abstract List<ShortcutManager.ShareShortcutInfo> getShareTargets( @NonNull String callingPackage, @NonNull IntentFilter intentFilter, int userId); /** * Returns the icon Uri of the shortcut, and grants Uri read permission to the caller. */ public abstract String getShortcutIconUri(int launcherUserId, @NonNull String launcherPackage, @NonNull String packageName, @NonNull String shortcutId, int userId); }
services/core/java/com/android/server/pm/LauncherAppsService.java +12 −0 Original line number Diff line number Diff line Loading @@ -818,6 +818,18 @@ public class LauncherAppsService extends SystemService { callingPackage, packageName, id, targetUserId); } @Override public String getShortcutIconUri(String callingPackage, String packageName, String shortcutId, int userId) { ensureShortcutPermission(callingPackage); if (!canAccessProfile(userId, "Cannot access shortcuts")) { return null; } return mShortcutServiceInternal.getShortcutIconUri(getCallingUserId(), callingPackage, packageName, shortcutId, userId); } @Override public boolean hasShortcutHostPermission(String callingPackage) { verifyCallingPackage(callingPackage); Loading