Merge "Adding multiuser support to the shelf."
This commit is contained in:
committed by
Android (Google) Code Review
commit
325e2124ab
@@ -21,11 +21,13 @@ import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityOptions;
|
||||
import android.app.AppGlobals;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipDescription;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.IPackageManager;
|
||||
@@ -71,6 +73,7 @@ class NavigationBarApps extends LinearLayout {
|
||||
private static NavigationBarAppsModel sAppsModel;
|
||||
|
||||
private final PackageManager mPackageManager;
|
||||
private final UserManager mUserManager;
|
||||
private final LayoutInflater mLayoutInflater;
|
||||
|
||||
// This view has two roles:
|
||||
@@ -82,13 +85,26 @@ class NavigationBarApps extends LinearLayout {
|
||||
// When the user is not dragging this member is null.
|
||||
private View mDragView;
|
||||
|
||||
private long mCurrentUserSerialNumber = -1;
|
||||
|
||||
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
|
||||
int currentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
|
||||
onUserSwitched(currentUserId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public NavigationBarApps(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
if (sAppsModel == null) {
|
||||
sAppsModel = new NavigationBarAppsModel(context);
|
||||
sAppsModel.initialize(); // Load the saved icons, if any.
|
||||
}
|
||||
mPackageManager = context.getPackageManager();
|
||||
mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
|
||||
mLayoutInflater = LayoutInflater.from(context);
|
||||
|
||||
// Dragging an icon removes and adds back the dragged icon. Use the layout transitions to
|
||||
@@ -108,17 +124,32 @@ class NavigationBarApps extends LinearLayout {
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
// When an icon is dragged out of the pinned area this view's width changes, which causes
|
||||
// the parent container's layout to change and the divider and recents icons to shift left.
|
||||
// Animate the parent's CHANGING transition.
|
||||
ViewGroup parent = (ViewGroup) getParent();
|
||||
LayoutTransition transition = new LayoutTransition();
|
||||
transition.disableTransitionType(LayoutTransition.APPEARING);
|
||||
transition.disableTransitionType(LayoutTransition.DISAPPEARING);
|
||||
transition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
|
||||
transition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
|
||||
transition.enableTransitionType(LayoutTransition.CHANGING);
|
||||
parent.setLayoutTransition(transition);
|
||||
// When an icon is dragged out of the pinned area this view's width changes, which causes
|
||||
// the parent container's layout to change and the divider and recents icons to shift left.
|
||||
// Animate the parent's CHANGING transition.
|
||||
ViewGroup parent = (ViewGroup) getParent();
|
||||
LayoutTransition transition = new LayoutTransition();
|
||||
transition.disableTransitionType(LayoutTransition.APPEARING);
|
||||
transition.disableTransitionType(LayoutTransition.DISAPPEARING);
|
||||
transition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
|
||||
transition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
|
||||
transition.enableTransitionType(LayoutTransition.CHANGING);
|
||||
parent.setLayoutTransition(transition);
|
||||
|
||||
mCurrentUserSerialNumber = mUserManager.getSerialNumberForUser(
|
||||
new UserHandle(ActivityManager.getCurrentUser()));
|
||||
sAppsModel.setCurrentUser(mCurrentUserSerialNumber);
|
||||
recreateAppButtons();
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_USER_SWITCHED);
|
||||
mContext.registerReceiver(mBroadcastReceiver, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
mContext.unregisterReceiver(mBroadcastReceiver);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -433,14 +464,11 @@ class NavigationBarApps extends LinearLayout {
|
||||
AppInfo appInfo = sAppsModel.getApp(indexOfChild(v));
|
||||
ComponentName component = appInfo.getComponentName();
|
||||
|
||||
UserManager userManager =
|
||||
(UserManager) getContext().getSystemService(Context.USER_SERVICE);
|
||||
|
||||
long appUserSerialNumber = appInfo.getUserSerialNumber();
|
||||
|
||||
UserHandle appUser = null;
|
||||
if (appUserSerialNumber != AppInfo.USER_UNSPECIFIED) {
|
||||
appUser = userManager.getUserForSerialNumber(appUserSerialNumber);
|
||||
appUser = mUserManager.getUserForSerialNumber(appUserSerialNumber);
|
||||
}
|
||||
|
||||
int appUserId;
|
||||
@@ -510,4 +538,15 @@ class NavigationBarApps extends LinearLayout {
|
||||
Log.e(TAG, "Attempt to launch activity without category Intent.CATEGORY_LAUNCHER " + component);
|
||||
}
|
||||
}
|
||||
|
||||
private void onUserSwitched(int currentUserId) {
|
||||
final long newUserSerialNumber =
|
||||
mUserManager.getSerialNumberForUser(new UserHandle(currentUserId));
|
||||
|
||||
if (newUserSerialNumber != mCurrentUserSerialNumber) {
|
||||
mCurrentUserSerialNumber = newUserSerialNumber;
|
||||
sAppsModel.setCurrentUser(newUserSerialNumber);
|
||||
recreateAppButtons();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,16 +19,20 @@ package com.android.systemui.statusbar.phone;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.LauncherActivityInfo;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.os.UserHandle;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.UserManager;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Data model and controller for app icons appearing in the navigation bar. The data is stored on
|
||||
@@ -48,7 +52,7 @@ class NavigationBarAppsModel {
|
||||
private final static String VERSION_PREF = "version";
|
||||
|
||||
// Current version number for preferences.
|
||||
private final static int CURRENT_VERSION = 1;
|
||||
private final static int CURRENT_VERSION = 2;
|
||||
|
||||
// Preference name for the number of app icons.
|
||||
private final static String APP_COUNT_PREF = "app_count";
|
||||
@@ -59,42 +63,99 @@ class NavigationBarAppsModel {
|
||||
// User serial number prefix for each app's info. The actual pref has an integer appended to it.
|
||||
private final static String APP_USER_PREFIX = "app_user_";
|
||||
|
||||
private final LauncherApps mLauncherApps;
|
||||
// Character separating current user serial number from the user-specific part of a pref.
|
||||
// Example "22|app_user_2" - when logged as user with serial 22, we'll use this pref for the
|
||||
// user serial of the third app of the logged-in user.
|
||||
private final static char USER_SEPARATOR = '|';
|
||||
|
||||
final Context mContext;
|
||||
private final SharedPreferences mPrefs;
|
||||
|
||||
// Apps are represented as an ordered list of app infos.
|
||||
private final List<AppInfo> mApps = new ArrayList<AppInfo>();
|
||||
|
||||
public NavigationBarAppsModel(Context context) {
|
||||
mLauncherApps = (LauncherApps) context.getSystemService("launcherapps");
|
||||
mPrefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
}
|
||||
// Serial number of the current user.
|
||||
private long mCurrentUserSerialNumber = AppInfo.USER_UNSPECIFIED;
|
||||
|
||||
@VisibleForTesting
|
||||
NavigationBarAppsModel(LauncherApps launcherApps, SharedPreferences prefs) {
|
||||
mLauncherApps = launcherApps;
|
||||
mPrefs = prefs;
|
||||
public NavigationBarAppsModel(Context context) {
|
||||
mContext = context;
|
||||
mPrefs = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
|
||||
int version = mPrefs.getInt(VERSION_PREF, -1);
|
||||
if (version != CURRENT_VERSION) {
|
||||
// Since the data format changed, clean everything.
|
||||
SharedPreferences.Editor edit = mPrefs.edit();
|
||||
edit.clear();
|
||||
edit.putInt(VERSION_PREF, CURRENT_VERSION);
|
||||
edit.apply();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the model with a list of apps, either by loading it off disk or by supplying
|
||||
* a default list.
|
||||
* Reinitializes the model for a new user.
|
||||
*/
|
||||
public void initialize() {
|
||||
if (mApps.size() > 0) {
|
||||
Slog.e(TAG, "Model already initialized");
|
||||
return;
|
||||
}
|
||||
public void setCurrentUser(long userSerialNumber) {
|
||||
mCurrentUserSerialNumber = userSerialNumber;
|
||||
|
||||
// Check for an existing list of apps.
|
||||
int version = mPrefs.getInt(VERSION_PREF, -1);
|
||||
if (version == CURRENT_VERSION) {
|
||||
mApps.clear();
|
||||
|
||||
int appCount = mPrefs.getInt(userPrefixed(APP_COUNT_PREF), -1);
|
||||
if (appCount >= 0) {
|
||||
loadAppsFromPrefs();
|
||||
} else {
|
||||
// We switched to this user for the first time ever. This is a good opportunity to clean
|
||||
// prefs for users deleted in the past.
|
||||
removePrefsForDeletedUsers();
|
||||
|
||||
addDefaultApps();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes prefs for users that don't exist on the device.
|
||||
*/
|
||||
private void removePrefsForDeletedUsers() {
|
||||
UserManager userManager =
|
||||
(UserManager) mContext.getSystemService(Context.USER_SERVICE);
|
||||
|
||||
// Build a set of string representations of serial numbers of the device users.
|
||||
final List<UserInfo> users = userManager.getUsers();
|
||||
final int userCount = users.size();
|
||||
|
||||
final Set<String> userSerials = new HashSet<String> ();
|
||||
|
||||
for (int i = 0; i < userCount; ++i) {
|
||||
userSerials.add(Long.toString(users.get(i).serialNumber));
|
||||
}
|
||||
|
||||
// Walk though all prefs and delete ones which user is not in the string set.
|
||||
final Map<String, ?> allPrefs = mPrefs.getAll();
|
||||
final SharedPreferences.Editor edit = mPrefs.edit();
|
||||
|
||||
for (Map.Entry<String, ?> pref : allPrefs.entrySet()) {
|
||||
final String key = pref.getKey();
|
||||
if (key.equals(VERSION_PREF)) continue;
|
||||
|
||||
final int userSeparatorPos = key.indexOf(USER_SEPARATOR);
|
||||
|
||||
if (userSeparatorPos < 0) {
|
||||
// Removing anomalous pref with no user.
|
||||
edit.remove(key);
|
||||
continue;
|
||||
}
|
||||
|
||||
final String prefUserSerial = key.substring(0, userSeparatorPos);
|
||||
|
||||
if (!userSerials.contains(prefUserSerial)) {
|
||||
// Removes pref for a not existing user.
|
||||
edit.remove(key);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
edit.apply();
|
||||
}
|
||||
|
||||
/** Returns the number of apps. */
|
||||
public int getAppCount() {
|
||||
return mApps.size();
|
||||
@@ -123,11 +184,8 @@ class NavigationBarAppsModel {
|
||||
/** Saves the current model to disk. */
|
||||
public void savePrefs() {
|
||||
SharedPreferences.Editor edit = mPrefs.edit();
|
||||
// The user might have removed icons, so clear all the old prefs.
|
||||
edit.clear();
|
||||
edit.putInt(VERSION_PREF, CURRENT_VERSION);
|
||||
int appCount = mApps.size();
|
||||
edit.putInt(APP_COUNT_PREF, appCount);
|
||||
edit.putInt(userPrefixed(APP_COUNT_PREF), appCount);
|
||||
for (int i = 0; i < appCount; i++) {
|
||||
final AppInfo appInfo = mApps.get(i);
|
||||
String componentNameString = appInfo.getComponentName().flattenToString();
|
||||
@@ -140,7 +198,7 @@ class NavigationBarAppsModel {
|
||||
|
||||
/** Loads the list of apps from SharedPreferences. */
|
||||
private void loadAppsFromPrefs() {
|
||||
int appCount = mPrefs.getInt(APP_COUNT_PREF, -1);
|
||||
int appCount = mPrefs.getInt(userPrefixed(APP_COUNT_PREF), -1);
|
||||
for (int i = 0; i < appCount; i++) {
|
||||
String prefValue = mPrefs.getString(prefNameForApp(i), null);
|
||||
if (prefValue == null) {
|
||||
@@ -154,27 +212,48 @@ class NavigationBarAppsModel {
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected int getCurrentUser() {
|
||||
return ActivityManager.getCurrentUser();
|
||||
}
|
||||
|
||||
/** Adds the first few apps from the owner profile. Used for demo purposes. */
|
||||
private void addDefaultApps() {
|
||||
// Get a list of all app activities.
|
||||
List<LauncherActivityInfo> apps =
|
||||
mLauncherApps.getActivityList(
|
||||
null /* packageName */, new UserHandle(ActivityManager.getCurrentUser()));
|
||||
int appCount = apps.size();
|
||||
final Intent queryIntent = new Intent(Intent.ACTION_MAIN, null);
|
||||
queryIntent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
final int currentUser = getCurrentUser();
|
||||
|
||||
final List<ResolveInfo> apps = mContext.getPackageManager().queryIntentActivitiesAsUser(
|
||||
queryIntent, 0 /* flags */, currentUser);
|
||||
final int appCount = apps.size();
|
||||
for (int i = 0; i < NUM_INITIAL_APPS && i < appCount; i++) {
|
||||
LauncherActivityInfo activityInfo = apps.get(i);
|
||||
mApps.add(new AppInfo(activityInfo.getComponentName(), AppInfo.USER_UNSPECIFIED));
|
||||
ResolveInfo ri = apps.get(i);
|
||||
ComponentName componentName = new ComponentName(
|
||||
ri.activityInfo.packageName, ri.activityInfo.name);
|
||||
mApps.add(new AppInfo(componentName, AppInfo.USER_UNSPECIFIED));
|
||||
}
|
||||
|
||||
savePrefs();
|
||||
}
|
||||
|
||||
/** Returns a pref prefixed with the serial number of the current user. */
|
||||
private String userPrefixed(String pref) {
|
||||
if (mCurrentUserSerialNumber == AppInfo.USER_UNSPECIFIED) {
|
||||
throw new RuntimeException("Current user is not yet set");
|
||||
}
|
||||
|
||||
return Long.toString(mCurrentUserSerialNumber) + USER_SEPARATOR + pref;
|
||||
}
|
||||
|
||||
/** Returns the pref name for the app at a given index. */
|
||||
private static String prefNameForApp(int index) {
|
||||
return APP_PREF_PREFIX + Integer.toString(index);
|
||||
private String prefNameForApp(int index) {
|
||||
return userPrefixed(APP_PREF_PREFIX + Integer.toString(index));
|
||||
}
|
||||
|
||||
/** Returns the pref name for the app's user at a given index. */
|
||||
private static String prefUserForApp(int index) {
|
||||
return APP_USER_PREFIX + Integer.toString(index);
|
||||
private String prefUserForApp(int index) {
|
||||
return userPrefixed(APP_USER_PREFIX + Integer.toString(index));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,24 +18,35 @@ package com.android.systemui.statusbar.phone;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.LauncherActivityInfo;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.os.UserHandle;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.UserManager;
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/** Tests for the data model for the navigation bar app icons. */
|
||||
public class NavigationBarAppsModelTest extends AndroidTestCase {
|
||||
private LauncherApps mMockLauncherApps;
|
||||
private PackageManager mMockPackageManager;
|
||||
private SharedPreferences mMockPrefs;
|
||||
private SharedPreferences.Editor mMockEdit;
|
||||
private UserManager mMockUserManager;
|
||||
|
||||
private NavigationBarAppsModel mModel;
|
||||
|
||||
@@ -47,26 +58,44 @@ public class NavigationBarAppsModelTest extends AndroidTestCase {
|
||||
System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
|
||||
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
|
||||
|
||||
mMockLauncherApps = mock(LauncherApps.class);
|
||||
final Context context = mock(Context.class);
|
||||
mMockPackageManager = mock(PackageManager.class);
|
||||
mMockPrefs = mock(SharedPreferences.class);
|
||||
mModel = new NavigationBarAppsModel(mMockLauncherApps, mMockPrefs);
|
||||
mMockEdit = mock(SharedPreferences.Editor.class);
|
||||
mMockUserManager = mock(UserManager.class);
|
||||
|
||||
when (context.getSharedPreferences(
|
||||
"com.android.systemui.navbarapps", Context.MODE_PRIVATE)).thenReturn(mMockPrefs);
|
||||
when(context.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
|
||||
when(context.getPackageManager()).thenReturn(mMockPackageManager);
|
||||
|
||||
setContext(context);
|
||||
|
||||
when(mMockUserManager.getUsers()).thenReturn(new ArrayList<UserInfo>());
|
||||
// Assume the version pref is present and equal to the current version.
|
||||
when(mMockPrefs.getInt("version", -1)).thenReturn(2);
|
||||
when(mMockPrefs.edit()).thenReturn(mMockEdit);
|
||||
|
||||
mModel = new NavigationBarAppsModel(context) {
|
||||
@Override
|
||||
protected int getCurrentUser() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Initializes the model from SharedPreferences for a few app activites. */
|
||||
private void initializeModelFromPrefs() {
|
||||
// Assume the version pref is present.
|
||||
when(mMockPrefs.getInt("version", -1)).thenReturn(1);
|
||||
|
||||
// Assume several apps are stored.
|
||||
when(mMockPrefs.getInt("app_count", -1)).thenReturn(3);
|
||||
when(mMockPrefs.getString("app_0", null)).thenReturn("package0/class0");
|
||||
when(mMockPrefs.getLong("app_user_0", -1)).thenReturn(-1L);
|
||||
when(mMockPrefs.getString("app_1", null)).thenReturn("package1/class1");
|
||||
when(mMockPrefs.getLong("app_user_1", -1)).thenReturn(45L);
|
||||
when(mMockPrefs.getString("app_2", null)).thenReturn("package2/class2");
|
||||
when(mMockPrefs.getLong("app_user_2", -1)).thenReturn(239L);
|
||||
when(mMockPrefs.getInt("22|app_count", -1)).thenReturn(3);
|
||||
when(mMockPrefs.getString("22|app_0", null)).thenReturn("package0/class0");
|
||||
when(mMockPrefs.getLong("22|app_user_0", -1)).thenReturn(-1L);
|
||||
when(mMockPrefs.getString("22|app_1", null)).thenReturn("package1/class1");
|
||||
when(mMockPrefs.getLong("22|app_user_1", -1)).thenReturn(45L);
|
||||
when(mMockPrefs.getString("22|app_2", null)).thenReturn("package2/class2");
|
||||
when(mMockPrefs.getLong("22|app_user_2", -1)).thenReturn(239L);
|
||||
|
||||
mModel.initialize();
|
||||
mModel.setCurrentUser(22L);
|
||||
}
|
||||
|
||||
/** Tests initializing the model from SharedPreferences. */
|
||||
@@ -83,22 +112,26 @@ public class NavigationBarAppsModelTest extends AndroidTestCase {
|
||||
|
||||
/** Tests initializing the model when the SharedPreferences aren't available. */
|
||||
public void testInitializeDefaultApps() {
|
||||
// Assume the version pref isn't available.
|
||||
when(mMockPrefs.getInt("version", -1)).thenReturn(-1);
|
||||
// Assume the user's app count pref isn't available.
|
||||
when(mMockPrefs.getInt("0|app_count", -1)).thenReturn(-1);
|
||||
|
||||
// Assume some installed activities.
|
||||
LauncherActivityInfo activity1 = mock(LauncherActivityInfo.class);
|
||||
when(activity1.getComponentName()).thenReturn(new ComponentName("package1", "class1"));
|
||||
LauncherActivityInfo activity2 = mock(LauncherActivityInfo.class);
|
||||
when(activity2.getComponentName()).thenReturn(new ComponentName("package2", "class2"));
|
||||
List<LauncherActivityInfo> apps = new ArrayList<LauncherActivityInfo>();
|
||||
apps.add(activity1);
|
||||
apps.add(activity2);
|
||||
when(mMockLauncherApps.getActivityList(anyString(), any(UserHandle.class)))
|
||||
.thenReturn(apps);
|
||||
ActivityInfo ai1 = new ActivityInfo();
|
||||
ai1.packageName = "package1";
|
||||
ai1.name = "class1";
|
||||
ActivityInfo ai2 = new ActivityInfo();
|
||||
ai2.packageName = "package2";
|
||||
ai2.name = "class2";
|
||||
ResolveInfo ri1 = new ResolveInfo();
|
||||
ri1.activityInfo = ai1;
|
||||
ResolveInfo ri2 = new ResolveInfo();
|
||||
ri2.activityInfo = ai2;
|
||||
when(mMockPackageManager
|
||||
.queryIntentActivitiesAsUser(any(Intent.class), eq(0), eq(0)))
|
||||
.thenReturn(Arrays.asList(ri1, ri2));
|
||||
|
||||
// Initializing the model should load the installed activities.
|
||||
mModel.initialize();
|
||||
// Setting the user should load the installed activities.
|
||||
mModel.setCurrentUser(0L);
|
||||
assertEquals(2, mModel.getAppCount());
|
||||
assertEquals("package1/class1", mModel.getApp(0).getComponentName().flattenToString());
|
||||
assertEquals(-1L, mModel.getApp(0).getUserSerialNumber());
|
||||
@@ -108,19 +141,16 @@ public class NavigationBarAppsModelTest extends AndroidTestCase {
|
||||
|
||||
/** Tests initializing the model if one of the prefs is missing. */
|
||||
public void testInitializeWithMissingPref() {
|
||||
// Assume the version pref is present.
|
||||
when(mMockPrefs.getInt("version", -1)).thenReturn(1);
|
||||
|
||||
// Assume two apps are nominally stored.
|
||||
when(mMockPrefs.getInt("app_count", -1)).thenReturn(2);
|
||||
when(mMockPrefs.getString("app_0", null)).thenReturn("package0/class0");
|
||||
when(mMockPrefs.getLong("app_user_0", -1)).thenReturn(239L);
|
||||
when(mMockPrefs.getInt("22|app_count", -1)).thenReturn(2);
|
||||
when(mMockPrefs.getString("22|app_0", null)).thenReturn("package0/class0");
|
||||
when(mMockPrefs.getLong("22|app_user_0", -1)).thenReturn(239L);
|
||||
|
||||
// But assume one pref is missing.
|
||||
when(mMockPrefs.getString("app_1", null)).thenReturn(null);
|
||||
when(mMockPrefs.getString("22|app_1", null)).thenReturn(null);
|
||||
|
||||
// Initializing the model should load from prefs and skip the missing one.
|
||||
mModel.initialize();
|
||||
mModel.setCurrentUser(22L);
|
||||
assertEquals(1, mModel.getAppCount());
|
||||
assertEquals("package0/class0", mModel.getApp(0).getComponentName().flattenToString());
|
||||
assertEquals(239L, mModel.getApp(0).getUserSerialNumber());
|
||||
@@ -130,15 +160,64 @@ public class NavigationBarAppsModelTest extends AndroidTestCase {
|
||||
public void testSavePrefs() {
|
||||
initializeModelFromPrefs();
|
||||
|
||||
SharedPreferences.Editor mockEdit = mock(SharedPreferences.Editor.class);
|
||||
when(mMockPrefs.edit()).thenReturn(mockEdit);
|
||||
|
||||
mModel.savePrefs();
|
||||
verify(mockEdit).clear(); // Old prefs were removed.
|
||||
verify(mockEdit).putInt("version", 1);
|
||||
verify(mockEdit).putInt("app_count", 3);
|
||||
verify(mockEdit).putString("app_0", "package0/class0");
|
||||
verify(mockEdit).putString("app_1", "package1/class1");
|
||||
verify(mockEdit).putString("app_2", "package2/class2");
|
||||
verify(mMockEdit).putInt("22|app_count", 3);
|
||||
verify(mMockEdit).putString("22|app_0", "package0/class0");
|
||||
verify(mMockEdit).putLong("22|app_user_0", -1L);
|
||||
verify(mMockEdit).putString("22|app_1", "package1/class1");
|
||||
verify(mMockEdit).putLong("22|app_user_1", 45L);
|
||||
verify(mMockEdit).putString("22|app_2", "package2/class2");
|
||||
verify(mMockEdit).putLong("22|app_user_2", 239L);
|
||||
verify(mMockEdit).apply();
|
||||
verifyNoMoreInteractions(mMockEdit);
|
||||
}
|
||||
|
||||
/** Tests cleaning all prefs on a version change. */
|
||||
public void testVersionChange() {
|
||||
// Assume the version pref changed.
|
||||
when(mMockPrefs.getInt("version", -1)).thenReturn(1);
|
||||
|
||||
new NavigationBarAppsModel(getContext());
|
||||
verify(mMockEdit).clear();
|
||||
verify(mMockEdit).putInt("version", 2);
|
||||
verify(mMockEdit).apply();
|
||||
verifyNoMoreInteractions(mMockEdit);
|
||||
}
|
||||
|
||||
/** Tests cleaning prefs for deleted users. */
|
||||
public void testCleaningDeletedUsers() {
|
||||
// Users on the device.
|
||||
final UserInfo user1 = new UserInfo(11, "", 0);
|
||||
user1.serialNumber = 1111;
|
||||
final UserInfo user2 = new UserInfo(13, "", 0);
|
||||
user2.serialNumber = 1313;
|
||||
|
||||
when(mMockUserManager.getUsers()).thenReturn(Arrays.asList(user1, user2));
|
||||
|
||||
when(mMockPrefs.edit()).
|
||||
thenReturn(mMockEdit).
|
||||
thenReturn(mock(SharedPreferences.Editor.class));
|
||||
|
||||
// Assume the user's app count pref isn't available. This will trigger clearing deleted
|
||||
// users' prefs.
|
||||
when(mMockPrefs.getInt("0|app_count", -1)).thenReturn(-1);
|
||||
|
||||
final Map allPrefs = new HashMap<String, Object>();
|
||||
allPrefs.put("version", null);
|
||||
allPrefs.put("some_strange_pref", null);
|
||||
allPrefs.put("", null);
|
||||
allPrefs.put("|", null);
|
||||
allPrefs.put("1313|app_count", null);
|
||||
allPrefs.put("1212|app_count", null);
|
||||
when(mMockPrefs.getAll()).thenReturn(allPrefs);
|
||||
|
||||
// Setting the user should remove prefs for deleted users.
|
||||
mModel.setCurrentUser(0L);
|
||||
verify(mMockEdit).remove("some_strange_pref");
|
||||
verify(mMockEdit).remove("");
|
||||
verify(mMockEdit).remove("|");
|
||||
verify(mMockEdit).remove("1212|app_count");
|
||||
verify(mMockEdit).apply();
|
||||
verifyNoMoreInteractions(mMockEdit);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user