Merge "Add UserHandle to ShortcutInfo, and simplify LauncherApps APIs." into nyc-dev
This commit is contained in:
@@ -9498,9 +9498,10 @@ package android.content.pm {
|
||||
public class LauncherApps {
|
||||
method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
|
||||
method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
|
||||
method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo, android.os.UserHandle);
|
||||
method public int getShortcutIconResId(android.content.pm.ShortcutInfo, android.os.UserHandle);
|
||||
method public java.util.List<android.content.pm.ShortcutInfo> getShortcutInfo(java.lang.String, java.util.List<java.lang.String>, android.os.UserHandle);
|
||||
method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo);
|
||||
method public android.os.ParcelFileDescriptor getShortcutIconFd(java.lang.String, java.lang.String, android.os.UserHandle);
|
||||
method public int getShortcutIconResId(android.content.pm.ShortcutInfo);
|
||||
method public int getShortcutIconResId(java.lang.String, java.lang.String, android.os.UserHandle);
|
||||
method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
|
||||
method public boolean hasShortcutHostPermission();
|
||||
method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
|
||||
@@ -9512,6 +9513,7 @@ package android.content.pm {
|
||||
method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
|
||||
method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
|
||||
method public boolean startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
|
||||
method public boolean startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle);
|
||||
method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
|
||||
}
|
||||
|
||||
@@ -9533,6 +9535,7 @@ package android.content.pm {
|
||||
method public void setChangedSince(long);
|
||||
method public void setPackage(java.lang.String);
|
||||
method public void setQueryFlags(int);
|
||||
method public void setShortcutIds(java.util.List<java.lang.String>);
|
||||
field public static final int FLAG_GET_DYNAMIC = 1; // 0x1
|
||||
field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
|
||||
field public static final int FLAG_GET_PINNED = 2; // 0x2
|
||||
@@ -10046,6 +10049,7 @@ package android.content.pm {
|
||||
method public java.lang.String getPackageName();
|
||||
method public java.lang.String getText();
|
||||
method public java.lang.String getTitle();
|
||||
method public android.os.UserHandle getUserHandle();
|
||||
method public int getWeight();
|
||||
method public boolean hasIconFile();
|
||||
method public boolean hasIconResource();
|
||||
|
||||
@@ -9836,9 +9836,10 @@ package android.content.pm {
|
||||
public class LauncherApps {
|
||||
method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
|
||||
method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
|
||||
method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo, android.os.UserHandle);
|
||||
method public int getShortcutIconResId(android.content.pm.ShortcutInfo, android.os.UserHandle);
|
||||
method public java.util.List<android.content.pm.ShortcutInfo> getShortcutInfo(java.lang.String, java.util.List<java.lang.String>, android.os.UserHandle);
|
||||
method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo);
|
||||
method public android.os.ParcelFileDescriptor getShortcutIconFd(java.lang.String, java.lang.String, android.os.UserHandle);
|
||||
method public int getShortcutIconResId(android.content.pm.ShortcutInfo);
|
||||
method public int getShortcutIconResId(java.lang.String, java.lang.String, android.os.UserHandle);
|
||||
method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
|
||||
method public boolean hasShortcutHostPermission();
|
||||
method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
|
||||
@@ -9850,6 +9851,7 @@ package android.content.pm {
|
||||
method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
|
||||
method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
|
||||
method public boolean startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
|
||||
method public boolean startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle);
|
||||
method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
|
||||
}
|
||||
|
||||
@@ -9871,6 +9873,7 @@ package android.content.pm {
|
||||
method public void setChangedSince(long);
|
||||
method public void setPackage(java.lang.String);
|
||||
method public void setQueryFlags(int);
|
||||
method public void setShortcutIds(java.util.List<java.lang.String>);
|
||||
field public static final int FLAG_GET_DYNAMIC = 1; // 0x1
|
||||
field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
|
||||
field public static final int FLAG_GET_PINNED = 2; // 0x2
|
||||
@@ -10446,6 +10449,7 @@ package android.content.pm {
|
||||
method public java.lang.String getPackageName();
|
||||
method public java.lang.String getText();
|
||||
method public java.lang.String getTitle();
|
||||
method public android.os.UserHandle getUserHandle();
|
||||
method public int getWeight();
|
||||
method public boolean hasIconFile();
|
||||
method public boolean hasIconResource();
|
||||
|
||||
@@ -9507,9 +9507,10 @@ package android.content.pm {
|
||||
public class LauncherApps {
|
||||
method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
|
||||
method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
|
||||
method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo, android.os.UserHandle);
|
||||
method public int getShortcutIconResId(android.content.pm.ShortcutInfo, android.os.UserHandle);
|
||||
method public java.util.List<android.content.pm.ShortcutInfo> getShortcutInfo(java.lang.String, java.util.List<java.lang.String>, android.os.UserHandle);
|
||||
method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo);
|
||||
method public android.os.ParcelFileDescriptor getShortcutIconFd(java.lang.String, java.lang.String, android.os.UserHandle);
|
||||
method public int getShortcutIconResId(android.content.pm.ShortcutInfo);
|
||||
method public int getShortcutIconResId(java.lang.String, java.lang.String, android.os.UserHandle);
|
||||
method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
|
||||
method public boolean hasShortcutHostPermission();
|
||||
method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
|
||||
@@ -9521,6 +9522,7 @@ package android.content.pm {
|
||||
method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
|
||||
method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
|
||||
method public boolean startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
|
||||
method public boolean startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle);
|
||||
method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
|
||||
}
|
||||
|
||||
@@ -9542,6 +9544,7 @@ package android.content.pm {
|
||||
method public void setChangedSince(long);
|
||||
method public void setPackage(java.lang.String);
|
||||
method public void setQueryFlags(int);
|
||||
method public void setShortcutIds(java.util.List<java.lang.String>);
|
||||
field public static final int FLAG_GET_DYNAMIC = 1; // 0x1
|
||||
field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
|
||||
field public static final int FLAG_GET_PINNED = 2; // 0x2
|
||||
@@ -10056,6 +10059,7 @@ package android.content.pm {
|
||||
method public java.lang.String getPackageName();
|
||||
method public java.lang.String getText();
|
||||
method public java.lang.String getTitle();
|
||||
method public android.os.UserHandle getUserHandle();
|
||||
method public int getWeight();
|
||||
method public boolean hasIconFile();
|
||||
method public boolean hasIconResource();
|
||||
|
||||
@@ -47,17 +47,16 @@ interface ILauncherApps {
|
||||
ApplicationInfo getApplicationInfo(String packageName, int flags, in UserHandle user);
|
||||
|
||||
ParceledListSlice getShortcuts(String callingPackage, long changedSince, String packageName,
|
||||
in ComponentName componentName, int flags, in UserHandle user);
|
||||
ParceledListSlice getShortcutInfo(String callingPackage, String packageName, in List<String> ids,
|
||||
in UserHandle user);
|
||||
in List shortcutIds, in ComponentName componentName, int flags, in UserHandle user);
|
||||
void pinShortcuts(String callingPackage, String packageName, in List<String> shortcutIds,
|
||||
in UserHandle user);
|
||||
boolean startShortcut(String callingPackage, String packageName, String id,
|
||||
in Rect sourceBounds, in Bundle startActivityOptions, in UserHandle user);
|
||||
in Rect sourceBounds, in Bundle startActivityOptions, int userId);
|
||||
|
||||
int getShortcutIconResId(String callingPackage, in ShortcutInfo shortcut, in UserHandle user);
|
||||
ParcelFileDescriptor getShortcutIconFd(String callingPackage, in ShortcutInfo shortcut,
|
||||
in UserHandle user);
|
||||
int getShortcutIconResId(String callingPackage, String packageName, String id,
|
||||
int userId);
|
||||
ParcelFileDescriptor getShortcutIconFd(String callingPackage, String packageName, String id,
|
||||
int userId);
|
||||
|
||||
boolean hasShortcutHostPermission(String callingPackage);
|
||||
}
|
||||
|
||||
@@ -204,6 +204,9 @@ public class LauncherApps {
|
||||
@Nullable
|
||||
String mPackage;
|
||||
|
||||
@Nullable
|
||||
List<String> mShortcutIds;
|
||||
|
||||
@Nullable
|
||||
ComponentName mActivity;
|
||||
|
||||
@@ -228,6 +231,14 @@ public class LauncherApps {
|
||||
mPackage = packageName;
|
||||
}
|
||||
|
||||
/**
|
||||
* If non-null, return only the specified shortcuts by ID. When setting this field,
|
||||
* a packange name must also be set with {@link #setPackage}.
|
||||
*/
|
||||
public void setShortcutIds(@Nullable List<String> shortcutIds) {
|
||||
mShortcutIds = shortcutIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* If non-null, returns only shortcuts associated with the activity.
|
||||
*/
|
||||
@@ -429,7 +440,8 @@ public class LauncherApps {
|
||||
@NonNull UserHandle user) {
|
||||
try {
|
||||
return mService.getShortcuts(mContext.getPackageName(),
|
||||
query.mChangedSince, query.mPackage, query.mActivity, query.mQueryFlags, user)
|
||||
query.mChangedSince, query.mPackage, query.mShortcutIds, query.mActivity,
|
||||
query.mQueryFlags, user)
|
||||
.getList();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
@@ -437,29 +449,18 @@ public class LauncherApps {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link ShortcutInfo}s with the given IDs from a package.
|
||||
*
|
||||
* <p>Callers must be allowed to access the shortcut information, as defined in {@link
|
||||
* #hasShortcutHostPermission()}.
|
||||
*
|
||||
* @param packageName The target package.
|
||||
* @param ids IDs of the shortcuts to retrieve.
|
||||
* @param user The UserHandle of the profile.
|
||||
*
|
||||
* @return list of {@link ShortcutInfo} associated with the package.
|
||||
* @hide // No longer used. Use getShortcuts() instead. Kept for unit tests.
|
||||
*/
|
||||
@Nullable
|
||||
public List<ShortcutInfo> getShortcutInfo(@NonNull String packageName,
|
||||
@NonNull List<String> ids, @NonNull UserHandle user) {
|
||||
try {
|
||||
return mService.getShortcutInfo(mContext.getPackageName(), packageName, ids, user)
|
||||
.getList();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
final ShortcutQuery q = new ShortcutQuery();
|
||||
q.setPackage(packageName);
|
||||
q.setShortcutIds(ids);
|
||||
q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
|
||||
return getShortcuts(q, user);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pin shortcuts on a package.
|
||||
*
|
||||
@@ -490,11 +491,33 @@ public class LauncherApps {
|
||||
* #hasShortcutHostPermission()}.
|
||||
*
|
||||
* @param shortcut The target shortcut.
|
||||
*/
|
||||
public int getShortcutIconResId(@NonNull ShortcutInfo shortcut) {
|
||||
return getShortcutIconResId(shortcut.getPackageName(), shortcut.getId(),
|
||||
shortcut.getUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the icon resource ID, if {@code shortcut} has one
|
||||
* (i.e. when {@link ShortcutInfo#hasIconResource()} returns {@code true}).
|
||||
*
|
||||
* <p>Callers must be allowed to access the shortcut information, as defined in {@link
|
||||
* #hasShortcutHostPermission()}.
|
||||
*
|
||||
* @param packageName The target package name.
|
||||
* @param shortcutId The ID of the shortcut to lad rom.
|
||||
* @param user The UserHandle of the profile.
|
||||
*/
|
||||
public int getShortcutIconResId(@NonNull ShortcutInfo shortcut, @NonNull UserHandle user) {
|
||||
public int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId,
|
||||
@NonNull UserHandle user) {
|
||||
return getShortcutIconResId(packageName, shortcutId, user.getIdentifier());
|
||||
}
|
||||
|
||||
private int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId,
|
||||
int userId) {
|
||||
try {
|
||||
return mService.getShortcutIconResId(mContext.getPackageName(), shortcut, user);
|
||||
return mService.getShortcutIconResId(mContext.getPackageName(),
|
||||
packageName, shortcutId, userId);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
@@ -508,12 +531,34 @@ public class LauncherApps {
|
||||
* #hasShortcutHostPermission()}.
|
||||
*
|
||||
* @param shortcut The target shortcut.
|
||||
*/
|
||||
public ParcelFileDescriptor getShortcutIconFd(
|
||||
@NonNull ShortcutInfo shortcut) {
|
||||
return getShortcutIconFd(shortcut.getPackageName(), shortcut.getId(),
|
||||
shortcut.getUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the icon as {@link ParcelFileDescriptor}, when it's stored as a file
|
||||
* (i.e. when {@link ShortcutInfo#hasIconFile()} returns {@code true}).
|
||||
*
|
||||
* <p>Callers must be allowed to access the shortcut information, as defined in {@link
|
||||
* #hasShortcutHostPermission()}.
|
||||
*
|
||||
* @param packageName The target package name.
|
||||
* @param shortcutId The ID of the shortcut to lad rom.
|
||||
* @param user The UserHandle of the profile.
|
||||
*/
|
||||
public ParcelFileDescriptor getShortcutIconFd(
|
||||
@NonNull ShortcutInfo shortcut, @NonNull UserHandle user) {
|
||||
@NonNull String packageName, @NonNull String shortcutId, @NonNull UserHandle user) {
|
||||
return getShortcutIconFd(packageName, shortcutId, user.getIdentifier());
|
||||
}
|
||||
|
||||
private ParcelFileDescriptor getShortcutIconFd(
|
||||
@NonNull String packageName, @NonNull String shortcutId, int userId) {
|
||||
try {
|
||||
return mService.getShortcutIconFd(mContext.getPackageName(), shortcut, user);
|
||||
return mService.getShortcutIconFd(mContext.getPackageName(),
|
||||
packageName, shortcutId, userId);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
@@ -536,9 +581,35 @@ public class LauncherApps {
|
||||
public boolean startShortcut(@NonNull String packageName, @NonNull String shortcutId,
|
||||
@Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
|
||||
@NonNull UserHandle user) {
|
||||
return startShortcut(packageName, shortcutId, sourceBounds, startActivityOptions,
|
||||
user.getIdentifier());
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches a shortcut.
|
||||
*
|
||||
* <p>Callers must be allowed to access the shortcut information, as defined in {@link
|
||||
* #hasShortcutHostPermission()}.
|
||||
*
|
||||
* @param shortcut The target shortcut.
|
||||
* @param sourceBounds The Rect containing the source bounds of the clicked icon.
|
||||
* @param startActivityOptions Options to pass to startActivity.
|
||||
* @return {@code false} when the shortcut is no longer valid (e.g. the creator application
|
||||
* has been uninstalled). {@code true} when the shortcut is still valid.
|
||||
*/
|
||||
public boolean startShortcut(@NonNull ShortcutInfo shortcut,
|
||||
@Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions) {
|
||||
return startShortcut(shortcut.getPackageName(), shortcut.getId(),
|
||||
sourceBounds, startActivityOptions,
|
||||
shortcut.getUserId());
|
||||
}
|
||||
|
||||
private boolean startShortcut(@NonNull String packageName, @NonNull String shortcutId,
|
||||
@Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
|
||||
int userId) {
|
||||
try {
|
||||
return mService.startShortcut(mContext.getPackageName(), packageName, shortcutId,
|
||||
sourceBounds, startActivityOptions, user);
|
||||
sourceBounds, startActivityOptions, userId);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.content.pm;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
@@ -153,7 +154,11 @@ public final class ShortcutInfo implements Parcelable {
|
||||
@Nullable
|
||||
private String mBitmapPath;
|
||||
|
||||
private final int mUserId;
|
||||
|
||||
private ShortcutInfo(Builder b) {
|
||||
mUserId = b.mContext.getUserId();
|
||||
|
||||
mId = Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided");
|
||||
|
||||
// Note we can't do other null checks here because SM.updateShortcuts() takes partial
|
||||
@@ -191,6 +196,7 @@ public final class ShortcutInfo implements Parcelable {
|
||||
* Copy constructor.
|
||||
*/
|
||||
private ShortcutInfo(ShortcutInfo source, @CloneFlags int cloneFlags) {
|
||||
mUserId = source.mUserId;
|
||||
mId = source.mId;
|
||||
mPackageName = source.mPackageName;
|
||||
mFlags = source.mFlags;
|
||||
@@ -238,6 +244,7 @@ public final class ShortcutInfo implements Parcelable {
|
||||
* @hide
|
||||
*/
|
||||
public void copyNonNullFieldsFrom(ShortcutInfo source) {
|
||||
Preconditions.checkState(mUserId == source.mUserId, "Owner User ID must match");
|
||||
Preconditions.checkState(mId.equals(source.mId), "ID must match");
|
||||
Preconditions.checkState(mPackageName.equals(source.mPackageName),
|
||||
"Package name must match");
|
||||
@@ -362,8 +369,8 @@ public final class ShortcutInfo implements Parcelable {
|
||||
*
|
||||
* <p>For performance reasons, icons will <b>NOT</b> be available on instances
|
||||
* returned by {@link ShortcutManager} or {@link LauncherApps}. Launcher applications
|
||||
* need to use {@link LauncherApps#getShortcutIconFd(ShortcutInfo, UserHandle)}
|
||||
* and {@link LauncherApps#getShortcutIconResId(ShortcutInfo, UserHandle)}.
|
||||
* need to use {@link LauncherApps#getShortcutIconFd(ShortcutInfo)}
|
||||
* and {@link LauncherApps#getShortcutIconResId(ShortcutInfo)}.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setIcon(Icon icon) {
|
||||
@@ -544,6 +551,18 @@ public final class ShortcutInfo implements Parcelable {
|
||||
return mExtras;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public int getUserId() {
|
||||
return mUserId;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link UserHandle} on which the publisher created shortcuts.
|
||||
*/
|
||||
public UserHandle getUserHandle() {
|
||||
return UserHandle.of(mUserId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Last time when any of the fields was updated.
|
||||
*/
|
||||
@@ -590,7 +609,7 @@ public final class ShortcutInfo implements Parcelable {
|
||||
/**
|
||||
* Return whether a shortcut's icon is a resource in the owning package.
|
||||
*
|
||||
* @see LauncherApps#getShortcutIconResId(ShortcutInfo, UserHandle)
|
||||
* @see LauncherApps#getShortcutIconResId(ShortcutInfo)
|
||||
*/
|
||||
public boolean hasIconResource() {
|
||||
return hasFlags(FLAG_HAS_ICON_RES);
|
||||
@@ -599,7 +618,7 @@ public final class ShortcutInfo implements Parcelable {
|
||||
/**
|
||||
* Return whether a shortcut's icon is stored as a file.
|
||||
*
|
||||
* @see LauncherApps#getShortcutIconFd(ShortcutInfo, UserHandle)
|
||||
* @see LauncherApps#getShortcutIconFd(ShortcutInfo)
|
||||
*/
|
||||
public boolean hasIconFile() {
|
||||
return hasFlags(FLAG_HAS_ICON_FILE);
|
||||
@@ -661,6 +680,7 @@ public final class ShortcutInfo implements Parcelable {
|
||||
private ShortcutInfo(Parcel source) {
|
||||
final ClassLoader cl = getClass().getClassLoader();
|
||||
|
||||
mUserId = source.readInt();
|
||||
mId = source.readString();
|
||||
mPackageName = source.readString();
|
||||
mActivityComponent = source.readParcelable(cl);
|
||||
@@ -679,6 +699,7 @@ public final class ShortcutInfo implements Parcelable {
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(mUserId);
|
||||
dest.writeString(mId);
|
||||
dest.writeString(mPackageName);
|
||||
dest.writeParcelable(mActivityComponent, flags);
|
||||
@@ -784,11 +805,13 @@ public final class ShortcutInfo implements Parcelable {
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public ShortcutInfo(String id, String packageName, ComponentName activityComponent,
|
||||
public ShortcutInfo(
|
||||
@UserIdInt int userId, String id, String packageName, ComponentName activityComponent,
|
||||
Icon icon, String title, String text, Intent intent,
|
||||
PersistableBundle intentPersistableExtras,
|
||||
int weight, PersistableBundle extras, long lastChangedTimestamp,
|
||||
int flags, int iconResId, String bitmapPath) {
|
||||
mUserId = userId;
|
||||
mId = id;
|
||||
mPackageName = packageName;
|
||||
mActivityComponent = activityComponent;
|
||||
|
||||
@@ -42,15 +42,10 @@ public abstract class ShortcutServiceInternal {
|
||||
public abstract List<ShortcutInfo>
|
||||
getShortcuts(int launcherUserId,
|
||||
@NonNull String callingPackage, long changedSince,
|
||||
@Nullable String packageName, @Nullable ComponentName componentName,
|
||||
@ShortcutQuery.QueryFlags int flags,
|
||||
@Nullable String packageName, @Nullable List<String> shortcutIds,
|
||||
@Nullable ComponentName componentName, @ShortcutQuery.QueryFlags int flags,
|
||||
int userId);
|
||||
|
||||
public abstract List<ShortcutInfo>
|
||||
getShortcutInfo(int launcherUserId, @NonNull String callingPackage,
|
||||
@NonNull String packageName, @Nullable List<String> ids, int userId);
|
||||
|
||||
|
||||
public abstract boolean
|
||||
isPinnedByCaller(int launcherUserId, @NonNull String callingPackage,
|
||||
@NonNull String packageName, @NonNull String id, int userId);
|
||||
@@ -65,11 +60,11 @@ public abstract class ShortcutServiceInternal {
|
||||
public abstract void addListener(@NonNull ShortcutChangeListener listener);
|
||||
|
||||
public abstract int getShortcutIconResId(int launcherUserId, @NonNull String callingPackage,
|
||||
@NonNull ShortcutInfo shortcut, int userId);
|
||||
@NonNull String packageName, @NonNull String shortcutId, int userId);
|
||||
|
||||
public abstract ParcelFileDescriptor getShortcutIconFd(int launcherUserId,
|
||||
@NonNull String callingPackage,
|
||||
@NonNull ShortcutInfo shortcut, int userId);
|
||||
@NonNull String packageName, @NonNull String shortcutId, int userId);
|
||||
|
||||
public abstract boolean hasShortcutHostPermission(int launcherUserId,
|
||||
@NonNull String callingPackage);
|
||||
|
||||
@@ -213,8 +213,11 @@ public class LauncherAppsService extends SystemService {
|
||||
* Checks if the caller is in the same group as the userToCheck.
|
||||
*/
|
||||
private void ensureInUserProfiles(UserHandle userToCheck, String message) {
|
||||
ensureInUserProfiles(userToCheck.getIdentifier(), message);
|
||||
}
|
||||
|
||||
private void ensureInUserProfiles(int targetUserId, String message) {
|
||||
final int callingUserId = injectCallingUserId();
|
||||
final int targetUserId = userToCheck.getIdentifier();
|
||||
|
||||
if (targetUserId == callingUserId) return;
|
||||
|
||||
@@ -253,9 +256,13 @@ public class LauncherAppsService extends SystemService {
|
||||
* Checks if the user is enabled.
|
||||
*/
|
||||
private boolean isUserEnabled(UserHandle user) {
|
||||
return isUserEnabled(user.getIdentifier());
|
||||
}
|
||||
|
||||
private boolean isUserEnabled(int userId) {
|
||||
long ident = injectClearCallingIdentity();
|
||||
try {
|
||||
UserInfo targetUserInfo = mUm.getUserInfo(user.getIdentifier());
|
||||
UserInfo targetUserInfo = mUm.getUserInfo(userId);
|
||||
return targetUserInfo != null && targetUserInfo.isEnabled();
|
||||
} finally {
|
||||
injectRestoreCallingIdentity(ident);
|
||||
@@ -346,8 +353,12 @@ public class LauncherAppsService extends SystemService {
|
||||
}
|
||||
|
||||
private void ensureShortcutPermission(@NonNull String callingPackage, UserHandle user) {
|
||||
ensureShortcutPermission(callingPackage, user.getIdentifier());
|
||||
}
|
||||
|
||||
private void ensureShortcutPermission(@NonNull String callingPackage, int userId) {
|
||||
verifyCallingPackage(callingPackage);
|
||||
ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user);
|
||||
ensureInUserProfiles(userId, "Cannot start activity for unrelated profile " + userId);
|
||||
|
||||
if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(),
|
||||
callingPackage)) {
|
||||
@@ -357,31 +368,23 @@ public class LauncherAppsService extends SystemService {
|
||||
|
||||
@Override
|
||||
public ParceledListSlice getShortcuts(String callingPackage, long changedSince,
|
||||
String packageName, ComponentName componentName, int flags, UserHandle user) {
|
||||
String packageName, List shortcutIds, ComponentName componentName, int flags,
|
||||
UserHandle user) {
|
||||
ensureShortcutPermission(callingPackage, user);
|
||||
if (!isUserEnabled(user)) {
|
||||
return new ParceledListSlice<>(new ArrayList(0));
|
||||
}
|
||||
if (shortcutIds != null && packageName == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"To query by shortcut ID, package name must also be set");
|
||||
}
|
||||
|
||||
return new ParceledListSlice<>(
|
||||
mShortcutServiceInternal.getShortcuts(getCallingUserId(),
|
||||
callingPackage, changedSince, packageName,
|
||||
callingPackage, changedSince, packageName, shortcutIds,
|
||||
componentName, flags, user.getIdentifier()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParceledListSlice getShortcutInfo(String callingPackage, String packageName,
|
||||
List<String> ids, UserHandle user) {
|
||||
ensureShortcutPermission(callingPackage, user);
|
||||
if (!isUserEnabled(user)) {
|
||||
return new ParceledListSlice<>(new ArrayList(0));
|
||||
}
|
||||
|
||||
return new ParceledListSlice<>(
|
||||
mShortcutServiceInternal.getShortcutInfo(getCallingUserId(),
|
||||
callingPackage, packageName, ids, user.getIdentifier()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pinShortcuts(String callingPackage, String packageName, List<String> ids,
|
||||
UserHandle user) {
|
||||
@@ -396,27 +399,27 @@ public class LauncherAppsService extends SystemService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getShortcutIconResId(String callingPackage, ShortcutInfo shortcut,
|
||||
UserHandle user) {
|
||||
ensureShortcutPermission(callingPackage, user);
|
||||
if (!isUserEnabled(user)) {
|
||||
public int getShortcutIconResId(String callingPackage, String packageName, String id,
|
||||
int userId) {
|
||||
ensureShortcutPermission(callingPackage, userId);
|
||||
if (!isUserEnabled(userId)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return mShortcutServiceInternal.getShortcutIconResId(getCallingUserId(),
|
||||
callingPackage, shortcut, user.getIdentifier());
|
||||
callingPackage, packageName, id, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParcelFileDescriptor getShortcutIconFd(String callingPackage, ShortcutInfo shortcut,
|
||||
UserHandle user) {
|
||||
ensureShortcutPermission(callingPackage, user);
|
||||
if (!isUserEnabled(user)) {
|
||||
public ParcelFileDescriptor getShortcutIconFd(String callingPackage,
|
||||
String packageName, String id, int userId) {
|
||||
ensureShortcutPermission(callingPackage, userId);
|
||||
if (!isUserEnabled(userId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return mShortcutServiceInternal.getShortcutIconFd(getCallingUserId(),
|
||||
callingPackage, shortcut, user.getIdentifier());
|
||||
callingPackage, packageName, id, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -428,23 +431,23 @@ public class LauncherAppsService extends SystemService {
|
||||
|
||||
@Override
|
||||
public boolean startShortcut(String callingPackage, String packageName, String shortcutId,
|
||||
Rect sourceBounds, Bundle startActivityOptions, UserHandle user) {
|
||||
Rect sourceBounds, Bundle startActivityOptions, int userId) {
|
||||
verifyCallingPackage(callingPackage);
|
||||
ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user);
|
||||
ensureInUserProfiles(userId, "Cannot start activity for unrelated profile " + userId);
|
||||
|
||||
if (!isUserEnabled(user)) {
|
||||
if (!isUserEnabled(userId)) {
|
||||
throw new IllegalStateException("Cannot start a shortcut for disabled profile "
|
||||
+ user);
|
||||
+ userId);
|
||||
}
|
||||
|
||||
// Even without the permission, pinned shortcuts are always launchable.
|
||||
if (!mShortcutServiceInternal.isPinnedByCaller(getCallingUserId(),
|
||||
callingPackage, packageName, shortcutId, user.getIdentifier())) {
|
||||
ensureShortcutPermission(callingPackage, user);
|
||||
callingPackage, packageName, shortcutId, userId)) {
|
||||
ensureShortcutPermission(callingPackage, userId);
|
||||
}
|
||||
|
||||
final Intent intent = mShortcutServiceInternal.createShortcutIntent(getCallingUserId(),
|
||||
callingPackage, packageName, shortcutId, user.getIdentifier());
|
||||
callingPackage, packageName, shortcutId, userId);
|
||||
if (intent == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -455,7 +458,7 @@ public class LauncherAppsService extends SystemService {
|
||||
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mContext.startActivityAsUser(intent, startActivityOptions, user);
|
||||
mContext.startActivityAsUser(intent, startActivityOptions, UserHandle.of(userId));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
@@ -768,7 +771,8 @@ public class LauncherAppsService extends SystemService {
|
||||
final List<ShortcutInfo> list =
|
||||
mShortcutServiceInternal.getShortcuts(launcherUserId,
|
||||
cookie.packageName,
|
||||
/* changedSince= */ 0, packageName, /* component= */ null,
|
||||
/* changedSince= */ 0, packageName, /* shortcutIds=*/ null,
|
||||
/* component= */ null,
|
||||
ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY
|
||||
| ShortcutQuery.FLAG_GET_PINNED
|
||||
| ShortcutQuery.FLAG_GET_DYNAMIC
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.android.server.pm;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
@@ -522,7 +523,7 @@ class ShortcutPackage extends ShortcutPackageItem {
|
||||
ret.getPackageInfo().loadFromXml(parser, fromBackup);
|
||||
continue;
|
||||
case TAG_SHORTCUT:
|
||||
final ShortcutInfo si = parseShortcut(parser, packageName);
|
||||
final ShortcutInfo si = parseShortcut(parser, packageName, ownerUserId);
|
||||
|
||||
// Don't use addShortcut(), we don't need to save the icon.
|
||||
ret.mShortcuts.put(si.getId(), si);
|
||||
@@ -534,8 +535,8 @@ class ShortcutPackage extends ShortcutPackageItem {
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static ShortcutInfo parseShortcut(XmlPullParser parser, String packageName)
|
||||
throws IOException, XmlPullParserException {
|
||||
private static ShortcutInfo parseShortcut(XmlPullParser parser, String packageName,
|
||||
@UserIdInt int userId) throws IOException, XmlPullParserException {
|
||||
String id;
|
||||
ComponentName activityComponent;
|
||||
// Icon icon;
|
||||
@@ -586,7 +587,7 @@ class ShortcutPackage extends ShortcutPackageItem {
|
||||
throw ShortcutService.throwForInvalidTag(depth, tag);
|
||||
}
|
||||
return new ShortcutInfo(
|
||||
id, packageName, activityComponent, /* icon =*/ null, title, text, intent,
|
||||
userId, id, packageName, activityComponent, /* icon =*/ null, title, text, intent,
|
||||
intentPersistableExtras, weight, extras, lastChangedTimestamp, flags,
|
||||
iconRes, bitmapPath);
|
||||
}
|
||||
|
||||
@@ -968,7 +968,8 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
return; // has no icon
|
||||
}
|
||||
|
||||
Bitmap bitmap = null;
|
||||
Bitmap bitmap;
|
||||
Bitmap bitmapToRecycle = null;
|
||||
try {
|
||||
switch (icon.getType()) {
|
||||
case Icon.TYPE_RESOURCE: {
|
||||
@@ -979,7 +980,7 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
return;
|
||||
}
|
||||
case Icon.TYPE_BITMAP: {
|
||||
bitmap = icon.getBitmap();
|
||||
bitmap = icon.getBitmap(); // Don't recycle in this case.
|
||||
break;
|
||||
}
|
||||
case Icon.TYPE_URI: {
|
||||
@@ -987,7 +988,8 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
|
||||
try (InputStream is = mContext.getContentResolver().openInputStream(uri)) {
|
||||
|
||||
bitmap = BitmapFactory.decodeStream(is);
|
||||
bitmapToRecycle = BitmapFactory.decodeStream(is);
|
||||
bitmap = bitmapToRecycle;
|
||||
|
||||
} catch (IOException e) {
|
||||
Slog.e(TAG, "Unable to load icon from " + uri);
|
||||
@@ -1011,8 +1013,14 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
try {
|
||||
path = out.getFile();
|
||||
|
||||
shrinkBitmap(bitmap, mMaxIconDimension)
|
||||
.compress(mIconPersistFormat, mIconPersistQuality, out);
|
||||
Bitmap shrunk = shrinkBitmap(bitmap, mMaxIconDimension);
|
||||
try {
|
||||
shrunk.compress(mIconPersistFormat, mIconPersistQuality, out);
|
||||
} finally {
|
||||
if (bitmap != shrunk) {
|
||||
shrunk.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
shortcut.setBitmapPath(out.getFile().getAbsolutePath());
|
||||
shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_FILE);
|
||||
@@ -1027,8 +1035,8 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (bitmap != null) {
|
||||
bitmap.recycle();
|
||||
if (bitmapToRecycle != null) {
|
||||
bitmapToRecycle.recycle();
|
||||
}
|
||||
// Once saved, we won't use the original icon information, so null it out.
|
||||
shortcut.clearIcon();
|
||||
@@ -1076,8 +1084,6 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
|
||||
c.drawBitmap(in, /*src=*/ null, dst, /* paint =*/ null);
|
||||
|
||||
in.recycle();
|
||||
|
||||
return scaledBitmap;
|
||||
}
|
||||
|
||||
@@ -1580,13 +1586,17 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
@Override
|
||||
public List<ShortcutInfo> getShortcuts(int launcherUserId,
|
||||
@NonNull String callingPackage, long changedSince,
|
||||
@Nullable String packageName, @Nullable ComponentName componentName,
|
||||
@Nullable String packageName, @Nullable List<String> shortcutIds,
|
||||
@Nullable ComponentName componentName,
|
||||
int queryFlags, int userId) {
|
||||
final ArrayList<ShortcutInfo> ret = new ArrayList<>();
|
||||
final int cloneFlag =
|
||||
((queryFlags & ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY) == 0)
|
||||
? ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER
|
||||
: ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO;
|
||||
if (packageName == null) {
|
||||
shortcutIds = null; // LauncherAppsService already threw for it though.
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
|
||||
@@ -1594,14 +1604,14 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
|
||||
if (packageName != null) {
|
||||
getShortcutsInnerLocked(launcherUserId,
|
||||
callingPackage, packageName, changedSince,
|
||||
callingPackage, packageName, shortcutIds, changedSince,
|
||||
componentName, queryFlags, userId, ret, cloneFlag);
|
||||
} else {
|
||||
final ArrayMap<String, ShortcutPackage> packages =
|
||||
getUserShortcutsLocked(userId).getAllPackages();
|
||||
for (int i = packages.size() - 1; i >= 0; i--) {
|
||||
getShortcutsInnerLocked(launcherUserId,
|
||||
callingPackage, packages.keyAt(i), changedSince,
|
||||
callingPackage, packages.keyAt(i), shortcutIds, changedSince,
|
||||
componentName, queryFlags, userId, ret, cloneFlag);
|
||||
}
|
||||
}
|
||||
@@ -1610,14 +1620,20 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
}
|
||||
|
||||
private void getShortcutsInnerLocked(int launcherUserId, @NonNull String callingPackage,
|
||||
@Nullable String packageName,long changedSince,
|
||||
@Nullable String packageName, @Nullable List<String> shortcutIds, long changedSince,
|
||||
@Nullable ComponentName componentName, int queryFlags,
|
||||
int userId, ArrayList<ShortcutInfo> ret, int cloneFlag) {
|
||||
final ArraySet<String> ids = shortcutIds == null ? null
|
||||
: new ArraySet<>(shortcutIds);
|
||||
|
||||
getPackageShortcutsLocked(packageName, userId).findAll(ShortcutService.this, ret,
|
||||
(ShortcutInfo si) -> {
|
||||
if (si.getLastChangedTimestamp() < changedSince) {
|
||||
return false;
|
||||
}
|
||||
if (ids != null && !ids.contains(si.getId())) {
|
||||
return false;
|
||||
}
|
||||
if (componentName != null
|
||||
&& !componentName.equals(si.getActivityComponent())) {
|
||||
return false;
|
||||
@@ -1632,27 +1648,6 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
}, cloneFlag, callingPackage, launcherUserId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ShortcutInfo> getShortcutInfo(int launcherUserId,
|
||||
@NonNull String callingPackage,
|
||||
@NonNull String packageName, @Nullable List<String> ids, int userId) {
|
||||
// Calling permission must be checked by LauncherAppsImpl.
|
||||
Preconditions.checkStringNotEmpty(packageName, "packageName");
|
||||
|
||||
final ArrayList<ShortcutInfo> ret = new ArrayList<>(ids.size());
|
||||
final ArraySet<String> idSet = new ArraySet<>(ids);
|
||||
synchronized (mLock) {
|
||||
getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
|
||||
.attemptToRestoreIfNeededAndSave(ShortcutService.this);
|
||||
|
||||
getPackageShortcutsLocked(packageName, userId).findAll(
|
||||
ShortcutService.this, ret,
|
||||
(ShortcutInfo si) -> idSet.contains(si.getId()),
|
||||
ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER, callingPackage, launcherUserId);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPinnedByCaller(int launcherUserId, @NonNull String callingPackage,
|
||||
@NonNull String packageName, @NonNull String shortcutId, int userId) {
|
||||
@@ -1733,17 +1728,18 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getShortcutIconResId(int launcherUserId,
|
||||
@NonNull String callingPackage,
|
||||
@NonNull ShortcutInfo shortcut, int userId) {
|
||||
Preconditions.checkNotNull(shortcut, "shortcut");
|
||||
public int getShortcutIconResId(int launcherUserId, @NonNull String callingPackage,
|
||||
@NonNull String packageName, @NonNull String shortcutId, int userId) {
|
||||
Preconditions.checkNotNull(callingPackage, "callingPackage");
|
||||
Preconditions.checkNotNull(packageName, "packageName");
|
||||
Preconditions.checkNotNull(shortcutId, "shortcutId");
|
||||
|
||||
synchronized (mLock) {
|
||||
getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
|
||||
.attemptToRestoreIfNeededAndSave(ShortcutService.this);
|
||||
|
||||
final ShortcutInfo shortcutInfo = getPackageShortcutsLocked(
|
||||
shortcut.getPackageName(), userId).findShortcutById(shortcut.getId());
|
||||
packageName, userId).findShortcutById(shortcutId);
|
||||
return (shortcutInfo != null && shortcutInfo.hasIconResource())
|
||||
? shortcutInfo.getIconResourceId() : 0;
|
||||
}
|
||||
@@ -1751,16 +1747,18 @@ public class ShortcutService extends IShortcutService.Stub {
|
||||
|
||||
@Override
|
||||
public ParcelFileDescriptor getShortcutIconFd(int launcherUserId,
|
||||
@NonNull String callingPackage,
|
||||
@NonNull ShortcutInfo shortcutIn, int userId) {
|
||||
Preconditions.checkNotNull(shortcutIn, "shortcut");
|
||||
@NonNull String callingPackage, @NonNull String packageName,
|
||||
@NonNull String shortcutId, int userId) {
|
||||
Preconditions.checkNotNull(callingPackage, "callingPackage");
|
||||
Preconditions.checkNotNull(packageName, "packageName");
|
||||
Preconditions.checkNotNull(shortcutId, "shortcutId");
|
||||
|
||||
synchronized (mLock) {
|
||||
getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
|
||||
.attemptToRestoreIfNeededAndSave(ShortcutService.this);
|
||||
|
||||
final ShortcutInfo shortcutInfo = getPackageShortcutsLocked(
|
||||
shortcutIn.getPackageName(), userId).findShortcutById(shortcutIn.getId());
|
||||
packageName, userId).findShortcutById(shortcutId);
|
||||
if (shortcutInfo == null || !shortcutInfo.hasIconFile()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -172,6 +172,11 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
public String getPackageName() {
|
||||
return mInjectedClientPackage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUserId() {
|
||||
return getCallingUserId();
|
||||
}
|
||||
}
|
||||
|
||||
/** Context used in the service side */
|
||||
@@ -190,6 +195,11 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
public void startActivityAsUser(@RequiresPermission Intent intent, @Nullable Bundle options,
|
||||
UserHandle userId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUserId() {
|
||||
return UserHandle.USER_SYSTEM;
|
||||
}
|
||||
}
|
||||
|
||||
/** ShortcutService with injection override methods. */
|
||||
@@ -1152,9 +1162,25 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
return intentCaptor.getValue();
|
||||
}
|
||||
|
||||
private Intent launchShortcutAndGetIntent_withShortcutInfo(
|
||||
@NonNull String packageName, @NonNull String shortcutId, int userId) {
|
||||
reset(mServiceContext);
|
||||
|
||||
assertTrue(mLauncherApps.startShortcut(
|
||||
getShortcutInfoAsLauncher(packageName, shortcutId, userId), null, null));
|
||||
|
||||
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mServiceContext).startActivityAsUser(
|
||||
intentCaptor.capture(),
|
||||
any(Bundle.class),
|
||||
eq(UserHandle.of(userId)));
|
||||
return intentCaptor.getValue();
|
||||
}
|
||||
|
||||
private void assertShortcutLaunchable(@NonNull String packageName, @NonNull String shortcutId,
|
||||
int userId) {
|
||||
assertNotNull(launchShortcutAndGetIntent(packageName, shortcutId, userId));
|
||||
assertNotNull(launchShortcutAndGetIntent_withShortcutInfo(packageName, shortcutId, userId));
|
||||
}
|
||||
|
||||
private void assertShortcutNotLaunchable(@NonNull String packageName,
|
||||
@@ -1193,6 +1219,14 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
return getLauncherShortcuts(launcher, userId, ShortcutQuery.FLAG_GET_PINNED);
|
||||
}
|
||||
|
||||
private ShortcutInfo getShortcutInfoAsLauncher(String packageName, String shortcutId,
|
||||
int userId) {
|
||||
final List<ShortcutInfo> infoList =
|
||||
mLauncherApps.getShortcutInfo(packageName, list(shortcutId),
|
||||
UserHandle.of(userId));
|
||||
assertEquals("No shortcutInfo found (or too many of them)", 1, infoList.size());
|
||||
return infoList.get(0);
|
||||
}
|
||||
|
||||
private Intent genPackageDeleteIntent(String pakcageName, int userId) {
|
||||
Intent i = new Intent(Intent.ACTION_PACKAGE_REMOVED);
|
||||
@@ -1728,6 +1762,16 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
"res64x64",
|
||||
"none");
|
||||
|
||||
// Different profile. Note the names and the contents don't match.
|
||||
setCaller(CALLING_PACKAGE_1, USER_P0);
|
||||
assertTrue(mManager.setDynamicShortcuts(list(
|
||||
makeShortcutWithIcon("res32x32", res512x512),
|
||||
makeShortcutWithIcon("bmp32x32", bmp512x512)
|
||||
)));
|
||||
assertShortcutIds(assertAllNotHaveIcon(mManager.getDynamicShortcuts()),
|
||||
"res32x32",
|
||||
"bmp32x32");
|
||||
|
||||
// Re-initialize and load from the files.
|
||||
mService.saveDirtyInfo();
|
||||
initService();
|
||||
@@ -1737,61 +1781,90 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
|
||||
setCaller(LAUNCHER_1);
|
||||
// Check hasIconResource()/hasIconFile().
|
||||
assertShortcutIds(assertAllHaveIconResId(mLauncherApps.getShortcutInfo(
|
||||
CALLING_PACKAGE_1, list("res32x32"),
|
||||
getCallingUser())), "res32x32");
|
||||
assertShortcutIds(assertAllHaveIconResId(
|
||||
list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res32x32", USER_0))),
|
||||
"res32x32");
|
||||
|
||||
assertShortcutIds(assertAllHaveIconResId(mLauncherApps.getShortcutInfo(
|
||||
CALLING_PACKAGE_1, list("res64x64"), getCallingUser())),
|
||||
assertShortcutIds(assertAllHaveIconResId(
|
||||
list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res64x64", USER_0))),
|
||||
"res64x64");
|
||||
|
||||
assertShortcutIds(assertAllHaveIconFile(mLauncherApps.getShortcutInfo(
|
||||
CALLING_PACKAGE_1, list("bmp32x32"), getCallingUser())),
|
||||
assertShortcutIds(assertAllHaveIconFile(
|
||||
list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_0))),
|
||||
"bmp32x32");
|
||||
|
||||
assertShortcutIds(assertAllHaveIconFile(mLauncherApps.getShortcutInfo(
|
||||
CALLING_PACKAGE_1, list("bmp64x64"), getCallingUser())),
|
||||
assertShortcutIds(assertAllHaveIconFile(
|
||||
list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp64x64", USER_0))),
|
||||
"bmp64x64");
|
||||
|
||||
assertShortcutIds(assertAllHaveIconFile(mLauncherApps.getShortcutInfo(
|
||||
CALLING_PACKAGE_1, list("bmp512x512"), getCallingUser())),
|
||||
assertShortcutIds(assertAllHaveIconFile(
|
||||
list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp512x512", USER_0))),
|
||||
"bmp512x512");
|
||||
|
||||
assertShortcutIds(assertAllHaveIconResId(
|
||||
list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res32x32", USER_P0))),
|
||||
"res32x32");
|
||||
assertShortcutIds(assertAllHaveIconFile(
|
||||
list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_P0))),
|
||||
"bmp32x32");
|
||||
|
||||
// Check
|
||||
assertEquals(
|
||||
R.drawable.black_32x32,
|
||||
mLauncherApps.getShortcutIconResId(
|
||||
makePackageShortcut(CALLING_PACKAGE_1, "res32x32"), getCallingUser()));
|
||||
getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res32x32", USER_0)));
|
||||
|
||||
assertEquals(
|
||||
R.drawable.black_64x64,
|
||||
mLauncherApps.getShortcutIconResId(
|
||||
|
||||
makePackageShortcut(CALLING_PACKAGE_1, "res64x64"), getCallingUser()));
|
||||
getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res64x64", USER_0)));
|
||||
|
||||
assertEquals(
|
||||
0, // because it's not a resource
|
||||
mLauncherApps.getShortcutIconResId(
|
||||
makePackageShortcut(CALLING_PACKAGE_1, "bmp32x32"), getCallingUser()));
|
||||
getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_0)));
|
||||
assertEquals(
|
||||
0, // because it's not a resource
|
||||
mLauncherApps.getShortcutIconResId(
|
||||
makePackageShortcut(CALLING_PACKAGE_1, "bmp64x64"), getCallingUser()));
|
||||
getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp64x64", USER_0)));
|
||||
assertEquals(
|
||||
0, // because it's not a resource
|
||||
mLauncherApps.getShortcutIconResId(
|
||||
makePackageShortcut(CALLING_PACKAGE_1, "bmp512x512"), getCallingUser()));
|
||||
getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp512x512", USER_0)));
|
||||
|
||||
bmp = pfdToBitmap(mLauncherApps.getShortcutIconFd(
|
||||
makePackageShortcut(CALLING_PACKAGE_1, "bmp32x32"), getCallingUser()));
|
||||
getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_0)));
|
||||
assertBitmapSize(32, 32, bmp);
|
||||
|
||||
bmp = pfdToBitmap(mLauncherApps.getShortcutIconFd(
|
||||
makePackageShortcut(CALLING_PACKAGE_1, "bmp64x64"), getCallingUser()));
|
||||
getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp64x64", USER_0)));
|
||||
assertBitmapSize(64, 64, bmp);
|
||||
|
||||
bmp = pfdToBitmap(mLauncherApps.getShortcutIconFd(
|
||||
makePackageShortcut(CALLING_PACKAGE_1, "bmp512x512"), getCallingUser()));
|
||||
getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp512x512", USER_0)));
|
||||
assertBitmapSize(128, 128, bmp);
|
||||
|
||||
assertEquals(
|
||||
R.drawable.black_512x512,
|
||||
mLauncherApps.getShortcutIconResId(
|
||||
getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res32x32", USER_P0)));
|
||||
// Should be 512x512, so shrunk.
|
||||
bmp = pfdToBitmap(mLauncherApps.getShortcutIconFd(
|
||||
getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_P0)));
|
||||
assertBitmapSize(128, 128, bmp);
|
||||
|
||||
// Also check the overload APIs too.
|
||||
assertEquals(
|
||||
R.drawable.black_32x32,
|
||||
mLauncherApps.getShortcutIconResId(CALLING_PACKAGE_1, "res32x32", HANDLE_USER_0));
|
||||
assertEquals(
|
||||
R.drawable.black_64x64,
|
||||
mLauncherApps.getShortcutIconResId(CALLING_PACKAGE_1, "res64x64", HANDLE_USER_0));
|
||||
assertEquals(
|
||||
R.drawable.black_512x512,
|
||||
mLauncherApps.getShortcutIconResId(CALLING_PACKAGE_1, "res32x32", HANDLE_USER_P0));
|
||||
bmp = pfdToBitmap(
|
||||
mLauncherApps.getShortcutIconFd(CALLING_PACKAGE_1, "bmp32x32", HANDLE_USER_P0));
|
||||
assertBitmapSize(128, 128, bmp);
|
||||
|
||||
// TODO Test the content URI case too.
|
||||
@@ -2034,9 +2107,16 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
private static ShortcutQuery buildQuery(long changedSince,
|
||||
String packageName, ComponentName componentName,
|
||||
/* @ShortcutQuery.QueryFlags */ int flags) {
|
||||
return buildQuery(changedSince, packageName, null, componentName, flags);
|
||||
}
|
||||
|
||||
private static ShortcutQuery buildQuery(long changedSince,
|
||||
String packageName, List<String> shortcutIds, ComponentName componentName,
|
||||
/* @ShortcutQuery.QueryFlags */ int flags) {
|
||||
final ShortcutQuery q = new ShortcutQuery();
|
||||
q.setChangedSince(changedSince);
|
||||
q.setPackage(packageName);
|
||||
q.setShortcutIds(shortcutIds);
|
||||
q.setActivity(componentName);
|
||||
q.setQueryFlags(flags);
|
||||
return q;
|
||||
@@ -2110,6 +2190,36 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
getCallingUser())),
|
||||
"s2", "s3"))));
|
||||
|
||||
// With ID.
|
||||
assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
|
||||
assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
|
||||
/* time =*/ 1000, CALLING_PACKAGE_2, list("s3"),
|
||||
/* activity =*/ null,
|
||||
ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
|
||||
getCallingUser())),
|
||||
"s3"))));
|
||||
assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
|
||||
assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
|
||||
/* time =*/ 1000, CALLING_PACKAGE_2, list("s3", "s2", "ss"),
|
||||
/* activity =*/ null,
|
||||
ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
|
||||
getCallingUser())),
|
||||
"s2", "s3"))));
|
||||
assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
|
||||
assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
|
||||
/* time =*/ 1000, CALLING_PACKAGE_2, list("s3x", "s2x"),
|
||||
/* activity =*/ null,
|
||||
ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
|
||||
getCallingUser()))
|
||||
/* empty */))));
|
||||
assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
|
||||
assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
|
||||
/* time =*/ 1000, CALLING_PACKAGE_2, list(),
|
||||
/* activity =*/ null,
|
||||
ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
|
||||
getCallingUser()))
|
||||
/* empty */))));
|
||||
|
||||
// Pin some shortcuts.
|
||||
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
|
||||
list("s3", "s4"), getCallingUser());
|
||||
@@ -2132,6 +2242,13 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
getCallingUser())),
|
||||
"s1", "s3");
|
||||
|
||||
TestUtils.assertExpectException(
|
||||
IllegalArgumentException.class, "package name must also be set", () -> {
|
||||
mLauncherApps.getShortcuts(buildQuery(
|
||||
/* time =*/ 0, /* package= */ null, list("id"),
|
||||
/* activity =*/ null, /* flags */ 0), getCallingUser());
|
||||
});
|
||||
|
||||
// TODO More tests: pinned but dynamic, filter by activity
|
||||
}
|
||||
|
||||
@@ -5063,12 +5180,15 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
}
|
||||
|
||||
public void testShortcutInfoParcel() {
|
||||
ShortcutInfo si = parceled(new ShortcutInfo.Builder(getTestContext())
|
||||
setCaller(CALLING_PACKAGE_1, USER_10);
|
||||
ShortcutInfo si = parceled(new ShortcutInfo.Builder(mClientContext)
|
||||
.setId("id")
|
||||
.setTitle("title")
|
||||
.setIntent(makeIntent("action", ShortcutActivity.class))
|
||||
.build());
|
||||
assertEquals(getTestContext().getPackageName(), si.getPackageName());
|
||||
assertEquals(mClientContext.getPackageName(), si.getPackageName());
|
||||
assertEquals(USER_10, si.getUserId());
|
||||
assertEquals(HANDLE_USER_10, si.getUserHandle());
|
||||
assertEquals("id", si.getId());
|
||||
assertEquals("title", si.getTitle());
|
||||
assertEquals("action", si.getIntent().getAction());
|
||||
@@ -5109,9 +5229,11 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
}
|
||||
|
||||
public void testShortcutInfoClone() {
|
||||
setCaller(CALLING_PACKAGE_1, USER_11);
|
||||
|
||||
PersistableBundle pb = new PersistableBundle();
|
||||
pb.putInt("k", 1);
|
||||
ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
|
||||
ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
|
||||
.setId("id")
|
||||
.setActivityComponent(new ComponentName("a", "b"))
|
||||
.setIcon(Icon.createWithContentUri("content://a.b.c/"))
|
||||
@@ -5127,7 +5249,9 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
|
||||
ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
|
||||
|
||||
assertEquals(getTestContext().getPackageName(), si.getPackageName());
|
||||
assertEquals(USER_11, si.getUserId());
|
||||
assertEquals(HANDLE_USER_11, si.getUserHandle());
|
||||
assertEquals(mClientContext.getPackageName(), si.getPackageName());
|
||||
assertEquals("id", si.getId());
|
||||
assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
|
||||
assertEquals("content://a.b.c/", si.getIcon().getUriString());
|
||||
@@ -5144,7 +5268,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
|
||||
si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
|
||||
|
||||
assertEquals(getTestContext().getPackageName(), si.getPackageName());
|
||||
assertEquals(mClientContext.getPackageName(), si.getPackageName());
|
||||
assertEquals("id", si.getId());
|
||||
assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
|
||||
assertEquals(null, si.getIcon());
|
||||
@@ -5161,7 +5285,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
|
||||
si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
|
||||
|
||||
assertEquals(getTestContext().getPackageName(), si.getPackageName());
|
||||
assertEquals(mClientContext.getPackageName(), si.getPackageName());
|
||||
assertEquals("id", si.getId());
|
||||
assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
|
||||
assertEquals(null, si.getIcon());
|
||||
@@ -5177,7 +5301,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
|
||||
si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
|
||||
|
||||
assertEquals(getTestContext().getPackageName(), si.getPackageName());
|
||||
assertEquals(mClientContext.getPackageName(), si.getPackageName());
|
||||
assertEquals("id", si.getId());
|
||||
assertEquals(null, si.getActivityComponent());
|
||||
assertEquals(null, si.getIcon());
|
||||
@@ -5267,7 +5391,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
}
|
||||
|
||||
public void testShortcutInfoSaveAndLoad() throws InterruptedException {
|
||||
setCaller(CALLING_PACKAGE_1, USER_0);
|
||||
setCaller(CALLING_PACKAGE_1, USER_10);
|
||||
|
||||
final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
|
||||
getTestContext().getResources(), R.drawable.black_32x32));
|
||||
@@ -5293,11 +5417,13 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
|
||||
// Save and load.
|
||||
mService.saveDirtyInfo();
|
||||
initService();
|
||||
mService.handleUnlockUser(USER_0);
|
||||
mService.handleUnlockUser(USER_10);
|
||||
|
||||
ShortcutInfo si;
|
||||
si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
|
||||
si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10);
|
||||
|
||||
assertEquals(USER_10, si.getUserId());
|
||||
assertEquals(HANDLE_USER_10, si.getUserHandle());
|
||||
assertEquals(CALLING_PACKAGE_1, si.getPackageName());
|
||||
assertEquals("id", si.getId());
|
||||
assertEquals(ShortcutActivity2.class.getName(), si.getActivityComponent().getClassName());
|
||||
|
||||
Reference in New Issue
Block a user