Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 98ffa48a authored by Mehdi Alizadeh's avatar Mehdi Alizadeh
Browse files

Load Uri based shortcut drawable in LauncherApps

Bug: 143106625
Test: Manual test by publishing shortcuts with uri icons in a sample app
Test: atest com.android.server.pm.ShortcutManagerTest1 \
            com.android.server.pm.ShortcutManagerTest2 \
            com.android.server.pm.ShortcutManagerTest3 \
            com.android.server.pm.ShortcutManagerTest4 \
            com.android.server.pm.ShortcutManagerTest5 \
            com.android.server.pm.ShortcutManagerTest6 \
            com.android.server.pm.ShortcutManagerTest7 \
            com.android.server.pm.ShortcutManagerTest8 \
            com.android.server.pm.ShortcutManagerTest9 \
            com.android.server.pm.ShortcutManagerTest10

Change-Id: Ibfb3cf6f7dabdeed36b845ab6e026506978d972a
parent f38f2c7d
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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);
}
+59 −20
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -1200,6 +1203,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.
     *
@@ -1220,26 +1252,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);
@@ -1263,6 +1279,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 {
+6 −0
Original line number Diff line number Diff line
@@ -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);
}
+12 −0
Original line number Diff line number Diff line
@@ -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);
+73 −1
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.IUidObserver;
import android.app.IUriGrantsManager;
import android.app.UriGrantsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
@@ -65,6 +67,7 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
import android.os.LocaleList;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
@@ -106,6 +109,7 @@ import com.android.internal.util.StatLogger;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.pm.ShortcutUser.PackageWithUser;
import com.android.server.uri.UriGrantsManagerInternal;

import libcore.io.IoUtils;

@@ -327,6 +331,9 @@ public class ShortcutService extends IShortcutService.Stub {
    private final UserManagerInternal mUserManagerInternal;
    private final UsageStatsManagerInternal mUsageStatsManagerInternal;
    private final ActivityManagerInternal mActivityManagerInternal;
    private final IUriGrantsManager mUriGrantsManager;
    private final UriGrantsManagerInternal mUriGrantsManagerInternal;
    private final IBinder mUriPermissionOwner;

    private final ShortcutRequestPinProcessor mShortcutRequestPinProcessor;
    private final ShortcutBitmapSaver mShortcutBitmapSaver;
@@ -449,6 +456,11 @@ public class ShortcutService extends IShortcutService.Stub {
        mActivityManagerInternal = Objects.requireNonNull(
                LocalServices.getService(ActivityManagerInternal.class));

        mUriGrantsManager = UriGrantsManager.getService();
        mUriGrantsManagerInternal = Objects.requireNonNull(
                LocalServices.getService(UriGrantsManagerInternal.class));
        mUriPermissionOwner = mUriGrantsManagerInternal.newUriPermissionOwner(TAG);

        mShortcutRequestPinProcessor = new ShortcutRequestPinProcessor(this, mLock);
        mShortcutBitmapSaver = new ShortcutBitmapSaver(this);
        mShortcutDumpFiles = new ShortcutDumpFiles(this);
@@ -3137,6 +3149,59 @@ public class ShortcutService extends IShortcutService.Stub {
            }
        }

        @Override
        public String getShortcutIconUri(int launcherUserId, @NonNull String launcherPackage,
                @NonNull String packageName, @NonNull String shortcutId, int userId) {
            Objects.requireNonNull(launcherPackage, "launcherPackage");
            Objects.requireNonNull(packageName, "packageName");
            Objects.requireNonNull(shortcutId, "shortcutId");

            synchronized (mLock) {
                throwIfUserLockedL(userId);
                throwIfUserLockedL(launcherUserId);

                getLauncherShortcutsLocked(launcherPackage, userId, launcherUserId)
                        .attemptToRestoreIfNeededAndSave();

                final ShortcutPackage p = getUserShortcutsLocked(userId)
                        .getPackageShortcutsIfExists(packageName);
                if (p == null) {
                    return null;
                }

                final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId);
                if (shortcutInfo == null || !shortcutInfo.hasIconUri()) {
                    return null;
                }
                String uri = shortcutInfo.getIconUri();
                if (uri == null) {
                    Slog.w(TAG, "null uri detected in getShortcutIconUri()");
                    return null;
                }

                final long token = Binder.clearCallingIdentity();
                try {
                    int packageUid = mPackageManagerInternal.getPackageUidInternal(packageName,
                            PackageManager.MATCH_DIRECT_BOOT_AUTO, userId);
                    // Grant read uri permission to the caller on behalf of the shortcut owner. All
                    // granted permissions are revoked when the default launcher changes, or when
                    // device is rebooted.
                    // b/151572645 is tracking a bug where Uri permissions are persisted across
                    // reboots, even when Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION is not used.
                    mUriGrantsManager.grantUriPermissionFromOwner(mUriPermissionOwner, packageUid,
                            launcherPackage, Uri.parse(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION,
                            userId, launcherUserId);
                } catch (Exception e) {
                    Slog.e(TAG, "Failed to grant uri access to " + launcherPackage + " for " + uri,
                            e);
                    uri = null;
                } finally {
                    Binder.restoreCallingIdentity(token);
                }
                return uri;
            }
        }

        @Override
        public boolean hasShortcutHostPermission(int launcherUserId,
                @NonNull String callingPackage, int callingPid, int callingUid) {
@@ -3250,7 +3315,14 @@ public class ShortcutService extends IShortcutService.Stub {
                    user.clearLauncher();
                }
                if (Intent.ACTION_PREFERRED_ACTIVITY_CHANGED.equals(action)) {
                    // Nothing farther to do.
                    final ShortcutUser user = getUserShortcutsLocked(userId);
                    final ComponentName lastLauncher = user.getLastKnownLauncher();
                    final ComponentName currentLauncher = getDefaultLauncher(userId);
                    if (currentLauncher == null || !currentLauncher.equals(lastLauncher)) {
                        // Default launcher is removed or changed, revoke all URI permissions.
                        mUriGrantsManagerInternal.revokeUriPermissionFromOwner(mUriPermissionOwner,
                                null, ~0, 0);
                    }
                    return;
                }

Loading