Merge \"ShortcutManager: Make sure persisted default launcher still exists.\" into nyc-mr1-dev

am: 5b080d4e90

Change-Id: I8f1db21f5372a23b6584c1275aa0a2ee6edadb53
This commit is contained in:
Makoto Onuki
2016-07-01 16:42:24 +00:00
committed by android-build-merger
9 changed files with 502 additions and 87 deletions

View File

@@ -260,9 +260,6 @@ class ShortcutPackage extends ShortcutPackageItem {
} }
} }
// TODO Check max dynamic count.
// mShortcutUser.mService.enforceMaxDynamicShortcuts(newDynamicCount);
// If it was originally pinned, the new one should be pinned too. // If it was originally pinned, the new one should be pinned too.
if (wasPinned) { if (wasPinned) {
newShortcut.addFlags(ShortcutInfo.FLAG_PINNED); newShortcut.addFlags(ShortcutInfo.FLAG_PINNED);

View File

@@ -20,7 +20,6 @@ import android.annotation.UserIdInt;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutInfo;
import android.content.res.TypedArray; import android.content.res.TypedArray;
@@ -79,7 +78,7 @@ public class ShortcutParser {
} }
final ActivityInfo activityInfoWithMetadata = final ActivityInfo activityInfoWithMetadata =
service.injectGetActivityInfoWithMetadata( service.getActivityInfoWithMetadata(
activityInfoNoMetadata.getComponentName(), userId); activityInfoNoMetadata.getComponentName(), userId);
if (activityInfoWithMetadata != null) { if (activityInfoWithMetadata != null) {
result = parseShortcutsOneFile( result = parseShortcutsOneFile(

View File

@@ -232,6 +232,13 @@ public class ShortcutService extends IShortcutService.Stub {
private final Object mLock = new Object(); private final Object mLock = new Object();
private static List<ResolveInfo> EMPTY_RESOLVE_INFO = new ArrayList<>(0);
private static Predicate<ResolveInfo> ACTIVITY_NOT_EXPORTED =
ri -> !ri.activityInfo.exported;
private static Predicate<PackageInfo> PACKAGE_NOT_INSTALLED = pi -> !isInstalled(pi);
private final Handler mHandler; private final Handler mHandler;
@GuardedBy("mLock") @GuardedBy("mLock")
@@ -318,8 +325,9 @@ public class ShortcutService extends IShortcutService.Stub {
int RESOURCE_NAME_LOOKUP = 10; int RESOURCE_NAME_LOOKUP = 10;
int GET_LAUNCHER_ACTIVITY = 11; int GET_LAUNCHER_ACTIVITY = 11;
int CHECK_LAUNCHER_ACTIVITY = 12; int CHECK_LAUNCHER_ACTIVITY = 12;
int IS_ACTIVITY_ENABLED = 13;
int COUNT = CHECK_LAUNCHER_ACTIVITY + 1; int COUNT = IS_ACTIVITY_ENABLED + 1;
} }
final Object mStatLock = new Object(); final Object mStatLock = new Object();
@@ -348,11 +356,11 @@ public class ShortcutService extends IShortcutService.Stub {
} }
public ShortcutService(Context context) { public ShortcutService(Context context) {
this(context, BackgroundThread.get().getLooper()); this(context, BackgroundThread.get().getLooper(), /*onyForPackgeManagerApis*/ false);
} }
@VisibleForTesting @VisibleForTesting
ShortcutService(Context context, Looper looper) { ShortcutService(Context context, Looper looper, boolean onlyForPackageManagerApis) {
mContext = Preconditions.checkNotNull(context); mContext = Preconditions.checkNotNull(context);
LocalServices.addService(ShortcutServiceInternal.class, new LocalService()); LocalServices.addService(ShortcutServiceInternal.class, new LocalService());
mHandler = new Handler(looper); mHandler = new Handler(looper);
@@ -363,6 +371,10 @@ public class ShortcutService extends IShortcutService.Stub {
mUsageStatsManagerInternal = Preconditions.checkNotNull( mUsageStatsManagerInternal = Preconditions.checkNotNull(
LocalServices.getService(UsageStatsManagerInternal.class)); LocalServices.getService(UsageStatsManagerInternal.class));
if (onlyForPackageManagerApis) {
return; // Don't do anything further. For unit tests only.
}
mPackageMonitor.register(context, looper, UserHandle.ALL, /* externalStorage= */ false); mPackageMonitor.register(context, looper, UserHandle.ALL, /* externalStorage= */ false);
injectRegisterUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE injectRegisterUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE
@@ -1571,11 +1583,6 @@ public class ShortcutService extends IShortcutService.Stub {
removeIcon(userId, target); removeIcon(userId, target);
} }
if (source.getActivity() != null &&
!source.getActivity().equals(target.getActivity())) {
// TODO When activity is changing, check the dynamic count.
}
// Note copyNonNullFieldsFrom() does the "updatable with?" check too. // Note copyNonNullFieldsFrom() does the "updatable with?" check too.
target.copyNonNullFieldsFrom(source); target.copyNonNullFieldsFrom(source);
target.setTimestamp(injectCurrentTimeMillis()); target.setTimestamp(injectCurrentTimeMillis());
@@ -1915,9 +1922,16 @@ public class ShortcutService extends IShortcutService.Stub {
} else { } else {
detected = user.getDefaultLauncherComponent(); detected = user.getDefaultLauncherComponent();
// TODO: Make sure it's still enabled. if (detected != null) {
if (DEBUG) { if (injectIsActivityEnabledAndExported(detected, userId)) {
Slog.v(TAG, "Cached launcher: " + detected); if (DEBUG) {
Slog.v(TAG, "Cached launcher: " + detected);
}
} else {
Slog.w(TAG, "Cached launcher " + detected + " no longer exists");
detected = null;
user.setDefaultLauncherComponent(null);
}
} }
} }
@@ -2363,6 +2377,10 @@ public class ShortcutService extends IShortcutService.Stub {
return; // Don't delete shadow information. return; // Don't delete shadow information.
} }
if (!isPackageInstalled(spi.getPackageName(), spi.getPackageUserId())) { if (!isPackageInstalled(spi.getPackageName(), spi.getPackageUserId())) {
if (DEBUG) {
Slog.d(TAG, "Uninstalled: " + spi.getPackageName()
+ " user " + spi.getPackageUserId());
}
gonePackages.add(PackageWithUser.of(spi)); gonePackages.add(PackageWithUser.of(spi));
} }
}); });
@@ -2457,21 +2475,26 @@ public class ShortcutService extends IShortcutService.Stub {
// === PackageManager interaction === // === PackageManager interaction ===
/**
* Returns {@link PackageInfo} unless it's uninstalled or disabled.
*/
@Nullable @Nullable
PackageInfo getPackageInfoWithSignatures(String packageName, @UserIdInt int userId) { final PackageInfo getPackageInfoWithSignatures(String packageName, @UserIdInt int userId) {
return injectPackageInfo(packageName, userId, true); return getPackageInfo(packageName, userId, true);
} }
/**
* Returns {@link PackageInfo} unless it's uninstalled or disabled.
*/
@Nullable @Nullable
PackageInfo getPackageInfo(String packageName, @UserIdInt int userId) { final PackageInfo getPackageInfo(String packageName, @UserIdInt int userId) {
return injectPackageInfo(packageName, userId, false); return getPackageInfo(packageName, userId, false);
} }
int injectGetPackageUid(@NonNull String packageName, @UserIdInt int userId) { int injectGetPackageUid(@NonNull String packageName, @UserIdInt int userId) {
final long token = injectClearCallingIdentity(); final long token = injectClearCallingIdentity();
try { try {
return mIPackageManager.getPackageUid(packageName, PACKAGE_MATCH_FLAGS return mIPackageManager.getPackageUid(packageName, PACKAGE_MATCH_FLAGS, userId);
, userId);
} catch (RemoteException e) { } catch (RemoteException e) {
// Shouldn't happen. // Shouldn't happen.
Slog.wtf(TAG, "RemoteException", e); Slog.wtf(TAG, "RemoteException", e);
@@ -2481,16 +2504,30 @@ public class ShortcutService extends IShortcutService.Stub {
} }
} }
/**
* Returns {@link PackageInfo} unless it's uninstalled or disabled.
*/
@Nullable @Nullable
@VisibleForTesting @VisibleForTesting
PackageInfo injectPackageInfo(String packageName, @UserIdInt int userId, final PackageInfo getPackageInfo(String packageName, @UserIdInt int userId,
boolean getSignatures) {
return isInstalledOrNull(injectPackageInfoWithUninstalled(
packageName, userId, getSignatures));
}
/**
* Do not use directly; this returns uninstalled packages too.
*/
@Nullable
@VisibleForTesting
PackageInfo injectPackageInfoWithUninstalled(String packageName, @UserIdInt int userId,
boolean getSignatures) { boolean getSignatures) {
final long start = injectElapsedRealtime(); final long start = injectElapsedRealtime();
final long token = injectClearCallingIdentity(); final long token = injectClearCallingIdentity();
try { try {
return mIPackageManager.getPackageInfo(packageName, PACKAGE_MATCH_FLAGS return mIPackageManager.getPackageInfo(
| (getSignatures ? PackageManager.GET_SIGNATURES : 0) packageName, PACKAGE_MATCH_FLAGS
, userId); | (getSignatures ? PackageManager.GET_SIGNATURES : 0), userId);
} catch (RemoteException e) { } catch (RemoteException e) {
// Shouldn't happen. // Shouldn't happen.
Slog.wtf(TAG, "RemoteException", e); Slog.wtf(TAG, "RemoteException", e);
@@ -2504,9 +2541,22 @@ public class ShortcutService extends IShortcutService.Stub {
} }
} }
/**
* Returns {@link ApplicationInfo} unless it's uninstalled or disabled.
*/
@Nullable @Nullable
@VisibleForTesting @VisibleForTesting
ApplicationInfo injectApplicationInfo(String packageName, @UserIdInt int userId) { final ApplicationInfo getApplicationInfo(String packageName, @UserIdInt int userId) {
return isInstalledOrNull(injectApplicationInfoWithUninstalled(packageName, userId));
}
/**
* Do not use directly; this returns uninstalled packages too.
*/
@Nullable
@VisibleForTesting
ApplicationInfo injectApplicationInfoWithUninstalled(
String packageName, @UserIdInt int userId) {
final long start = injectElapsedRealtime(); final long start = injectElapsedRealtime();
final long token = injectClearCallingIdentity(); final long token = injectClearCallingIdentity();
try { try {
@@ -2522,13 +2572,27 @@ public class ShortcutService extends IShortcutService.Stub {
} }
} }
/**
* Returns {@link ActivityInfo} with its metadata unless it's uninstalled or disabled.
*/
@Nullable @Nullable
ActivityInfo injectGetActivityInfoWithMetadata(ComponentName activity, @UserIdInt int userId) { final ActivityInfo getActivityInfoWithMetadata(ComponentName activity, @UserIdInt int userId) {
return isInstalledOrNull(injectGetActivityInfoWithMetadataWithUninstalled(
activity, userId));
}
/**
* Do not use directly; this returns uninstalled packages too.
*/
@Nullable
@VisibleForTesting
ActivityInfo injectGetActivityInfoWithMetadataWithUninstalled(
ComponentName activity, @UserIdInt int userId) {
final long start = injectElapsedRealtime(); final long start = injectElapsedRealtime();
final long token = injectClearCallingIdentity(); final long token = injectClearCallingIdentity();
try { try {
return mIPackageManager.getActivityInfo(activity, return mIPackageManager.getActivityInfo(activity,
PACKAGE_MATCH_FLAGS | PackageManager.GET_META_DATA, userId); (PACKAGE_MATCH_FLAGS | PackageManager.GET_META_DATA), userId);
} catch (RemoteException e) { } catch (RemoteException e) {
// Shouldn't happen. // Shouldn't happen.
Slog.wtf(TAG, "RemoteException", e); Slog.wtf(TAG, "RemoteException", e);
@@ -2540,18 +2604,20 @@ public class ShortcutService extends IShortcutService.Stub {
} }
} }
@Nullable /**
* Return all installed and enabled packages.
*/
@NonNull
@VisibleForTesting @VisibleForTesting
List<PackageInfo> injectInstalledPackages(@UserIdInt int userId) { final List<PackageInfo> getInstalledPackages(@UserIdInt int userId) {
final long start = injectElapsedRealtime(); final long start = injectElapsedRealtime();
final long token = injectClearCallingIdentity(); final long token = injectClearCallingIdentity();
try { try {
final ParceledListSlice<PackageInfo> parceledList = final List<PackageInfo> all = injectGetPackagesWithUninstalled(userId);
mIPackageManager.getInstalledPackages(PACKAGE_MATCH_FLAGS, userId);
if (parceledList == null) { all.removeIf(PACKAGE_NOT_INSTALLED);
return Collections.emptyList();
} return all;
return parceledList.getList();
} catch (RemoteException e) { } catch (RemoteException e) {
// Shouldn't happen. // Shouldn't happen.
Slog.wtf(TAG, "RemoteException", e); Slog.wtf(TAG, "RemoteException", e);
@@ -2563,17 +2629,31 @@ public class ShortcutService extends IShortcutService.Stub {
} }
} }
/**
* Do not use directly; this returns uninstalled packages too.
*/
@NonNull
@VisibleForTesting
List<PackageInfo> injectGetPackagesWithUninstalled(@UserIdInt int userId)
throws RemoteException {
final ParceledListSlice<PackageInfo> parceledList =
mIPackageManager.getInstalledPackages(PACKAGE_MATCH_FLAGS, userId);
if (parceledList == null) {
return Collections.emptyList();
}
return parceledList.getList();
}
private void forUpdatedPackages(@UserIdInt int userId, long lastScanTime, private void forUpdatedPackages(@UserIdInt int userId, long lastScanTime,
Consumer<ApplicationInfo> callback) { Consumer<ApplicationInfo> callback) {
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, "forUpdatedPackages for user " + userId + ", lastScanTime=" + lastScanTime); Slog.d(TAG, "forUpdatedPackages for user " + userId + ", lastScanTime=" + lastScanTime);
} }
final List<PackageInfo> list = injectInstalledPackages(userId); final List<PackageInfo> list = getInstalledPackages(userId);
for (int i = list.size() - 1; i >= 0; i--) { for (int i = list.size() - 1; i >= 0; i--) {
final PackageInfo pi = list.get(i); final PackageInfo pi = list.get(i);
if (((pi.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) if (pi.lastUpdateTime >= lastScanTime) {
&& (pi.lastUpdateTime >= lastScanTime)) {
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, "Found updated package " + pi.packageName); Slog.d(TAG, "Found updated package " + pi.packageName);
} }
@@ -2582,13 +2662,37 @@ public class ShortcutService extends IShortcutService.Stub {
} }
} }
private boolean isApplicationFlagSet(String packageName, int userId, int flags) { private boolean isApplicationFlagSet(@NonNull String packageName, int userId, int flags) {
final ApplicationInfo ai = injectApplicationInfo(packageName, userId); final ApplicationInfo ai = injectApplicationInfoWithUninstalled(packageName, userId);
return (ai != null) && ((ai.flags & flags) == flags); return (ai != null) && ((ai.flags & flags) == flags);
} }
private static boolean isInstalled(@Nullable ApplicationInfo ai) {
return (ai != null) && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
}
private static boolean isInstalled(@Nullable PackageInfo pi) {
return (pi != null) && isInstalled(pi.applicationInfo);
}
private static boolean isInstalled(@Nullable ActivityInfo ai) {
return (ai != null) && isInstalled(ai.applicationInfo);
}
private static ApplicationInfo isInstalledOrNull(ApplicationInfo ai) {
return isInstalled(ai) ? ai : null;
}
private static PackageInfo isInstalledOrNull(PackageInfo pi) {
return isInstalled(pi) ? pi : null;
}
private static ActivityInfo isInstalledOrNull(ActivityInfo ai) {
return isInstalled(ai) ? ai : null;
}
boolean isPackageInstalled(String packageName, int userId) { boolean isPackageInstalled(String packageName, int userId) {
return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_INSTALLED); return getApplicationInfo(packageName, userId) != null;
} }
@Nullable @Nullable
@@ -2619,20 +2723,46 @@ public class ShortcutService extends IShortcutService.Stub {
return intent; return intent;
} }
/**
* Same as queryIntentActivitiesAsUser, except it makes sure the package is installed,
* and only returns exported activities.
*/
@NonNull
@VisibleForTesting
List<ResolveInfo> queryActivities(@NonNull Intent baseIntent,
@NonNull String packageName, @Nullable ComponentName activity, int userId) {
baseIntent.setPackage(Preconditions.checkNotNull(packageName));
if (activity != null) {
baseIntent.setComponent(activity);
}
final List<ResolveInfo> resolved =
mContext.getPackageManager().queryIntentActivitiesAsUser(
baseIntent, PACKAGE_MATCH_FLAGS, userId);
if (resolved == null || resolved.size() == 0) {
return EMPTY_RESOLVE_INFO;
}
// Make sure the package is installed.
if (!isInstalled(resolved.get(0).activityInfo)) {
return EMPTY_RESOLVE_INFO;
}
resolved.removeIf(ACTIVITY_NOT_EXPORTED);
return resolved;
}
/**
* Return the main activity that is enabled and exported. If multiple activities are found,
* return the first one.
*/
@Nullable @Nullable
ComponentName injectGetDefaultMainActivity(@NonNull String packageName, int userId) { ComponentName injectGetDefaultMainActivity(@NonNull String packageName, int userId) {
final long start = injectElapsedRealtime(); final long start = injectElapsedRealtime();
final long token = injectClearCallingIdentity(); final long token = injectClearCallingIdentity();
try { try {
final Intent intent = getMainActivityIntent();
intent.setPackage(packageName);
final List<ResolveInfo> resolved = final List<ResolveInfo> resolved =
mContext.getPackageManager().queryIntentActivitiesAsUser( queryActivities(getMainActivityIntent(), packageName, null, userId);
intent, PACKAGE_MATCH_FLAGS, userId); return resolved.size() == 0 ? null : resolved.get(0).activityInfo.getComponentName();
return (resolved == null || resolved.size() == 0)
? null : resolved.get(0).activityInfo.getComponentName();
} finally { } finally {
injectRestoreCallingIdentity(token); injectRestoreCallingIdentity(token);
@@ -2640,19 +2770,17 @@ public class ShortcutService extends IShortcutService.Stub {
} }
} }
/**
* Return whether an activity is enabled, exported and main.
*/
boolean injectIsMainActivity(@NonNull ComponentName activity, int userId) { boolean injectIsMainActivity(@NonNull ComponentName activity, int userId) {
final long start = injectElapsedRealtime(); final long start = injectElapsedRealtime();
final long token = injectClearCallingIdentity(); final long token = injectClearCallingIdentity();
try { try {
final Intent intent = getMainActivityIntent();
intent.setPackage(activity.getPackageName());
intent.setComponent(activity);
final List<ResolveInfo> resolved = final List<ResolveInfo> resolved =
mContext.getPackageManager().queryIntentActivitiesAsUser( queryActivities(getMainActivityIntent(), activity.getPackageName(),
intent, PACKAGE_MATCH_FLAGS, userId); activity, userId);
return resolved.size() > 0;
return resolved != null && resolved.size() > 0;
} finally { } finally {
injectRestoreCallingIdentity(token); injectRestoreCallingIdentity(token);
@@ -2660,19 +2788,15 @@ public class ShortcutService extends IShortcutService.Stub {
} }
} }
/**
* Return all the enabled, exported and main activities from a package.
*/
@NonNull @NonNull
List<ResolveInfo> injectGetMainActivities(@NonNull String packageName, int userId) { List<ResolveInfo> injectGetMainActivities(@NonNull String packageName, int userId) {
final long start = injectElapsedRealtime(); final long start = injectElapsedRealtime();
final long token = injectClearCallingIdentity(); final long token = injectClearCallingIdentity();
try { try {
final Intent intent = getMainActivityIntent(); return queryActivities(getMainActivityIntent(), packageName, null, userId);
intent.setPackage(packageName);
final List<ResolveInfo> resolved =
mContext.getPackageManager().queryIntentActivitiesAsUser(
intent, PACKAGE_MATCH_FLAGS, userId);
return (resolved != null) ? resolved : new ArrayList<>(0);
} finally { } finally {
injectRestoreCallingIdentity(token); injectRestoreCallingIdentity(token);
@@ -2680,6 +2804,24 @@ public class ShortcutService extends IShortcutService.Stub {
} }
} }
/**
* Return whether an activity is enabled and exported.
*/
@VisibleForTesting
boolean injectIsActivityEnabledAndExported(
@NonNull ComponentName activity, @UserIdInt int userId) {
final long start = injectElapsedRealtime();
final long token = injectClearCallingIdentity();
try {
return queryActivities(new Intent(), activity.getPackageName(), activity, userId)
.size() > 0;
} finally {
injectRestoreCallingIdentity(token);
logDurationStat(Stats.IS_ACTIVITY_ENABLED, start);
}
}
boolean injectIsSafeModeEnabled() { boolean injectIsSafeModeEnabled() {
final long token = injectClearCallingIdentity(); final long token = injectClearCallingIdentity();
try { try {
@@ -2839,6 +2981,7 @@ public class ShortcutService extends IShortcutService.Stub {
dumpStatLS(pw, p, Stats.RESOURCE_NAME_LOOKUP, "resourceNameLookup"); dumpStatLS(pw, p, Stats.RESOURCE_NAME_LOOKUP, "resourceNameLookup");
dumpStatLS(pw, p, Stats.GET_LAUNCHER_ACTIVITY, "getLauncherActivity"); dumpStatLS(pw, p, Stats.GET_LAUNCHER_ACTIVITY, "getLauncherActivity");
dumpStatLS(pw, p, Stats.CHECK_LAUNCHER_ACTIVITY, "checkLauncherActivity"); dumpStatLS(pw, p, Stats.CHECK_LAUNCHER_ACTIVITY, "checkLauncherActivity");
dumpStatLS(pw, p, Stats.IS_ACTIVITY_ENABLED, "isActivityEnabled");
} }
for (int i = 0; i < mUsers.size(); i++) { for (int i = 0; i < mUsers.size(); i++) {

View File

@@ -108,9 +108,53 @@
<service android:name="com.android.server.job.MockPriorityJobService" <service android:name="com.android.server.job.MockPriorityJobService"
android:permission="android.permission.BIND_JOB_SERVICE" /> android:permission="android.permission.BIND_JOB_SERVICE" />
<activity android:name="com.android.server.pm.ShortcutManagerTest$ShortcutActivity" /> <activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity" />
<activity android:name="com.android.server.pm.ShortcutManagerTest$ShortcutActivity2" /> <activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity2" />
<activity android:name="com.android.server.pm.ShortcutManagerTest$ShortcutActivity3" /> <activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity3" />
<activity android:name="com.android.server.pm.ShortcutTestActivity"
android:enabled="true" android:exported="true" />
<activity-alias android:name="a.ShortcutEnabled"
android:targetActivity="com.android.server.pm.ShortcutTestActivity"
android:enabled="true" android:exported="true">
</activity-alias>
<activity-alias android:name="a.ShortcutDisabled"
android:targetActivity="com.android.server.pm.ShortcutTestActivity"
android:enabled="false" android:exported="true">
<meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcut_5"/>
</activity-alias>
<activity-alias android:name="a.ShortcutUnexported"
android:targetActivity="com.android.server.pm.ShortcutTestActivity"
android:enabled="true" android:exported="false">
<meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcut_5"/>
</activity-alias>
<activity-alias android:name="a.Shortcut1"
android:targetActivity="com.android.server.pm.ShortcutTestActivity"
android:enabled="true" android:exported="true">
<meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcut_1"/>
</activity-alias>
<activity-alias android:name="a.DisabledMain"
android:targetActivity="com.android.server.pm.ShortcutTestActivity"
android:enabled="false" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias android:name="a.UnexportedMain"
android:targetActivity="com.android.server.pm.ShortcutTestActivity"
android:enabled="true" android:exported="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
</application> </application>
<instrumentation <instrumentation

View File

@@ -103,8 +103,6 @@ import java.util.Set;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.BiPredicate; import java.util.function.BiPredicate;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
protected static final String TAG = "ShortcutManagerTest"; protected static final String TAG = "ShortcutManagerTest";
@@ -206,7 +204,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
IUidObserver mUidObserver; IUidObserver mUidObserver;
public ShortcutServiceTestable(ServiceContext context, Looper looper) { public ShortcutServiceTestable(ServiceContext context, Looper looper) {
super(context, looper); super(context, looper, /* onyForPackageManagerApis */ false);
mContext = context; mContext = context;
} }
@@ -301,24 +299,26 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
} }
@Override @Override
PackageInfo injectPackageInfo(String packageName, @UserIdInt int userId, PackageInfo injectPackageInfoWithUninstalled(String packageName, @UserIdInt int userId,
boolean getSignatures) { boolean getSignatures) {
return getInjectedPackageInfo(packageName, userId, getSignatures); return getInjectedPackageInfo(packageName, userId, getSignatures);
} }
@Override @Override
ApplicationInfo injectApplicationInfo(String packageName, @UserIdInt int userId) { ApplicationInfo injectApplicationInfoWithUninstalled(
PackageInfo pi = injectPackageInfo(packageName, userId, /* getSignatures= */ false); String packageName, @UserIdInt int userId) {
PackageInfo pi = injectPackageInfoWithUninstalled(
packageName, userId, /* getSignatures= */ false);
return pi != null ? pi.applicationInfo : null; return pi != null ? pi.applicationInfo : null;
} }
@Override @Override
List<PackageInfo> injectInstalledPackages(@UserIdInt int userId) { List<PackageInfo> injectGetPackagesWithUninstalled(@UserIdInt int userId) {
return getInstalledPackages(userId); return BaseShortcutManagerTest.this.getInstalledPackagesWithUninstalled(userId);
} }
@Override @Override
ActivityInfo injectGetActivityInfoWithMetadata(ComponentName activity, ActivityInfo injectGetActivityInfoWithMetadataWithUninstalled(ComponentName activity,
@UserIdInt int userId) { @UserIdInt int userId) {
final PackageInfo pi = mContext.injectGetActivitiesWithMetadata( final PackageInfo pi = mContext.injectGetActivitiesWithMetadata(
activity.getPackageName(), userId); activity.getPackageName(), userId);
@@ -369,6 +369,11 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
return mMainActivityFetcher.apply(packageName, userId); return mMainActivityFetcher.apply(packageName, userId);
} }
@Override
boolean injectIsActivityEnabledAndExported(ComponentName activity, @UserIdInt int userId) {
return mEnabledActivityChecker.test(activity, userId);
}
@Override @Override
XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) { XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
return mContext.injectXmlMetaData(activityInfo, key); return mContext.injectXmlMetaData(activityInfo, key);
@@ -951,7 +956,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
} }
} }
private List<PackageInfo> getInstalledPackages(int userId) { private List<PackageInfo> getInstalledPackagesWithUninstalled(int userId) {
final ArrayList<PackageInfo> ret = new ArrayList<>(); final ArrayList<PackageInfo> ret = new ArrayList<>();
addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_1, userId, false), ret); addPackageInfo(getInjectedPackageInfo(CALLING_PACKAGE_1, userId, false), ret);
@@ -990,6 +995,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
ai.name = cn.getClassName(); ai.name = cn.getClassName();
ai.metaData = new Bundle(); ai.metaData = new Bundle();
ai.metaData.putInt(ShortcutParser.METADATA_KEY, activities.get(cn)); ai.metaData.putInt(ShortcutParser.METADATA_KEY, activities.get(cn));
ai.applicationInfo = ret.applicationInfo;
list.add(ai); list.add(ai);
} }
ret.activities = list.toArray(new ActivityInfo[list.size()]); ret.activities = list.toArray(new ActivityInfo[list.size()]);
@@ -1462,14 +1468,18 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
return infoList.get(0); return infoList.get(0);
} }
protected Intent genPackageAddIntent(String pakcageName, int userId) { protected Intent genPackageAddIntent(String packageName, int userId) {
installPackage(userId, packageName);
Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED); Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED);
i.setData(Uri.parse("package:" + pakcageName)); i.setData(Uri.parse("package:" + packageName));
i.putExtra(Intent.EXTRA_USER_HANDLE, userId); i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
return i; return i;
} }
protected Intent genPackageDeleteIntent(String pakcageName, int userId) { protected Intent genPackageDeleteIntent(String pakcageName, int userId) {
uninstallPackage(userId, pakcageName);
Intent i = new Intent(Intent.ACTION_PACKAGE_REMOVED); Intent i = new Intent(Intent.ACTION_PACKAGE_REMOVED);
i.setData(Uri.parse("package:" + pakcageName)); i.setData(Uri.parse("package:" + pakcageName));
i.putExtra(Intent.EXTRA_USER_HANDLE, userId); i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
@@ -1477,6 +1487,8 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
} }
protected Intent genPackageUpdateIntent(String pakcageName, int userId) { protected Intent genPackageUpdateIntent(String pakcageName, int userId) {
installPackage(userId, pakcageName);
Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED); Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED);
i.setData(Uri.parse("package:" + pakcageName)); i.setData(Uri.parse("package:" + pakcageName));
i.putExtra(Intent.EXTRA_USER_HANDLE, userId); i.putExtra(Intent.EXTRA_USER_HANDLE, userId);

