Adding quiet mode support for shortcuts
> LauncherApps returns empty list when the user is locked. Not relying on LauncherApps in this case > When the user is locked, removing all dynamic shortcuts > Loading shortcuts from DB when the user is locked > Verifying the shortcuts again when the user is available Bug: 30411561 Change-Id: Ib6eb372c5b009cadb86a8f6e781f3f3cbf787ceb
This commit is contained in:
@@ -117,8 +117,10 @@ import com.android.launcher3.model.WidgetsModel;
|
||||
import com.android.launcher3.pageindicators.PageIndicator;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutManager;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutsContainer;
|
||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.ItemInfoMatcher;
|
||||
import com.android.launcher3.util.MultiHashMap;
|
||||
import com.android.launcher3.util.PackageManagerHelper;
|
||||
import com.android.launcher3.util.TestingUtils;
|
||||
@@ -2655,14 +2657,17 @@ public class Launcher extends Activity
|
||||
final ShortcutInfo shortcut = (ShortcutInfo) tag;
|
||||
|
||||
if (shortcut.isDisabled != 0) {
|
||||
if ((shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_SUSPENDED) != 0
|
||||
|| (shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_QUIET_USER) != 0) {
|
||||
// Launch activity anyway, framework will tell the user why the app is suspended.
|
||||
if ((shortcut.isDisabled &
|
||||
~ShortcutInfo.FLAG_DISABLED_SUSPENDED &
|
||||
~ShortcutInfo.FLAG_DISABLED_QUIET_USER) == 0) {
|
||||
// If the app is only disabled because of the above flags, launch activity anyway.
|
||||
// Framework will tell the user why the app is suspended.
|
||||
} else {
|
||||
int error = R.string.activity_not_available;
|
||||
if ((shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_SAFEMODE) != 0) {
|
||||
error = R.string.safemode_shortcut_error;
|
||||
} else if ((shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_BY_PUBLISHER) != 0) {
|
||||
} else if ((shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_BY_PUBLISHER) != 0 ||
|
||||
(shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_LOCKED_USER) != 0) {
|
||||
error = R.string.shortcut_not_available;
|
||||
}
|
||||
Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
|
||||
@@ -4208,8 +4213,12 @@ public class Launcher extends Activity
|
||||
|
||||
/**
|
||||
* Some shortcuts were updated in the background.
|
||||
*
|
||||
* Implementation of the method from LauncherModel.Callbacks.
|
||||
*
|
||||
* @param updated list of shortcuts which have changed.
|
||||
* @param removed list of shortcuts which were deleted in the background. This can happen when
|
||||
* an app gets removed from the system or some of its components are no longer
|
||||
* available.
|
||||
*/
|
||||
@Override
|
||||
public void bindShortcutsChanged(final ArrayList<ShortcutInfo> updated,
|
||||
@@ -4228,13 +4237,28 @@ public class Launcher extends Activity
|
||||
}
|
||||
|
||||
if (!removed.isEmpty()) {
|
||||
HashSet<ComponentName> removedComponents = new HashSet<ComponentName>();
|
||||
HashSet<ComponentName> removedComponents = new HashSet<>();
|
||||
HashSet<ShortcutKey> removedDeepShortcuts = new HashSet<>();
|
||||
|
||||
for (ShortcutInfo si : removed) {
|
||||
removedComponents.add(si.getTargetComponent());
|
||||
if (si.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
|
||||
removedDeepShortcuts.add(ShortcutKey.fromItemInfo(si));
|
||||
} else {
|
||||
removedComponents.add(si.getTargetComponent());
|
||||
}
|
||||
}
|
||||
|
||||
if (!removedComponents.isEmpty()) {
|
||||
ItemInfoMatcher matcher = ItemInfoMatcher.ofComponents(removedComponents, user);
|
||||
mWorkspace.removeItemsByMatcher(matcher);
|
||||
mDragController.onAppsRemoved(matcher);
|
||||
}
|
||||
|
||||
if (!removedDeepShortcuts.isEmpty()) {
|
||||
ItemInfoMatcher matcher = ItemInfoMatcher.ofShortcutKeys(removedDeepShortcuts);
|
||||
mWorkspace.removeItemsByMatcher(matcher);
|
||||
mDragController.onAppsRemoved(matcher);
|
||||
}
|
||||
mWorkspace.removeItemsByComponentName(removedComponents, user);
|
||||
// Notify the drag controller
|
||||
mDragController.onAppsRemoved(new HashSet<String>(), removedComponents);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4277,14 +4301,16 @@ public class Launcher extends Activity
|
||||
return;
|
||||
}
|
||||
if (!packageNames.isEmpty()) {
|
||||
mWorkspace.removeItemsByPackageName(packageNames, user);
|
||||
ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(packageNames, user);
|
||||
mWorkspace.removeItemsByMatcher(matcher);
|
||||
mDragController.onAppsRemoved(matcher);
|
||||
|
||||
}
|
||||
if (!components.isEmpty()) {
|
||||
mWorkspace.removeItemsByComponentName(components, user);
|
||||
ItemInfoMatcher matcher = ItemInfoMatcher.ofComponents(components, user);
|
||||
mWorkspace.removeItemsByMatcher(matcher);
|
||||
mDragController.onAppsRemoved(matcher);
|
||||
}
|
||||
// Notify the drag controller
|
||||
mDragController.onAppsRemoved(packageNames, components);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -109,10 +109,11 @@ public class LauncherAppState {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_LOCALE_CHANGED);
|
||||
// For handling managed profiles
|
||||
filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED);
|
||||
filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED);
|
||||
filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_AVAILABLE);
|
||||
filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_UNAVAILABLE);
|
||||
filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
|
||||
filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
|
||||
filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
|
||||
filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
|
||||
filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
|
||||
// For extracting colors from the wallpaper
|
||||
if (Utilities.isNycOrAbove()) {
|
||||
// TODO: add a broadcast entry to the manifest for pre-N.
|
||||
|
||||
@@ -322,8 +322,8 @@ public class LauncherModel extends BroadcastReceiver
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (sBgLock) {
|
||||
final ArrayList<ShortcutInfo> updates = new ArrayList<>();
|
||||
final UserHandleCompat user = UserHandleCompat.myUserHandle();
|
||||
ArrayList<ShortcutInfo> updates = new ArrayList<>();
|
||||
UserHandleCompat user = UserHandleCompat.myUserHandle();
|
||||
|
||||
for (ItemInfo info : sBgItemsIdMap) {
|
||||
if (info instanceof ShortcutInfo) {
|
||||
@@ -345,19 +345,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
}
|
||||
}
|
||||
|
||||
if (!updates.isEmpty()) {
|
||||
// Push changes to the callback.
|
||||
Runnable r = new Runnable() {
|
||||
public void run() {
|
||||
Callbacks callbacks = getCallback();
|
||||
if (callbacks != null) {
|
||||
callbacks.bindShortcutsChanged(updates,
|
||||
new ArrayList<ShortcutInfo>(), user);
|
||||
}
|
||||
}
|
||||
};
|
||||
mHandler.post(r);
|
||||
}
|
||||
bindUpdatedShortcuts(updates, user);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -926,12 +914,8 @@ public class LauncherModel extends BroadcastReceiver
|
||||
}
|
||||
}
|
||||
if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
|
||||
ShortcutInfo shortcutInfo = (ShortcutInfo) item;
|
||||
ShortcutKey shortcutToPin = new ShortcutKey(
|
||||
shortcutInfo.intent.getPackage(),
|
||||
shortcutInfo.user,
|
||||
shortcutInfo.getDeepShortcutId());
|
||||
incrementPinnedShortcutCount(shortcutToPin, true /* shouldPin */);
|
||||
incrementPinnedShortcutCount(
|
||||
ShortcutKey.fromItemInfo(item), true /* shouldPin */);
|
||||
}
|
||||
break;
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
|
||||
@@ -1000,12 +984,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
sBgWorkspaceItems.remove(item);
|
||||
break;
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
|
||||
ShortcutInfo shortcutInfo = ((ShortcutInfo) item);
|
||||
ShortcutKey pinnedShortcut = new ShortcutKey(
|
||||
shortcutInfo.intent.getPackage(),
|
||||
shortcutInfo.user,
|
||||
shortcutInfo.getDeepShortcutId());
|
||||
decrementPinnedShortcutCount(pinnedShortcut);
|
||||
decrementPinnedShortcutCount(ShortcutKey.fromItemInfo(item));
|
||||
// Fall through.
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
|
||||
@@ -1215,17 +1194,28 @@ public class LauncherModel extends BroadcastReceiver
|
||||
if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
|
||||
// If we have changed locale we need to clear out the labels in all apps/workspace.
|
||||
forceReload();
|
||||
} else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED.equals(action)
|
||||
|| LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
|
||||
} else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
|
||||
|| Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
|
||||
UserManagerCompat.getInstance(context).enableAndResetCache();
|
||||
forceReload();
|
||||
} else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action) ||
|
||||
LauncherAppsCompat.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
|
||||
} else if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action) ||
|
||||
Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action) ||
|
||||
Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action)) {
|
||||
UserHandleCompat user = UserHandleCompat.fromIntent(intent);
|
||||
if (user != null) {
|
||||
enqueueItemUpdatedTask(new PackageUpdatedTask(
|
||||
PackageUpdatedTask.OP_USER_AVAILABILITY_CHANGE,
|
||||
new String[0], user));
|
||||
if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action) ||
|
||||
Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
|
||||
enqueueItemUpdatedTask(new PackageUpdatedTask(
|
||||
PackageUpdatedTask.OP_USER_AVAILABILITY_CHANGE,
|
||||
new String[0], user));
|
||||
}
|
||||
|
||||
// ACTION_MANAGED_PROFILE_UNAVAILABLE sends the profile back to locked mode, so
|
||||
// we need to run the state change task again.
|
||||
if (Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action) ||
|
||||
Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action)) {
|
||||
enqueueItemUpdatedTask(new UserLockStateChangedTask(user));
|
||||
}
|
||||
}
|
||||
} else if (Intent.ACTION_WALLPAPER_CHANGED.equals(action)) {
|
||||
ExtractionUtils.startColorExtractionServiceIfNecessary(context);
|
||||
@@ -1702,8 +1692,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
|
||||
final int intentIndex = c.getColumnIndexOrThrow
|
||||
(LauncherSettings.Favorites.INTENT);
|
||||
final int titleIndex = c.getColumnIndexOrThrow
|
||||
(LauncherSettings.Favorites.TITLE);
|
||||
final int containerIndex = c.getColumnIndexOrThrow(
|
||||
LauncherSettings.Favorites.CONTAINER);
|
||||
final int itemTypeIndex = c.getColumnIndexOrThrow(
|
||||
@@ -1730,20 +1718,27 @@ public class LauncherModel extends BroadcastReceiver
|
||||
LauncherSettings.Favorites.PROFILE_ID);
|
||||
final int optionsIndex = c.getColumnIndexOrThrow(
|
||||
LauncherSettings.Favorites.OPTIONS);
|
||||
final CursorIconInfo cursorIconInfo = new CursorIconInfo(c);
|
||||
final CursorIconInfo cursorIconInfo = new CursorIconInfo(mContext, c);
|
||||
|
||||
final LongSparseArray<UserHandleCompat> allUsers = new LongSparseArray<>();
|
||||
final LongSparseArray<Boolean> quietMode = new LongSparseArray<>();
|
||||
final LongSparseArray<Boolean> unlockedUsers = new LongSparseArray<>();
|
||||
for (UserHandleCompat user : mUserManager.getUserProfiles()) {
|
||||
long serialNo = mUserManager.getSerialNumberForUser(user);
|
||||
allUsers.put(serialNo, user);
|
||||
quietMode.put(serialNo, mUserManager.isQuietModeEnabled(user));
|
||||
|
||||
List<ShortcutInfoCompat> pinnedShortcuts = mDeepShortcutManager
|
||||
.queryForPinnedShortcuts(null, user);
|
||||
for (ShortcutInfoCompat shortcut : pinnedShortcuts) {
|
||||
shortcutKeyToPinnedShortcuts.put(ShortcutKey.fromInfo(shortcut),
|
||||
shortcut);
|
||||
boolean userUnlocked = mUserManager.isUserUnlocked(user);
|
||||
unlockedUsers.put(serialNo, userUnlocked);
|
||||
|
||||
// We can only query for shortcuts when the user is unlocked.
|
||||
if (userUnlocked) {
|
||||
List<ShortcutInfoCompat> pinnedShortcuts = mDeepShortcutManager
|
||||
.queryForPinnedShortcuts(null, user);
|
||||
for (ShortcutInfoCompat shortcut : pinnedShortcuts) {
|
||||
shortcutKeyToPinnedShortcuts.put(ShortcutKey.fromInfo(shortcut),
|
||||
shortcut);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1907,9 +1902,8 @@ public class LauncherModel extends BroadcastReceiver
|
||||
|
||||
if (itemReplaced) {
|
||||
if (user.equals(UserHandleCompat.myUserHandle())) {
|
||||
info = getAppShortcutInfo(intent, user, context, null,
|
||||
cursorIconInfo.iconIndex, titleIndex,
|
||||
false, useLowResIcon);
|
||||
info = getAppShortcutInfo(intent, user, null,
|
||||
cursorIconInfo, false, useLowResIcon);
|
||||
} else {
|
||||
// Don't replace items for other profiles.
|
||||
itemsToRemove.add(id);
|
||||
@@ -1917,8 +1911,8 @@ public class LauncherModel extends BroadcastReceiver
|
||||
}
|
||||
} else if (restored) {
|
||||
if (user.equals(UserHandleCompat.myUserHandle())) {
|
||||
info = getRestoredItemInfo(c, titleIndex, intent,
|
||||
promiseType, itemType, cursorIconInfo, context);
|
||||
info = getRestoredItemInfo(c, intent,
|
||||
promiseType, itemType, cursorIconInfo);
|
||||
intent = getRestoredItemIntent(c, context, intent);
|
||||
} else {
|
||||
// Don't restore items for other profiles.
|
||||
@@ -1927,46 +1921,34 @@ public class LauncherModel extends BroadcastReceiver
|
||||
}
|
||||
} else if (itemType ==
|
||||
LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
|
||||
info = getAppShortcutInfo(intent, user, context, c,
|
||||
cursorIconInfo.iconIndex, titleIndex,
|
||||
allowMissingTarget, useLowResIcon);
|
||||
info = getAppShortcutInfo(intent, user, c,
|
||||
cursorIconInfo, allowMissingTarget, useLowResIcon);
|
||||
} else if (itemType ==
|
||||
LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
|
||||
String shortcutId = intent.getStringExtra(
|
||||
ShortcutInfoCompat.EXTRA_SHORTCUT_ID);
|
||||
String packageName = intent.getPackage();
|
||||
ShortcutKey key = new ShortcutKey(intent.getPackage(),
|
||||
user, shortcutId);
|
||||
ShortcutInfoCompat pinnedShortcut =
|
||||
shortcutKeyToPinnedShortcuts.get(key);
|
||||
boolean shouldPin = false; // It's already pinned.
|
||||
if (pinnedShortcut == null) {
|
||||
// It shouldn't be possible for a shortcut to be on the
|
||||
// workspace without being pinned, but if one somehow is,
|
||||
// we should pin it now to get back to a good state.
|
||||
Log.w(TAG, "Shortcut was on workspace but wasn't pinned");
|
||||
// Get full details; incrementing the count will pin it.
|
||||
List<ShortcutInfoCompat> fullDetails = mDeepShortcutManager
|
||||
.queryForFullDetails(packageName,
|
||||
Collections.singletonList(shortcutId), user);
|
||||
if (fullDetails == null || fullDetails.isEmpty()) {
|
||||
// There are no details for the shortcut. If this is due
|
||||
// to a SecurityException, keep it in the database so
|
||||
// we can restore the icon when the launcher regains
|
||||
// permission. Otherwise remove the icon from the db.
|
||||
if (!mDeepShortcutManager.wasLastCallSuccess()) {
|
||||
itemsToRemove.add(id);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
pinnedShortcut = fullDetails.get(0);
|
||||
shouldPin = true;
|
||||
|
||||
ShortcutKey key = ShortcutKey.fromIntent(intent, user);
|
||||
if (unlockedUsers.get(serialNumber)) {
|
||||
ShortcutInfoCompat pinnedShortcut =
|
||||
shortcutKeyToPinnedShortcuts.get(key);
|
||||
if (pinnedShortcut == null) {
|
||||
// The shortcut is no longer valid.
|
||||
itemsToRemove.add(id);
|
||||
continue;
|
||||
}
|
||||
info = new ShortcutInfo(pinnedShortcut, context);
|
||||
intent = info.intent;
|
||||
} else {
|
||||
// Create a shortcut info in disabled mode for now.
|
||||
info = new ShortcutInfo();
|
||||
info.user = user;
|
||||
info.itemType = itemType;
|
||||
loadInfoFromCursor(info, c, cursorIconInfo);
|
||||
|
||||
info.isDisabled |= ShortcutInfo.FLAG_DISABLED_LOCKED_USER;
|
||||
}
|
||||
incrementPinnedShortcutCount(key, shouldPin);
|
||||
info = new ShortcutInfo(pinnedShortcut, context);
|
||||
incrementPinnedShortcutCount(key, false /* shouldPin */);
|
||||
} else { // item type == ITEM_TYPE_SHORTCUT
|
||||
info = getShortcutInfo(c, context, titleIndex, cursorIconInfo);
|
||||
info = getShortcutInfo(c, cursorIconInfo);
|
||||
|
||||
// Shortcuts are only available on the primary profile
|
||||
if (PackageManagerHelper.isAppSuspended(manager, targetPackage)) {
|
||||
@@ -2046,7 +2028,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);
|
||||
|
||||
// Do not trim the folder label, as is was set by the user.
|
||||
folderInfo.title = c.getString(titleIndex);
|
||||
folderInfo.title = c.getString(cursorIconInfo.titleIndex);
|
||||
folderInfo.id = id;
|
||||
folderInfo.container = container;
|
||||
folderInfo.screenId = c.getInt(screenIndex);
|
||||
@@ -2800,9 +2782,11 @@ public class LauncherModel extends BroadcastReceiver
|
||||
if (!mDeepShortcutsLoaded) {
|
||||
mBgDeepShortcutMap.clear();
|
||||
for (UserHandleCompat user : mUserManager.getUserProfiles()) {
|
||||
List<ShortcutInfoCompat> shortcuts = mDeepShortcutManager
|
||||
.queryForAllShortcuts(user);
|
||||
updateDeepShortcutMap(null, user, shortcuts);
|
||||
if (mUserManager.isUserUnlocked(user)) {
|
||||
List<ShortcutInfoCompat> shortcuts = mDeepShortcutManager
|
||||
.queryForAllShortcuts(user);
|
||||
updateDeepShortcutMap(null, user, shortcuts);
|
||||
}
|
||||
}
|
||||
synchronized (LoaderTask.this) {
|
||||
if (mStopped) {
|
||||
@@ -2907,18 +2891,23 @@ public class LauncherModel extends BroadcastReceiver
|
||||
}
|
||||
}
|
||||
|
||||
private void bindUpdatedShortcuts(final ArrayList<ShortcutInfo> updatedShortcuts,
|
||||
UserHandleCompat user) {
|
||||
if (!updatedShortcuts.isEmpty()) {
|
||||
private void bindUpdatedShortcuts(
|
||||
ArrayList<ShortcutInfo> updatedShortcuts, UserHandleCompat user) {
|
||||
bindUpdatedShortcuts(updatedShortcuts, new ArrayList<ShortcutInfo>(), user);
|
||||
}
|
||||
|
||||
private void bindUpdatedShortcuts(
|
||||
final ArrayList<ShortcutInfo> updatedShortcuts,
|
||||
final ArrayList<ShortcutInfo> removedShortcuts,
|
||||
final UserHandleCompat user) {
|
||||
if (!updatedShortcuts.isEmpty() || !removedShortcuts.isEmpty()) {
|
||||
final Callbacks callbacks = getCallback();
|
||||
final UserHandleCompat userFinal = user;
|
||||
mHandler.post(new Runnable() {
|
||||
|
||||
public void run() {
|
||||
Callbacks cb = getCallback();
|
||||
if (cb != null && callbacks == cb) {
|
||||
cb.bindShortcutsChanged(updatedShortcuts,
|
||||
new ArrayList<ShortcutInfo>(), userFinal);
|
||||
cb.bindShortcutsChanged(updatedShortcuts, removedShortcuts, user);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -3210,22 +3199,11 @@ public class LauncherModel extends BroadcastReceiver
|
||||
}
|
||||
}
|
||||
|
||||
if (!updatedShortcuts.isEmpty() || !removedShortcuts.isEmpty()) {
|
||||
final Callbacks callbacks = getCallback();
|
||||
mHandler.post(new Runnable() {
|
||||
|
||||
public void run() {
|
||||
Callbacks cb = getCallback();
|
||||
if (callbacks == cb && cb != null) {
|
||||
callbacks.bindShortcutsChanged(
|
||||
updatedShortcuts, removedShortcuts, mUser);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!removedShortcuts.isEmpty()) {
|
||||
deleteItemsFromDatabase(context, removedShortcuts);
|
||||
}
|
||||
bindUpdatedShortcuts(updatedShortcuts, removedShortcuts, mUser);
|
||||
if (!removedShortcuts.isEmpty()) {
|
||||
deleteItemsFromDatabase(context, removedShortcuts);
|
||||
}
|
||||
|
||||
if (!widgets.isEmpty()) {
|
||||
final Callbacks callbacks = getCallback();
|
||||
mHandler.post(new Runnable() {
|
||||
@@ -3387,6 +3365,74 @@ public class LauncherModel extends BroadcastReceiver
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Task to handle changing of lock state of the user
|
||||
*/
|
||||
private class UserLockStateChangedTask implements Runnable {
|
||||
|
||||
private final UserHandleCompat mUser;
|
||||
|
||||
public UserLockStateChangedTask(UserHandleCompat user) {
|
||||
mUser = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
boolean isUserUnlocked = mUserManager.isUserUnlocked(mUser);
|
||||
Context context = mApp.getContext();
|
||||
|
||||
HashMap<ShortcutKey, ShortcutInfoCompat> pinnedShortcuts = new HashMap<>();
|
||||
if (isUserUnlocked) {
|
||||
for (ShortcutInfoCompat shortcut :
|
||||
mDeepShortcutManager.queryForPinnedShortcuts(null, mUser)) {
|
||||
pinnedShortcuts.put(ShortcutKey.fromInfo(shortcut), shortcut);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the workspace to reflect the changes to updated shortcuts residing on it.
|
||||
ArrayList<ShortcutInfo> updatedShortcutInfos = new ArrayList<>();
|
||||
ArrayList<ShortcutInfo> deletedShortcutInfos = new ArrayList<>();
|
||||
for (ItemInfo itemInfo : sBgItemsIdMap) {
|
||||
if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
|
||||
&& mUser.equals(itemInfo.user)) {
|
||||
ShortcutInfo si = (ShortcutInfo) itemInfo;
|
||||
if (isUserUnlocked) {
|
||||
ShortcutInfoCompat shortcut =
|
||||
pinnedShortcuts.get(ShortcutKey.fromItemInfo(si));
|
||||
// We couldn't verify the shortcut during loader. If its no longer available
|
||||
// (probably due to clear data), delete the workspace item as well
|
||||
if (shortcut == null) {
|
||||
deletedShortcutInfos.add(si);
|
||||
continue;
|
||||
}
|
||||
si.isDisabled &= ~ShortcutInfo.FLAG_DISABLED_LOCKED_USER;
|
||||
si.updateFromDeepShortcutInfo(shortcut, context);
|
||||
} else {
|
||||
si.isDisabled |= ShortcutInfo.FLAG_DISABLED_LOCKED_USER;
|
||||
}
|
||||
updatedShortcutInfos.add(si);
|
||||
}
|
||||
}
|
||||
bindUpdatedShortcuts(updatedShortcutInfos, deletedShortcutInfos, mUser);
|
||||
if (!deletedShortcutInfos.isEmpty()) {
|
||||
deleteItemsFromDatabase(context, deletedShortcutInfos);
|
||||
}
|
||||
|
||||
// Remove shortcut id map for that user
|
||||
Iterator<ComponentKey> keysIter = mBgDeepShortcutMap.keySet().iterator();
|
||||
while (keysIter.hasNext()) {
|
||||
if (keysIter.next().user.equals(mUser)) {
|
||||
keysIter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (isUserUnlocked) {
|
||||
updateDeepShortcutMap(null, mUser, mDeepShortcutManager.queryForAllShortcuts(mUser));
|
||||
}
|
||||
bindDeepShortcuts();
|
||||
}
|
||||
}
|
||||
|
||||
private void bindWidgetsModel(final Callbacks callbacks, final WidgetsModel model) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
@@ -3447,12 +3493,12 @@ public class LauncherModel extends BroadcastReceiver
|
||||
* Make an ShortcutInfo object for a restored application or shortcut item that points
|
||||
* to a package that is not yet installed on the system.
|
||||
*/
|
||||
public ShortcutInfo getRestoredItemInfo(Cursor c, int titleIndex, Intent intent,
|
||||
int promiseType, int itemType, CursorIconInfo iconInfo, Context context) {
|
||||
public ShortcutInfo getRestoredItemInfo(Cursor c, Intent intent,
|
||||
int promiseType, int itemType, CursorIconInfo iconInfo) {
|
||||
final ShortcutInfo info = new ShortcutInfo();
|
||||
info.user = UserHandleCompat.myUserHandle();
|
||||
|
||||
Bitmap icon = iconInfo.loadIcon(c, info, context);
|
||||
Bitmap icon = iconInfo.loadIcon(c, info);
|
||||
// the fallback icon
|
||||
if (icon == null) {
|
||||
mIconCache.getTitleAndIcon(info, intent, info.user, false /* useLowResIcon */);
|
||||
@@ -3461,13 +3507,13 @@ public class LauncherModel extends BroadcastReceiver
|
||||
}
|
||||
|
||||
if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) {
|
||||
String title = (c != null) ? c.getString(titleIndex) : null;
|
||||
String title = iconInfo.getTitle(c);
|
||||
if (!TextUtils.isEmpty(title)) {
|
||||
info.title = Utilities.trim(title);
|
||||
}
|
||||
} else if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {
|
||||
if (TextUtils.isEmpty(info.title)) {
|
||||
info.title = (c != null) ? Utilities.trim(c.getString(titleIndex)) : "";
|
||||
info.title = iconInfo.getTitle(c);
|
||||
}
|
||||
} else {
|
||||
throw new InvalidParameterException("Invalid restoreType " + promiseType);
|
||||
@@ -3504,7 +3550,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
* If c is not null, then it will be used to fill in missing data like the title and icon.
|
||||
*/
|
||||
public ShortcutInfo getAppShortcutInfo(Intent intent,
|
||||
UserHandleCompat user, Context context, Cursor c, int iconIndex, int titleIndex,
|
||||
UserHandleCompat user, Cursor c, CursorIconInfo iconInfo,
|
||||
boolean allowMissingTarget, boolean useLowResIcon) {
|
||||
if (user == null) {
|
||||
Log.d(TAG, "Null user found in getShortcutInfo");
|
||||
@@ -3529,7 +3575,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
final ShortcutInfo info = new ShortcutInfo();
|
||||
mIconCache.getTitleAndIcon(info, componentName, lai, user, false, useLowResIcon);
|
||||
if (mIconCache.isDefaultIcon(info.getIcon(mIconCache), user) && c != null) {
|
||||
Bitmap icon = Utilities.createIconBitmap(c, iconIndex, context);
|
||||
Bitmap icon = iconInfo.loadIcon(c);
|
||||
info.setIcon(icon == null ? mIconCache.getDefaultIcon(user) : icon);
|
||||
}
|
||||
|
||||
@@ -3539,7 +3585,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
|
||||
// from the db
|
||||
if (TextUtils.isEmpty(info.title) && c != null) {
|
||||
info.title = Utilities.trim(c.getString(titleIndex));
|
||||
info.title = iconInfo.getTitle(c);
|
||||
}
|
||||
|
||||
// fall back to the class name of the activity
|
||||
@@ -3603,8 +3649,7 @@ public class LauncherModel extends BroadcastReceiver
|
||||
/**
|
||||
* Make an ShortcutInfo object for a shortcut that isn't an application.
|
||||
*/
|
||||
@Thunk ShortcutInfo getShortcutInfo(Cursor c, Context context,
|
||||
int titleIndex, CursorIconInfo iconInfo) {
|
||||
@Thunk ShortcutInfo getShortcutInfo(Cursor c, CursorIconInfo iconInfo) {
|
||||
final ShortcutInfo info = new ShortcutInfo();
|
||||
// Non-app shortcuts are only supported for current user.
|
||||
info.user = UserHandleCompat.myUserHandle();
|
||||
@@ -3612,16 +3657,22 @@ public class LauncherModel extends BroadcastReceiver
|
||||
|
||||
// TODO: If there's an explicit component and we can't install that, delete it.
|
||||
|
||||
info.title = Utilities.trim(c.getString(titleIndex));
|
||||
loadInfoFromCursor(info, c, iconInfo);
|
||||
return info;
|
||||
}
|
||||
|
||||
Bitmap icon = iconInfo.loadIcon(c, info, context);
|
||||
/**
|
||||
* Make an ShortcutInfo object for a shortcut that isn't an application.
|
||||
*/
|
||||
public void loadInfoFromCursor(ShortcutInfo info, Cursor c, CursorIconInfo iconInfo) {
|
||||
info.title = iconInfo.getTitle(c);
|
||||
Bitmap icon = iconInfo.loadIcon(c, info);
|
||||
// the fallback icon
|
||||
if (icon == null) {
|
||||
icon = mIconCache.getDefaultIcon(info.user);
|
||||
info.usingFallbackIcon = true;
|
||||
}
|
||||
info.setIcon(icon);
|
||||
return info;
|
||||
}
|
||||
|
||||
ShortcutInfo infoFromShortcutIntent(Context context, Intent data) {
|
||||
|
||||
@@ -117,12 +117,16 @@ public class ShortcutInfo extends ItemInfo {
|
||||
*/
|
||||
public static final int FLAG_DISABLED_QUIET_USER = 1 << 3;
|
||||
|
||||
|
||||
/**
|
||||
* Indicates that the icon is disabled as the publisher has disabled the actual shortcut.
|
||||
*/
|
||||
public static final int FLAG_DISABLED_BY_PUBLISHER = 1 << 4;
|
||||
|
||||
/**
|
||||
* Indicates that the icon is disabled as the user partition is currently locked.
|
||||
*/
|
||||
public static final int FLAG_DISABLED_LOCKED_USER = 1 << 5;
|
||||
|
||||
/**
|
||||
* Could be disabled, if the the app is installed but unavailable (eg. in safe mode or when
|
||||
* sd-card is not available).
|
||||
@@ -206,7 +210,6 @@ public class ShortcutInfo extends ItemInfo {
|
||||
public ShortcutInfo(ShortcutInfoCompat shortcutInfo, Context context) {
|
||||
user = shortcutInfo.getUserHandle();
|
||||
itemType = LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
|
||||
intent = shortcutInfo.makeIntent(context);
|
||||
flags = 0;
|
||||
updateFromDeepShortcutInfo(shortcutInfo, context);
|
||||
}
|
||||
@@ -291,6 +294,8 @@ public class ShortcutInfo extends ItemInfo {
|
||||
}
|
||||
|
||||
public void updateFromDeepShortcutInfo(ShortcutInfoCompat shortcutInfo, Context context) {
|
||||
// {@link ShortcutInfoCompat#getActivity} can change during an update. Recreate the intent
|
||||
intent = shortcutInfo.makeIntent(context);
|
||||
title = shortcutInfo.getShortLabel();
|
||||
|
||||
CharSequence label = shortcutInfo.getLongLabel();
|
||||
|
||||
@@ -80,6 +80,7 @@ import com.android.launcher3.shortcuts.DeepShortcutManager;
|
||||
import com.android.launcher3.shortcuts.ShortcutsContainerListener;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
|
||||
import com.android.launcher3.util.ItemInfoMatcher;
|
||||
import com.android.launcher3.util.LongArrayMap;
|
||||
import com.android.launcher3.util.MultiStateAlphaController;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
@@ -4023,66 +4024,30 @@ public class Workspace extends PagedView
|
||||
});
|
||||
}
|
||||
|
||||
// Removes ALL items that match a given package name, this is usually called when a package
|
||||
// has been removed and we want to remove all components (widgets, shortcuts, apps) that
|
||||
// belong to that package.
|
||||
void removeItemsByPackageName(final HashSet<String> packageNames, final UserHandleCompat user) {
|
||||
// Filter out all the ItemInfos that this is going to affect
|
||||
final HashSet<ItemInfo> infos = new HashSet<ItemInfo>();
|
||||
final HashSet<ComponentName> cns = new HashSet<ComponentName>();
|
||||
ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();
|
||||
for (CellLayout layoutParent : cellLayouts) {
|
||||
ViewGroup layout = layoutParent.getShortcutsAndWidgets();
|
||||
int childCount = layout.getChildCount();
|
||||
for (int i = 0; i < childCount; ++i) {
|
||||
View view = layout.getChildAt(i);
|
||||
infos.add((ItemInfo) view.getTag());
|
||||
}
|
||||
}
|
||||
LauncherModel.ItemInfoFilter filter = new LauncherModel.ItemInfoFilter() {
|
||||
@Override
|
||||
public boolean filterItem(ItemInfo parent, ItemInfo info,
|
||||
ComponentName cn) {
|
||||
if (packageNames.contains(cn.getPackageName())
|
||||
&& info.user.equals(user)) {
|
||||
cns.add(cn);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
LauncherModel.filterItemInfos(infos, filter);
|
||||
|
||||
// Remove the affected components
|
||||
removeItemsByComponentName(cns, user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes items that match the item info specified. When applications are removed
|
||||
* Removes items that match the {@param matcher}. When applications are removed
|
||||
* as a part of an update, this is called to ensure that other widgets and application
|
||||
* shortcuts are not removed.
|
||||
*/
|
||||
void removeItemsByComponentName(final HashSet<ComponentName> componentNames,
|
||||
final UserHandleCompat user) {
|
||||
public void removeItemsByMatcher(final ItemInfoMatcher matcher) {
|
||||
ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();
|
||||
for (final CellLayout layoutParent: cellLayouts) {
|
||||
final ViewGroup layout = layoutParent.getShortcutsAndWidgets();
|
||||
|
||||
final HashMap<ItemInfo, View> children = new HashMap<ItemInfo, View>();
|
||||
final HashMap<ItemInfo, View> children = new HashMap<>();
|
||||
for (int j = 0; j < layout.getChildCount(); j++) {
|
||||
final View view = layout.getChildAt(j);
|
||||
children.put((ItemInfo) view.getTag(), view);
|
||||
}
|
||||
|
||||
final ArrayList<View> childrenToRemove = new ArrayList<View>();
|
||||
final HashMap<FolderInfo, ArrayList<ShortcutInfo>> folderAppsToRemove =
|
||||
new HashMap<FolderInfo, ArrayList<ShortcutInfo>>();
|
||||
final ArrayList<View> childrenToRemove = new ArrayList<>();
|
||||
final HashMap<FolderInfo, ArrayList<ShortcutInfo>> folderAppsToRemove = new HashMap<>();
|
||||
LauncherModel.ItemInfoFilter filter = new LauncherModel.ItemInfoFilter() {
|
||||
@Override
|
||||
public boolean filterItem(ItemInfo parent, ItemInfo info,
|
||||
ComponentName cn) {
|
||||
ComponentName cn) {
|
||||
if (parent instanceof FolderInfo) {
|
||||
if (componentNames.contains(cn) && info.user.equals(user)) {
|
||||
if (matcher.matches(info, cn)) {
|
||||
FolderInfo folder = (FolderInfo) parent;
|
||||
ArrayList<ShortcutInfo> appsToRemove;
|
||||
if (folderAppsToRemove.containsKey(folder)) {
|
||||
@@ -4095,7 +4060,7 @@ public class Workspace extends PagedView
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (componentNames.contains(cn) && info.user.equals(user)) {
|
||||
if (matcher.matches(info, cn)) {
|
||||
childrenToRemove.add(children.get(info));
|
||||
return true;
|
||||
}
|
||||
@@ -4227,7 +4192,7 @@ public class Workspace extends PagedView
|
||||
HashSet<String> packages = new HashSet<>(1);
|
||||
packages.add(packageName);
|
||||
LauncherModel.deletePackageFromDatabase(mLauncher, packageName, user);
|
||||
removeItemsByPackageName(packages, user);
|
||||
removeItemsByMatcher(ItemInfoMatcher.ofPackages(packages, user));
|
||||
}
|
||||
|
||||
public void updateRestoreItems(final HashSet<ItemInfo> updates) {
|
||||
|
||||
@@ -31,15 +31,6 @@ import java.util.List;
|
||||
|
||||
public abstract class LauncherAppsCompat {
|
||||
|
||||
public static final String ACTION_MANAGED_PROFILE_ADDED =
|
||||
"android.intent.action.MANAGED_PROFILE_ADDED";
|
||||
public static final String ACTION_MANAGED_PROFILE_REMOVED =
|
||||
"android.intent.action.MANAGED_PROFILE_REMOVED";
|
||||
public static final String ACTION_MANAGED_PROFILE_AVAILABLE =
|
||||
"android.intent.action.MANAGED_PROFILE_AVAILABLE";
|
||||
public static final String ACTION_MANAGED_PROFILE_UNAVAILABLE =
|
||||
"android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
|
||||
|
||||
public interface OnAppsChangedCallbackCompat {
|
||||
void onPackageRemoved(String packageName, UserHandleCompat user);
|
||||
void onPackageAdded(String packageName, UserHandleCompat user);
|
||||
|
||||
@@ -57,4 +57,5 @@ public abstract class UserManagerCompat {
|
||||
public abstract CharSequence getBadgedLabelForUser(CharSequence label, UserHandleCompat user);
|
||||
public abstract long getUserCreationTime(UserHandleCompat user);
|
||||
public abstract boolean isQuietModeEnabled(UserHandleCompat user);
|
||||
public abstract boolean isUserUnlocked(UserHandleCompat user);
|
||||
}
|
||||
|
||||
@@ -55,4 +55,9 @@ public class UserManagerCompatV16 extends UserManagerCompat {
|
||||
public boolean isQuietModeEnabled(UserHandleCompat user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserUnlocked(UserHandleCompat user) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,15 +16,11 @@
|
||||
|
||||
package com.android.launcher3.compat;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.util.Log;
|
||||
import android.os.Build;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
//TODO: Once gogole3 SDK is updated to N, add @TargetApi(Build.VERSION_CODES.N)
|
||||
@TargetApi(Build.VERSION_CODES.N)
|
||||
public class UserManagerCompatVN extends UserManagerCompatVL {
|
||||
|
||||
private static final String TAG = "UserManagerCompatVN";
|
||||
@@ -35,21 +31,17 @@ public class UserManagerCompatVN extends UserManagerCompatVL {
|
||||
|
||||
@Override
|
||||
public boolean isQuietModeEnabled(UserHandleCompat user) {
|
||||
if (user != null) {
|
||||
try {
|
||||
//TODO: Replace with proper API call once google3 SDK is updated.
|
||||
Method isQuietModeEnabledMethod = UserManager.class.getMethod("isQuietModeEnabled",
|
||||
UserHandle.class);
|
||||
return (boolean) isQuietModeEnabledMethod.invoke(mUserManager, user.getUser());
|
||||
} catch (NoSuchMethodError | NoSuchMethodException | IllegalAccessException
|
||||
| InvocationTargetException e) {
|
||||
Log.e(TAG, "Running on N without isQuietModeEnabled", e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// TODO remove this when API is fixed to not throw this
|
||||
// when called on user that isn't a managed profile.
|
||||
}
|
||||
return mUserManager.isQuietModeEnabled(user.getUser());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserUnlocked(UserHandleCompat user) {
|
||||
// TODO: Remove the try-catch block when the API permission has been relaxed (b/30475753)
|
||||
try {
|
||||
return mUserManager.isUserUnlocked(user.getUser());
|
||||
} catch (RuntimeException e) {
|
||||
return !isQuietModeEnabled(user);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.Workspace;
|
||||
import com.android.launcher3.accessibility.DragViewStateAnnouncer;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.util.ItemInfoMatcher;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.util.TouchController;
|
||||
|
||||
@@ -325,22 +326,14 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
endDrag();
|
||||
}
|
||||
|
||||
public void onAppsRemoved(final HashSet<String> packageNames, HashSet<ComponentName> cns) {
|
||||
public void onAppsRemoved(ItemInfoMatcher matcher) {
|
||||
// Cancel the current drag if we are removing an app that we are dragging
|
||||
if (mDragObject != null) {
|
||||
Object rawDragInfo = mDragObject.dragInfo;
|
||||
if (rawDragInfo instanceof ShortcutInfo) {
|
||||
ShortcutInfo dragInfo = (ShortcutInfo) rawDragInfo;
|
||||
for (ComponentName componentName : cns) {
|
||||
if (dragInfo.intent != null) {
|
||||
ComponentName cn = dragInfo.intent.getComponent();
|
||||
boolean isSameComponent = cn != null && (cn.equals(componentName) ||
|
||||
packageNames.contains(cn.getPackageName()));
|
||||
if (isSameComponent) {
|
||||
cancelDrag();
|
||||
return;
|
||||
}
|
||||
}
|
||||
ItemInfo dragInfo = mDragObject.dragInfo;
|
||||
if (dragInfo instanceof ShortcutInfo) {
|
||||
ComponentName cn = dragInfo.getTargetComponent();
|
||||
if (cn != null && matcher.matches(dragInfo, cn)) {
|
||||
cancelDrag();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ public class DeepShortcutManager {
|
||||
public void unpinShortcut(final ShortcutKey key) {
|
||||
if (Utilities.isNycMR1OrAbove()) {
|
||||
String packageName = key.componentName.getPackageName();
|
||||
String id = key.id;
|
||||
String id = key.getId();
|
||||
UserHandleCompat user = key.user;
|
||||
List<String> pinnedIds = extractIds(queryForPinnedShortcuts(packageName, user));
|
||||
pinnedIds.remove(id);
|
||||
@@ -120,7 +120,7 @@ public class DeepShortcutManager {
|
||||
public void pinShortcut(final ShortcutKey key) {
|
||||
if (Utilities.isNycMR1OrAbove()) {
|
||||
String packageName = key.componentName.getPackageName();
|
||||
String id = key.id;
|
||||
String id = key.getId();
|
||||
UserHandleCompat user = key.user;
|
||||
List<String> pinnedIds = extractIds(queryForPinnedShortcuts(packageName, user));
|
||||
pinnedIds.add(id);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.android.launcher3.shortcuts;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.compat.UserHandleCompat;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
|
||||
@@ -9,16 +11,28 @@ import com.android.launcher3.util.ComponentKey;
|
||||
* A key that uniquely identifies a shortcut using its package, id, and user handle.
|
||||
*/
|
||||
public class ShortcutKey extends ComponentKey {
|
||||
final String id;
|
||||
|
||||
public ShortcutKey(String packageName, UserHandleCompat user, String id) {
|
||||
// Use the id as the class name.
|
||||
super(new ComponentName(packageName, id), user);
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return componentName.getClassName();
|
||||
}
|
||||
|
||||
public static ShortcutKey fromInfo(ShortcutInfoCompat shortcutInfo) {
|
||||
return new ShortcutKey(shortcutInfo.getPackage(), shortcutInfo.getUserHandle(),
|
||||
shortcutInfo.getId());
|
||||
}
|
||||
|
||||
public static ShortcutKey fromIntent(Intent intent, UserHandleCompat user) {
|
||||
String shortcutId = intent.getStringExtra(
|
||||
ShortcutInfoCompat.EXTRA_SHORTCUT_ID);
|
||||
return new ShortcutKey(intent.getPackage(), user, shortcutId);
|
||||
}
|
||||
|
||||
public static ShortcutKey fromItemInfo(ItemInfo info) {
|
||||
return fromIntent(info.getIntent(), info.user);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,13 +34,24 @@ public class CursorIconInfo {
|
||||
public final int iconResourceIndex;
|
||||
public final int iconIndex;
|
||||
|
||||
public CursorIconInfo(Cursor c) {
|
||||
public final int titleIndex;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
public CursorIconInfo(Context context, Cursor c) {
|
||||
mContext = context;
|
||||
|
||||
iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
|
||||
iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
|
||||
iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
|
||||
|
||||
titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
|
||||
}
|
||||
|
||||
public Bitmap loadIcon(Cursor c, ShortcutInfo info, Context context) {
|
||||
/**
|
||||
* Loads the icon from the cursor and updates the {@param info} if the icon is an app resource.
|
||||
*/
|
||||
public Bitmap loadIcon(Cursor c, ShortcutInfo info) {
|
||||
Bitmap icon = null;
|
||||
String packageName = c.getString(iconPackageIndex);
|
||||
String resourceName = c.getString(iconResourceIndex);
|
||||
@@ -48,12 +59,27 @@ public class CursorIconInfo {
|
||||
info.iconResource = new ShortcutIconResource();
|
||||
info.iconResource.packageName = packageName;
|
||||
info.iconResource.resourceName = resourceName;
|
||||
icon = Utilities.createIconBitmap(packageName, resourceName, context);
|
||||
icon = Utilities.createIconBitmap(packageName, resourceName, mContext);
|
||||
}
|
||||
if (icon == null) {
|
||||
// Failed to load from resource, try loading from DB.
|
||||
icon = Utilities.createIconBitmap(c, iconIndex, context);
|
||||
icon = loadIcon(c);
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the fixed bitmap from the icon if available.
|
||||
*/
|
||||
public Bitmap loadIcon(Cursor c) {
|
||||
return Utilities.createIconBitmap(c, iconIndex, mContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the title or empty string
|
||||
*/
|
||||
public String getTitle(Cursor c) {
|
||||
String title = c.getString(titleIndex);
|
||||
return TextUtils.isEmpty(title) ? "" : Utilities.trim(c.getString(titleIndex));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.launcher3.util;
|
||||
|
||||
import android.content.ComponentName;
|
||||
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.LauncherSettings.Favorites;
|
||||
import com.android.launcher3.compat.UserHandleCompat;
|
||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* A utility class to check for {@link ItemInfo}
|
||||
*/
|
||||
public abstract class ItemInfoMatcher {
|
||||
|
||||
public abstract boolean matches(ItemInfo info, ComponentName cn);
|
||||
|
||||
public static ItemInfoMatcher ofComponents(
|
||||
final HashSet<ComponentName> components, final UserHandleCompat user) {
|
||||
return new ItemInfoMatcher() {
|
||||
@Override
|
||||
public boolean matches(ItemInfo info, ComponentName cn) {
|
||||
return components.contains(cn) && info.user.equals(user);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static ItemInfoMatcher ofPackages(
|
||||
final HashSet<String> packageNames, final UserHandleCompat user) {
|
||||
return new ItemInfoMatcher() {
|
||||
@Override
|
||||
public boolean matches(ItemInfo info, ComponentName cn) {
|
||||
return packageNames.contains(cn.getPackageName()) && info.user.equals(user);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static ItemInfoMatcher ofShortcutKeys(final HashSet<ShortcutKey> keys) {
|
||||
return new ItemInfoMatcher() {
|
||||
@Override
|
||||
public boolean matches(ItemInfo info, ComponentName cn) {
|
||||
return info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT &&
|
||||
keys.contains(ShortcutKey.fromItemInfo(info));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user