Merge "Allow assistant app to access any shortcuts"
This commit is contained in:
committed by
Android (Google) Code Review
commit
a379f499c8
@@ -10574,6 +10574,7 @@ package android.content.pm {
|
||||
field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
|
||||
field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
|
||||
field public static final int FLAG_MATCH_PINNED = 2; // 0x2
|
||||
field public static final int FLAG_MATCH_PINNED_BY_ANY_LAUNCHER = 1024; // 0x400
|
||||
}
|
||||
|
||||
public class PackageInfo implements android.os.Parcelable {
|
||||
|
||||
@@ -11192,6 +11192,7 @@ package android.content.pm {
|
||||
field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
|
||||
field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
|
||||
field public static final int FLAG_MATCH_PINNED = 2; // 0x2
|
||||
field public static final int FLAG_MATCH_PINNED_BY_ANY_LAUNCHER = 1024; // 0x400
|
||||
}
|
||||
|
||||
public class PackageInfo implements android.os.Parcelable {
|
||||
|
||||
@@ -10653,10 +10653,10 @@ package android.content.pm {
|
||||
method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
|
||||
method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>);
|
||||
field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
|
||||
field public static final int FLAG_MATCH_ALL_PINNED = 1024; // 0x400
|
||||
field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
|
||||
field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
|
||||
field public static final int FLAG_MATCH_PINNED = 2; // 0x2
|
||||
field public static final int FLAG_MATCH_PINNED_BY_ANY_LAUNCHER = 1024; // 0x400
|
||||
}
|
||||
|
||||
public class PackageInfo implements android.os.Parcelable {
|
||||
|
||||
@@ -282,13 +282,13 @@ public class LauncherApps {
|
||||
public static final int FLAG_GET_MANIFEST = FLAG_MATCH_MANIFEST;
|
||||
|
||||
/**
|
||||
* @hide include all pinned shortcuts by any launchers, not just by the caller,
|
||||
* Include all pinned shortcuts by any launchers, not just by the caller,
|
||||
* in the result.
|
||||
* If the caller doesn't havve the {@link android.Manifest.permission#ACCESS_SHORTCUTS}
|
||||
* permission, this flag will be ignored.
|
||||
*
|
||||
* The caller must be the selected assistant app to use this flag, or have the system
|
||||
* {@code ACCESS_SHORTCUTS} permission.
|
||||
*/
|
||||
@TestApi
|
||||
public static final int FLAG_MATCH_ALL_PINNED = 1 << 10;
|
||||
public static final int FLAG_MATCH_PINNED_BY_ANY_LAUNCHER = 1 << 10;
|
||||
|
||||
/**
|
||||
* FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST
|
||||
@@ -302,7 +302,7 @@ public class LauncherApps {
|
||||
* @hide
|
||||
*/
|
||||
public static final int FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED =
|
||||
FLAG_MATCH_ALL_KINDS | FLAG_MATCH_ALL_PINNED;
|
||||
FLAG_MATCH_ALL_KINDS | FLAG_MATCH_PINNED_BY_ANY_LAUNCHER;
|
||||
|
||||
/** @hide kept for unit tests */
|
||||
@Deprecated
|
||||
|
||||
@@ -615,10 +615,16 @@ class ShortcutPackage extends ShortcutPackageItem {
|
||||
|
||||
// Fix up isPinned for the caller. Note we need to do it before the "test" callback,
|
||||
// since it may check isPinned.
|
||||
if (!isPinnedByCaller) {
|
||||
clone.clearFlags(ShortcutInfo.FLAG_PINNED);
|
||||
// However, if getPinnedByAnyLauncher is set, we do it after the test.
|
||||
if (!getPinnedByAnyLauncher) {
|
||||
if (!isPinnedByCaller) {
|
||||
clone.clearFlags(ShortcutInfo.FLAG_PINNED);
|
||||
}
|
||||
}
|
||||
if (query == null || query.test(clone)) {
|
||||
if (!isPinnedByCaller) {
|
||||
clone.clearFlags(ShortcutInfo.FLAG_PINNED);
|
||||
}
|
||||
result.add(clone);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2234,7 +2234,7 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
// We override this method in unit tests to do a simpler check.
|
||||
boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId,
|
||||
int callingPid, int callingUid) {
|
||||
if (injectCheckAccessShortcutsPermission(callingPid, callingUid)) {
|
||||
if (canSeeAnyPinnedShortcut(callingPackage, userId, callingPid, callingUid)) {
|
||||
return true;
|
||||
}
|
||||
final long start = injectElapsedRealtime();
|
||||
@@ -2245,10 +2245,21 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
boolean canSeeAnyPinnedShortcut(@NonNull String callingPackage, int userId,
|
||||
int callingPid, int callingUid) {
|
||||
if (injectHasAccessShortcutsPermission(callingPid, callingUid)) {
|
||||
return true;
|
||||
}
|
||||
synchronized (mLock) {
|
||||
return getUserShortcutsLocked(userId).hasHostPackage(callingPackage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the caller has the "ACCESS_SHORTCUTS" permission.
|
||||
*/
|
||||
boolean injectCheckAccessShortcutsPermission(int callingPid, int callingUid) {
|
||||
@VisibleForTesting
|
||||
boolean injectHasAccessShortcutsPermission(int callingPid, int callingUid) {
|
||||
return mContext.checkPermission(android.Manifest.permission.ACCESS_SHORTCUTS,
|
||||
callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
@@ -2262,10 +2273,6 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
|
||||
final ShortcutUser user = getUserShortcutsLocked(userId);
|
||||
|
||||
if (user.hasHostPackage(packageName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Always trust the cached component.
|
||||
final ComponentName cached = user.getCachedLauncher();
|
||||
if (cached != null) {
|
||||
@@ -2491,8 +2498,8 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
final ArraySet<String> ids = shortcutIds == null ? null
|
||||
: new ArraySet<>(shortcutIds);
|
||||
|
||||
final ShortcutPackage p = getUserShortcutsLocked(userId)
|
||||
.getPackageShortcutsIfExists(packageName);
|
||||
final ShortcutUser user = getUserShortcutsLocked(userId);
|
||||
final ShortcutPackage p = user.getPackageShortcutsIfExists(packageName);
|
||||
if (p == null) {
|
||||
return; // No need to instantiate ShortcutPackage.
|
||||
}
|
||||
@@ -2500,9 +2507,12 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
final boolean matchPinned = (queryFlags & ShortcutQuery.FLAG_MATCH_PINNED) != 0;
|
||||
final boolean matchManifest = (queryFlags & ShortcutQuery.FLAG_MATCH_MANIFEST) != 0;
|
||||
|
||||
final boolean canAccessAllShortcuts =
|
||||
canSeeAnyPinnedShortcut(callingPackage, launcherUserId, callingPid, callingUid);
|
||||
|
||||
final boolean getPinnedByAnyLauncher =
|
||||
((queryFlags & ShortcutQuery.FLAG_MATCH_ALL_PINNED) != 0)
|
||||
&& injectCheckAccessShortcutsPermission(callingPid, callingUid);
|
||||
canAccessAllShortcuts &&
|
||||
((queryFlags & ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER) != 0);
|
||||
|
||||
p.findAll(ret,
|
||||
(ShortcutInfo si) -> {
|
||||
@@ -2521,7 +2531,7 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
if (matchDynamic && si.isDynamic()) {
|
||||
return true;
|
||||
}
|
||||
if ((matchPinned && si.isPinned()) || getPinnedByAnyLauncher) {
|
||||
if ((matchPinned || getPinnedByAnyLauncher) && si.isPinned()) {
|
||||
return true;
|
||||
}
|
||||
if (matchManifest && si.isDeclaredInManifest()) {
|
||||
@@ -2614,14 +2624,15 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
.attemptToRestoreIfNeededAndSave();
|
||||
|
||||
final boolean getPinnedByAnyLauncher =
|
||||
injectCheckAccessShortcutsPermission(callingPid, callingUid);
|
||||
canSeeAnyPinnedShortcut(callingPackage, launcherUserId,
|
||||
callingPid, callingUid);
|
||||
|
||||
// Make sure the shortcut is actually visible to the launcher.
|
||||
final ShortcutInfo si = getShortcutInfoLocked(
|
||||
launcherUserId, callingPackage, packageName, shortcutId, userId,
|
||||
getPinnedByAnyLauncher);
|
||||
// "si == null" should suffice here, but check the flags too just to make sure.
|
||||
if (si == null || !si.isEnabled() || !si.isAlive()) {
|
||||
if (si == null || !si.isEnabled() || !(si.isAlive() || getPinnedByAnyLauncher)) {
|
||||
Log.e(TAG, "Shortcut " + shortcutId + " does not exist or disabled");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -453,7 +453,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean injectCheckAccessShortcutsPermission(int callingPid, int callingUid) {
|
||||
boolean injectHasAccessShortcutsPermission(int callingPid, int callingUid) {
|
||||
return mInjectCheckAccessShortcutsPermission;
|
||||
}
|
||||
|
||||
@@ -1648,7 +1648,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
|
||||
protected void assertShortcutLaunchable(@NonNull String packageName, @NonNull String shortcutId,
|
||||
int userId) {
|
||||
assertNotNull(launchShortcutAndGetIntent(packageName, shortcutId, userId));
|
||||
assertNotNull(launchShortcutAndGetIntent_withShortcutInfo(packageName, shortcutId, userId));
|
||||
}
|
||||
|
||||
protected void assertShortcutNotLaunched(@NonNull String packageName,
|
||||
|
||||
@@ -1918,7 +1918,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
|
||||
// Make sure FLAG_MATCH_ALL_PINNED will be ignored.
|
||||
assertWith(mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_MATCH_PINNED
|
||||
| ShortcutQuery.FLAG_MATCH_ALL_PINNED), getCallingUser()))
|
||||
| ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER), getCallingUser()))
|
||||
.isEmpty();
|
||||
|
||||
// Make sure the special permission works.
|
||||
@@ -1928,14 +1928,18 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
|
||||
|
||||
assertWith(mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_MATCH_PINNED
|
||||
| ShortcutQuery.FLAG_MATCH_ALL_PINNED), getCallingUser()))
|
||||
| ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER), getCallingUser()))
|
||||
.haveIds("s1", "s2");
|
||||
assertWith(mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_MATCH_PINNED), getCallingUser()))
|
||||
.isEmpty();
|
||||
|
||||
assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", getCallingUser().getIdentifier());
|
||||
|
||||
mInjectCheckAccessShortcutsPermission = false;
|
||||
|
||||
assertShortcutNotLaunched(CALLING_PACKAGE_2, "s1", getCallingUser().getIdentifier());
|
||||
|
||||
assertShortcutIds(assertAllDynamic(
|
||||
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
|
||||
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
|
||||
@@ -2106,6 +2110,62 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
|
||||
});
|
||||
}
|
||||
|
||||
public void testPinShortcutAndGetPinnedShortcuts_assistant() {
|
||||
// Create some shortcuts.
|
||||
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
|
||||
assertTrue(mManager.setDynamicShortcuts(list(
|
||||
makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
|
||||
});
|
||||
|
||||
// Pin some.
|
||||
runWithCaller(LAUNCHER_1, USER_0, () -> {
|
||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
|
||||
list("s3", "s4"), getCallingUser());
|
||||
});
|
||||
|
||||
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
|
||||
assertTrue(mManager.setDynamicShortcuts(list(
|
||||
makeShortcut("s1"))));
|
||||
});
|
||||
|
||||
runWithCaller(LAUNCHER_2, USER_0, () -> {
|
||||
final ShortcutQuery allPinned = new ShortcutQuery().setQueryFlags(
|
||||
ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER);
|
||||
|
||||
assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_0))
|
||||
.isEmpty();
|
||||
|
||||
assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
|
||||
assertShortcutNotLaunched(CALLING_PACKAGE_1, "s3", USER_0);
|
||||
assertShortcutNotLaunched(CALLING_PACKAGE_1, "s4", USER_0);
|
||||
|
||||
// Make it the assistant app.
|
||||
mInternal.setShortcutHostPackage("assistant", LAUNCHER_2, USER_0);
|
||||
assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_0))
|
||||
.haveIds("s3");
|
||||
|
||||
assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
|
||||
assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
|
||||
assertShortcutNotLaunched(CALLING_PACKAGE_1, "s4", USER_0);
|
||||
|
||||
mInternal.setShortcutHostPackage("another-type", LAUNCHER_3, USER_0);
|
||||
assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_0))
|
||||
.haveIds("s3");
|
||||
|
||||
mInternal.setShortcutHostPackage("assistant", null, USER_0);
|
||||
assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_0))
|
||||
.isEmpty();
|
||||
|
||||
mInternal.setShortcutHostPackage("assistant", LAUNCHER_2, USER_0);
|
||||
assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_0))
|
||||
.haveIds("s3");
|
||||
|
||||
mInternal.setShortcutHostPackage("assistant", LAUNCHER_1, USER_0);
|
||||
assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_0))
|
||||
.isEmpty();
|
||||
});
|
||||
}
|
||||
|
||||
public void testPinShortcutAndGetPinnedShortcuts_crossProfile_plusLaunch() {
|
||||
// Create some shortcuts.
|
||||
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
|
||||
|
||||
Reference in New Issue
Block a user