View File

@@ -55,7 +55,6 @@ import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@@ -86,7 +85,6 @@ import com.android.frameworks.servicestests.R;
import com.android.server.pm.ShortcutService.ConfigConstants; import com.android.server.pm.ShortcutService.ConfigConstants;
import com.android.server.pm.ShortcutService.FileOutputStreamWithPath; import com.android.server.pm.ShortcutService.FileOutputStreamWithPath;
import com.android.server.pm.ShortcutUser.PackageWithUser; import com.android.server.pm.ShortcutUser.PackageWithUser;
import com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.ShortcutListAsserter;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
@@ -94,9 +92,6 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Supplier;
/** /**
* Tests for ShortcutService and ShortcutManager. * Tests for ShortcutService and ShortcutManager.

View File

@@ -24,7 +24,9 @@ import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.PersistableBundle; import android.os.PersistableBundle;
import android.test.suitebuilder.annotation.SmallTest;
@SmallTest
public class ShortcutManagerTest4 extends BaseShortcutManagerTest { public class ShortcutManagerTest4 extends BaseShortcutManagerTest {
private static Bundle sIntentExtras = makeBundle( private static Bundle sIntentExtras = makeBundle(

View File

@@ -0,0 +1,202 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.pm;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set;
import android.app.Activity;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.ShortcutServiceInternal;
import android.content.res.XmlResourceParser;
import android.os.Looper;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.server.LocalServices;
import java.util.List;
import java.util.Set;
/**
* Unit tests for all the IPackageManager related methods in {@link ShortcutService}.
*
* All the tests here actually talks to the real IPackageManager, so we can't test complicated
* cases. Instead we just make sure they all work reasonably without at least crashing.
*/
@SmallTest
public class ShortcutManagerTest5 extends BaseShortcutManagerTest {
private ShortcutService mShortcutService;
private String mMyPackage;
private int mMyUserId;
public static class ShortcutEnabled extends Activity {
}
public static class ShortcutDisabled extends Activity {
}
@Override
protected void setUp() throws Exception {
super.setUp();
LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
mShortcutService = new ShortcutService(getTestContext(), Looper.getMainLooper(),
/* onyForPackageManagerApis */ true);
mMyPackage = getTestContext().getPackageName();
mMyUserId = android.os.Process.myUserHandle().getIdentifier();
}
public void testGetPackageUid() {
assertTrue(mShortcutService.injectGetPackageUid(
mMyPackage, mMyUserId) != 0);
assertEquals(-1, mShortcutService.injectGetPackageUid(
"no.such.package", mMyUserId));
}
public void testGetPackageInfo() {
PackageInfo pi = mShortcutService.getPackageInfo(
mMyPackage, mMyUserId, /*signature*/ false);
assertEquals(mMyPackage, pi.packageName);
assertNull(pi.signatures);
pi = mShortcutService.getPackageInfo(
mMyPackage, mMyUserId, /*signature*/ true);
assertEquals(mMyPackage, pi.packageName);
assertNotNull(pi.signatures);
pi = mShortcutService.getPackageInfo(
"no.such.package", mMyUserId, /*signature*/ true);
assertNull(pi);
}
public void testGetApplicationInfo() {
ApplicationInfo ai = mShortcutService.getApplicationInfo(
mMyPackage, mMyUserId);
assertEquals(mMyPackage, ai.packageName);
ai = mShortcutService.getApplicationInfo(
"no.such.package", mMyUserId);
assertNull(ai);
}
public void testGetActivityInfoWithMetadata() {
// Disabled activity
ActivityInfo ai = mShortcutService.getActivityInfoWithMetadata(
new ComponentName(mMyPackage, "ShortcutDisabled"), mMyUserId);
assertNull(ai);
// Nonexistent
ai = mShortcutService.getActivityInfoWithMetadata(
new ComponentName("no.such.package", "ShortcutDisabled"), mMyUserId);
assertNull(ai);
// Existent, with no metadata.
ai = mShortcutService.getActivityInfoWithMetadata(
new ComponentName(mMyPackage, "a.ShortcutEnabled"), mMyUserId);
assertEquals(mMyPackage, ai.packageName);
assertEquals("a.ShortcutEnabled", ai.name);
assertNull(ai.loadXmlMetaData(getTestContext().getPackageManager(),
"android.app.shortcuts"));
// Existent, with a shortcut metadata.
ai = mShortcutService.getActivityInfoWithMetadata(
new ComponentName(mMyPackage, "a.Shortcut1"), mMyUserId);
assertEquals(mMyPackage, ai.packageName);
assertEquals("a.Shortcut1", ai.name);
XmlResourceParser meta = ai.loadXmlMetaData(getTestContext().getPackageManager(),
"android.app.shortcuts");
assertNotNull(meta);
meta.close();
}
public void testGetInstalledPackages() {
List<PackageInfo> apks = mShortcutService.getInstalledPackages(mMyUserId);
Set<String> expectedPackages = set("com.android.settings", mMyPackage);
for (PackageInfo pi : apks) {
expectedPackages.remove(pi.packageName);
}
assertEquals(set(), expectedPackages);
}
public void testGetDefaultMainActivity() {
ComponentName cn = mShortcutService.injectGetDefaultMainActivity(
"com.android.settings", mMyUserId);
assertEquals(
ComponentName.unflattenFromString("com.android.settings/.Settings"),
cn);
// This package has no main activity.
assertNull(mShortcutService.injectGetDefaultMainActivity(
mMyPackage, mMyUserId));
// Nonexistent.
assertNull(mShortcutService.injectGetDefaultMainActivity(
"no.such.package", mMyUserId));
}
public void testIsMainActivity() {
assertTrue(mShortcutService.injectIsMainActivity(
ComponentName.unflattenFromString("com.android.settings/.Settings"), mMyUserId));
assertFalse(mShortcutService.injectIsMainActivity(
ComponentName.unflattenFromString("com.android.settings/.xxx"), mMyUserId));
assertFalse(mShortcutService.injectIsMainActivity(
ComponentName.unflattenFromString("no.such.package/.xxx"), mMyUserId));
assertFalse(mShortcutService.injectIsMainActivity(
new ComponentName(mMyPackage, "a.DisabledMain"), mMyUserId));
assertFalse(mShortcutService.injectIsMainActivity(
new ComponentName(mMyPackage, "a.UnexportedMain"), mMyUserId));
}
public void testGetMainActivities() {
assertEquals(1, mShortcutService.injectGetMainActivities(
"com.android.settings", mMyUserId).size());
// This APK has no main activities.
assertEquals(0, mShortcutService.injectGetMainActivities(
mMyPackage, mMyUserId).size());
}
public void testIsActivityEnabledAndExported() {
assertTrue(mShortcutService.injectIsActivityEnabledAndExported(
ComponentName.unflattenFromString("com.android.settings/.Settings"), mMyUserId));
assertFalse(mShortcutService.injectIsActivityEnabledAndExported(
ComponentName.unflattenFromString("com.android.settings/.xxx"), mMyUserId));
assertFalse(mShortcutService.injectIsActivityEnabledAndExported(
ComponentName.unflattenFromString("no.such.package/.xxx"), mMyUserId));
assertTrue(mShortcutService.injectIsActivityEnabledAndExported(
new ComponentName(mMyPackage, "com.android.server.pm.ShortcutTestActivity"),
mMyUserId));
assertTrue(mShortcutService.injectIsActivityEnabledAndExported(
new ComponentName(mMyPackage, "a.ShortcutEnabled"), mMyUserId));
assertFalse(mShortcutService.injectIsActivityEnabledAndExported(
new ComponentName(mMyPackage, "a.ShortcutDisabled"), mMyUserId));
assertFalse(mShortcutService.injectIsActivityEnabledAndExported(
new ComponentName(mMyPackage, "a.ShortcutUnexported"), mMyUserId));
}
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.pm;
import android.app.Activity;
public class ShortcutTestActivity extends Activity {
}