Merge "Allow user to place PendingAddShortcutInfo in opened Folder." into ub-launcher3-dorval-polish
diff --git a/res/layout/all_apps_discovery_item.xml b/res/layout/all_apps_discovery_item.xml
index 3350530..fb1755c 100644
--- a/res/layout/all_apps_discovery_item.xml
+++ b/res/layout/all_apps_discovery_item.xml
@@ -25,7 +25,9 @@
android:layout_width="56dp"
android:layout_height="56dp"
android:padding="8dp"
- android:scaleType="fitCenter"/>
+ android:scaleType="fitCenter"
+ android:focusable="false"
+ android:importantForAccessibility="no"/>
<LinearLayout
android:layout_width="match_parent"
diff --git a/res/layout/system_shortcut.xml b/res/layout/system_shortcut.xml
index 0952703..6f702f6 100644
--- a/res/layout/system_shortcut.xml
+++ b/res/layout/system_shortcut.xml
@@ -33,7 +33,8 @@
android:textColor="?android:attr/textColorPrimary"
android:fontFamily="sans-serif"
launcher:iconDisplay="shortcut_popup"
- launcher:layoutHorizontal="true" />
+ launcher:layoutHorizontal="true"
+ android:focusable="false" />
<View
android:id="@+id/icon"
diff --git a/res/values/config.xml b/res/values/config.xml
index ace1d7e..8f2590a 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -138,4 +138,5 @@
<item type="id" name="action_move_screen_forwards" />
<item type="id" name="action_resize" />
<item type="id" name="action_deep_shortcuts" />
+ <item type="id" name="action_dismiss_notification" />
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f7c4825..3648e15 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -159,7 +159,7 @@
<!-- Text for wallpaper change button -->
<string name="wallpaper_button_text">Wallpapers</string>
<!-- Text for settings button -->
- <string name="settings_button_text">Settings</string>
+ <string name="settings_button_text">Home settings</string>
<!-- Message shown when a feature is disabled by the administrator -->
<string name="msg_disabled_by_admin">Disabled by your admin</string>
<!-- Text for custom accessibility action to go to the overview mode, where users can look and change the overall UI of the launcher. -->
@@ -292,5 +292,13 @@
<!-- Accessibility description for the shortcuts menu shown for an app. -->
<string name="shortcuts_menu_description"><xliff:g id="number_of_shortcuts" example="3">%1$d</xliff:g> shortcuts for <xliff:g id="app_name" example="Messenger">%2$s</xliff:g></string>
+ <!-- Accessibility description when the shortcuts menu has notifications as well as shortcuts. -->
+ <string name="shortcuts_menu_with_notifications_description"><xliff:g id="number_of_shortcuts" example="3">%1$d</xliff:g> shortcuts and <xliff:g id="number_of_notifications" example="3">%2$d</xliff:g> notifications for <xliff:g id="app_name" example="Messenger">%3$s</xliff:g></string>
+
+ <!-- Accessibility action to dismiss a notification in the shortcuts menu for an icon. [CHAR_LIMIT=30] -->
+ <string name="action_dismiss_notification">Dismiss</string>
+
+ <!-- Accessibility confirmation for notification being dismissed. -->
+ <string name="notification_dismissed">Notification dismissed</string>
</resources>
diff --git a/src/com/android/launcher3/AllAppsList.java b/src/com/android/launcher3/AllAppsList.java
index d7f0180..f3202be 100644
--- a/src/com/android/launcher3/AllAppsList.java
+++ b/src/com/android/launcher3/AllAppsList.java
@@ -42,15 +42,13 @@
public static final int DEFAULT_APPLICATIONS_NUMBER = 42;
/** The list off all apps. */
- public ArrayList<AppInfo> data =
- new ArrayList<AppInfo>(DEFAULT_APPLICATIONS_NUMBER);
+ public final ArrayList<AppInfo> data = new ArrayList<>(DEFAULT_APPLICATIONS_NUMBER);
/** The list of apps that have been added since the last notify() call. */
- public ArrayList<AppInfo> added =
- new ArrayList<AppInfo>(DEFAULT_APPLICATIONS_NUMBER);
+ public ArrayList<AppInfo> added = new ArrayList<>(DEFAULT_APPLICATIONS_NUMBER);
/** The list of apps that have been removed since the last notify() call. */
- public ArrayList<AppInfo> removed = new ArrayList<AppInfo>();
+ public ArrayList<AppInfo> removed = new ArrayList<>();
/** The list of apps that have been modified since the last notify() call. */
- public ArrayList<AppInfo> modified = new ArrayList<AppInfo>();
+ public ArrayList<AppInfo> modified = new ArrayList<>();
private IconCache mIconCache;
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 251f9d8..e49ead0 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -674,14 +674,6 @@
}
}
- /**
- * Returns true if the view can show custom shortcuts.
- */
- public boolean hasDeepShortcuts() {
- return !mLauncher.getPopupDataProvider().getShortcutIdsForItem((ItemInfo) getTag())
- .isEmpty();
- }
-
public int getIconSize() {
return mIconSize;
}
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index ce85570..b136e7d 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -34,6 +34,7 @@
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
+import android.util.Pair;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserManagerCompat;
@@ -59,6 +60,16 @@
import java.util.Set;
public class InstallShortcutReceiver extends BroadcastReceiver {
+
+ public static final int FLAG_ACTIVITY_PAUSED = 1;
+ public static final int FLAG_LOADER_RUNNING = 2;
+ public static final int FLAG_DRAG_AND_DROP = 4;
+ public static final int FLAG_BULK_ADD = 4;
+
+ // Determines whether to defer installing shortcuts immediately until
+ // processAllPendingInstalls() is called.
+ private static int sInstallQueueDisabledFlags = 0;
+
private static final String TAG = "InstallShortcutReceiver";
private static final boolean DBG = false;
@@ -151,10 +162,6 @@
}
}
- // Determines whether to defer installing shortcuts immediately until
- // processAllPendingInstalls() is called.
- private static boolean mUseInstallQueue = false;
-
public void onReceive(Context context, Intent data) {
if (!ACTION_INSTALL_SHORTCUT.equals(data.getAction())) {
return;
@@ -207,7 +214,7 @@
public static ShortcutInfo fromShortcutIntent(Context context, Intent data) {
PendingInstallShortcutInfo info = createPendingInfo(context, data);
- return info == null ? null : (ShortcutInfo) info.getItemInfo();
+ return info == null ? null : (ShortcutInfo) info.getItemInfo().first;
}
public static void queueShortcut(ShortcutInfoCompat info, Context context) {
@@ -245,27 +252,28 @@
private static void queuePendingShortcutInfo(PendingInstallShortcutInfo info, Context context) {
// Queue the item up for adding if launcher has not loaded properly yet
- LauncherAppState app = LauncherAppState.getInstance(context);
- boolean launcherNotLoaded = app.getModel().getCallback() == null;
-
addToInstallQueue(Utilities.getPrefs(context), info);
- if (!mUseInstallQueue && !launcherNotLoaded) {
- flushInstallQueue(context);
- }
+ flushInstallQueue(context);
}
- static void enableInstallQueue() {
- mUseInstallQueue = true;
+ public static void enableInstallQueue(int flag) {
+ sInstallQueueDisabledFlags |= flag;
}
- static void disableAndFlushInstallQueue(Context context) {
- mUseInstallQueue = false;
+ public static void disableAndFlushInstallQueue(int flag, Context context) {
+ sInstallQueueDisabledFlags &= ~flag;
flushInstallQueue(context);
}
static void flushInstallQueue(Context context) {
+ LauncherModel model = LauncherAppState.getInstance(context).getModel();
+ boolean launcherNotLoaded = model.getCallback() == null;
+ if (sInstallQueueDisabledFlags != 0 || launcherNotLoaded) {
+ return;
+ }
+
ArrayList<PendingInstallShortcutInfo> items = getAndClearInstallQueue(context);
if (!items.isEmpty()) {
- LauncherAppState.getInstance(context).getModel().addAndBindAddedWorkspaceItems(
+ model.addAndBindAddedWorkspaceItems(
new LazyShortcutsProvider(context.getApplicationContext(), items));
}
}
@@ -439,7 +447,7 @@
}
}
- public ItemInfo getItemInfo() {
+ public Pair<ItemInfo, Object> getItemInfo() {
if (activityInfo != null) {
AppInfo appInfo = new AppInfo(mContext, activityInfo, user);
final LauncherAppState app = LauncherAppState.getInstance(mContext);
@@ -459,11 +467,11 @@
}
});
}
- return si;
+ return Pair.create((ItemInfo) si, (Object) activityInfo);
} else if (shortcutInfo != null) {
ShortcutInfo si = new ShortcutInfo(shortcutInfo, mContext);
si.iconBitmap = LauncherIcons.createShortcutIcon(shortcutInfo, mContext);
- return si;
+ return Pair.create((ItemInfo) si, (Object) shortcutInfo);
} else if (providerInfo != null) {
LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo
.fromProviderInfo(mContext, providerInfo);
@@ -475,9 +483,10 @@
widgetInfo.minSpanY = info.minSpanY;
widgetInfo.spanX = Math.min(info.spanX, idp.numColumns);
widgetInfo.spanY = Math.min(info.spanY, idp.numRows);
- return widgetInfo;
+ return Pair.create((ItemInfo) widgetInfo, (Object) providerInfo);
} else {
- return createShortcutInfo(data, LauncherAppState.getInstance(mContext));
+ ShortcutInfo si = createShortcutInfo(data, LauncherAppState.getInstance(mContext));
+ return Pair.create((ItemInfo) si, null);
}
}
@@ -588,7 +597,7 @@
return new PendingInstallShortcutInfo(info, original.mContext);
}
- private static class LazyShortcutsProvider extends Provider<List<ItemInfo>> {
+ private static class LazyShortcutsProvider extends Provider<List<Pair<ItemInfo, Object>>> {
private final Context mContext;
private final ArrayList<PendingInstallShortcutInfo> mPendingItems;
@@ -603,9 +612,9 @@
* packageManager and icon cache.
*/
@Override
- public ArrayList<ItemInfo> get() {
+ public ArrayList<Pair<ItemInfo, Object>> get() {
Preconditions.assertNonUiThread();
- ArrayList<ItemInfo> installQueue = new ArrayList<>();
+ ArrayList<Pair<ItemInfo, Object>> installQueue = new ArrayList<>();
LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext);
for (PendingInstallShortcutInfo pendingInfo : mPendingItems) {
// If the intent specifies a package, make sure the package exists
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index c5241d5..d3b4c94 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -91,7 +91,7 @@
import com.android.launcher3.anim.AnimationLayerSet;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
-import com.android.launcher3.compat.PinItemRequestCompat;
+import com.android.launcher3.compat.LauncherAppsCompatVO;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
@@ -1038,13 +1038,12 @@
updateInteraction(Workspace.State.NORMAL, mWorkspace.getState());
mWorkspace.onResume();
- if (!isWorkspaceLoading()) {
- // Process any items that were added while Launcher was away.
- InstallShortcutReceiver.disableAndFlushInstallQueue(this);
+ // Process any items that were added while Launcher was away.
+ InstallShortcutReceiver.disableAndFlushInstallQueue(
+ InstallShortcutReceiver.FLAG_ACTIVITY_PAUSED, this);
- // Refresh shortcuts if the permission changed.
- mModel.refreshShortcutsIfRequired();
- }
+ // Refresh shortcuts if the permission changed.
+ mModel.refreshShortcutsIfRequired();
if (shouldShowDiscoveryBounce()) {
mAllAppsController.showDiscoveryBounce();
@@ -1059,7 +1058,7 @@
@Override
protected void onPause() {
// Ensure that items added to Launcher are queued until Launcher returns
- InstallShortcutReceiver.enableInstallQueue();
+ InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_ACTIVITY_PAUSED);
super.onPause();
mPaused = true;
@@ -1425,8 +1424,8 @@
ShortcutInfo info = null;
if (Utilities.isAtLeastO()) {
- info = LauncherAppsCompat.createShortcutInfoFromPinItemRequest(
- this, PinItemRequestCompat.getPinItemRequest(data), 0);
+ info = LauncherAppsCompatVO.createShortcutInfoFromPinItemRequest(
+ this, LauncherAppsCompatVO.getPinItemRequest(data), 0);
}
if (info == null) {
@@ -3676,7 +3675,8 @@
mPendingActivityResult = null;
}
- InstallShortcutReceiver.disableAndFlushInstallQueue(this);
+ InstallShortcutReceiver.disableAndFlushInstallQueue(
+ InstallShortcutReceiver.FLAG_LOADER_RUNNING, this);
NotificationListener.setNotificationsChangedListener(mPopupDataProvider);
@@ -4075,8 +4075,8 @@
shortcutInfos.add(new KeyboardShortcutInfo(getString(R.string.custom_actions),
KeyEvent.KEYCODE_O, KeyEvent.META_CTRL_ON));
}
- if (currentFocus instanceof BubbleTextView &&
- ((BubbleTextView) currentFocus).hasDeepShortcuts()) {
+ if (currentFocus.getTag() instanceof ItemInfo
+ && DeepShortcutManager.supportsShortcuts((ItemInfo) currentFocus.getTag())) {
shortcutInfos.add(new KeyboardShortcutInfo(getString(R.string.action_deep_shortcut),
KeyEvent.KEYCODE_S, KeyEvent.META_CTRL_ON));
}
diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java
index 13cc7ba..c7b7782 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java
@@ -23,7 +23,6 @@
import android.graphics.Rect;
import android.os.Handler;
import android.os.SystemClock;
-import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -40,9 +39,7 @@
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragLayer.TouchCompleteListener;
-import java.lang.reflect.Method;
import java.util.ArrayList;
-import java.util.concurrent.Executor;
/**
* {@inheritDoc}
@@ -50,8 +47,6 @@
public class LauncherAppWidgetHostView extends AppWidgetHostView
implements TouchCompleteListener, View.OnLongClickListener {
- private static final String TAG = "LauncherWidgetHostView";
-
// Related to the auto-advancing of widgets
private static final long ADVANCE_INTERVAL = 20000;
private static final long ADVANCE_STAGGER = 250;
@@ -98,13 +93,7 @@
setBackgroundResource(R.drawable.widget_internal_focus_bg);
if (Utilities.isAtLeastO()) {
- try {
- Method asyncMethod = AppWidgetHostView.class
- .getMethod("setExecutor", Executor.class);
- asyncMethod.invoke(this, Utilities.THREAD_POOL_EXECUTOR);
- } catch (Exception e) {
- Log.e(TAG, "Unable to set async executor", e);
- }
+ setExecutor(Utilities.THREAD_POOL_EXECUTOR);
}
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index e75c217..b5ca301 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -40,6 +40,7 @@
import android.util.Log;
import android.util.LongSparseArray;
import android.util.MutableInt;
+import android.util.Pair;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
@@ -138,12 +139,6 @@
}
}
- /**
- * Set of runnables to be called on the background thread after the workspace binding
- * is complete.
- */
- static final ArrayList<Runnable> mBindCompleteRunnables = new ArrayList<Runnable>();
-
@Thunk WeakReference<Callbacks> mCallbacks;
// < only access in worker thread >
@@ -251,15 +246,8 @@
/**
* Adds the provided items to the workspace.
*/
- public void addAndBindAddedWorkspaceItems(List<ItemInfo> workspaceApps) {
- addAndBindAddedWorkspaceItems(Provider.of(workspaceApps));
- }
-
- /**
- * Adds the provided items to the workspace.
- */
public void addAndBindAddedWorkspaceItems(
- Provider<List<ItemInfo>> appsProvider) {
+ Provider<List<Pair<ItemInfo, Object>>> appsProvider) {
enqueueModelUpdateTask(new AddWorkspaceItemsTask(appsProvider));
}
@@ -529,7 +517,7 @@
*/
public boolean startLoader(int synchronousBindPage) {
// Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems
- InstallShortcutReceiver.enableInstallQueue();
+ InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_LOADER_RUNNING);
synchronized (mLock) {
// Don't bother to start the thread if we know it's not going to do anything
if (mCallbacks != null && mCallbacks.get() != null) {
@@ -607,7 +595,6 @@
private Context mContext;
private int mPageToBindFirst;
- @Thunk boolean mIsLoadingAndBindingWorkspace;
private boolean mStopped;
LoaderTask(Context context, int pageToBindFirst) {
@@ -675,8 +662,6 @@
try {
long now = 0;
if (DEBUG_LOADERS) Log.d(TAG, "step 1.1: loading workspace");
- // Set to false in bindWorkspace()
- mIsLoadingAndBindingWorkspace = true;
loadWorkspace();
verifyNotStopped();
@@ -1584,18 +1569,6 @@
callbacks.finishBindingItems();
}
- mIsLoadingAndBindingWorkspace = false;
-
- // Run all the bind complete runnables after workspace is bound.
- if (!mBindCompleteRunnables.isEmpty()) {
- synchronized (mBindCompleteRunnables) {
- for (final Runnable r : mBindCompleteRunnables) {
- runOnWorkerThread(r);
- }
- mBindCompleteRunnables.clear();
- }
- }
-
// If we're profiling, ensure this is the last thing in the queue.
if (DEBUG_LOADERS) {
Log.d(TAG, "bound workspace in "
@@ -1710,31 +1683,7 @@
mBgAllAppsList.add(new AppInfo(app, user, quietMode), app);
}
- final ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(mContext, user);
- if (heuristic != null) {
- final Runnable r = new Runnable() {
-
- @Override
- public void run() {
- heuristic.processUserApps(apps);
- }
- };
- mUiExecutor.execute(new Runnable() {
-
- @Override
- public void run() {
- // Check isLoadingWorkspace on the UI thread, as it is updated on
- // the UI thread.
- if (mIsLoadingAndBindingWorkspace) {
- synchronized (mBindCompleteRunnables) {
- mBindCompleteRunnables.add(r);
- }
- } else {
- runOnWorkerThread(r);
- }
- }
- });
- }
+ ManagedProfileHeuristic.onAllAppsLoaded(mContext, apps, user);
}
if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS) {
@@ -1768,8 +1717,6 @@
}
}
});
- // Cleanup any data stored for a deleted user.
- ManagedProfileHeuristic.processAllUsers(profiles, mContext);
if (DEBUG_LOADERS) {
Log.d(TAG, "Icons processed in "
+ (SystemClock.uptimeMillis() - loadTime) + "ms");
@@ -1829,7 +1776,7 @@
CacheDataUpdatedTask.OP_CACHE_UPDATE, user, updatedPackages));
}
- void enqueueModelUpdateTask(BaseModelUpdateTask task) {
+ public void enqueueModelUpdateTask(BaseModelUpdateTask task) {
if (!mModelLoaded && mLoaderTask == null) {
if (DEBUG_LOADERS) {
Log.d(TAG, "enqueueModelUpdateTask Ignoring task since loader is pending=" + task);
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index c84a431..4813571 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
+import android.annotation.TargetApi;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
@@ -38,6 +39,7 @@
import android.database.sqlite.SQLiteStatement;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -68,7 +70,6 @@
import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
@@ -855,15 +856,16 @@
* Removes widgets which are registered to the Launcher's host, but are not present
* in our model.
*/
+ @TargetApi(Build.VERSION_CODES.O)
public void removeGhostWidgets(SQLiteDatabase db) {
// Get all existing widget ids.
final AppWidgetHost host = newLauncherWidgetHost();
final int[] allWidgets;
try {
- Method getter = AppWidgetHost.class.getDeclaredMethod("getAppWidgetIds");
- getter.setAccessible(true);
- allWidgets = (int[]) getter.invoke(host);
- } catch (Exception e) {
+ // Although the method was defined in O, it has existed since the beginning of time,
+ // so it might work on older platforms as well.
+ allWidgets = host.getAppWidgetIds();
+ } catch (IncompatibleClassChangeError e) {
Log.e(TAG, "getAppWidgetIds not supported", e);
return;
}
diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java
index 61bcc17..8caba75 100644
--- a/src/com/android/launcher3/SessionCommitReceiver.java
+++ b/src/com/android/launcher3/SessionCommitReceiver.java
@@ -67,18 +67,19 @@
SessionInfo info = intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
- if (TextUtils.isEmpty(info.getAppPackageName()) ||
- info.getInstallReason() != PackageManager.INSTALL_REASON_USER) {
- return;
+ if (Process.myUserHandle().equals(user)) {
+ if (TextUtils.isEmpty(info.getAppPackageName()) ||
+ info.getInstallReason() != PackageManager.INSTALL_REASON_USER) {
+ return;
+ }
}
- if (!Process.myUserHandle().equals(user)) {
- // Managed profile is handled using ManagedProfileHeuristic
- return;
- }
+ queueAppIconAddition(context, info.getAppPackageName(), user);
+ }
+ public static void queueAppIconAddition(Context context, String packageName, UserHandle user) {
List<LauncherActivityInfo> activities = LauncherAppsCompat.getInstance(context)
- .getActivityList(info.getAppPackageName(), user);
+ .getActivityList(packageName, user);
if (activities == null || activities.isEmpty()) {
// no activity found
return;
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 54e7dd2..b006453 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -259,7 +259,7 @@
return scale;
}
- static boolean isSystemApp(Context context, Intent intent) {
+ public static boolean isSystemApp(Context context, Intent intent) {
PackageManager pm = context.getPackageManager();
ComponentName cn = intent.getComponent();
String packageName = null;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index b3dd7ac..672203c 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -451,7 +451,7 @@
mLauncher.lockScreenOrientation();
mLauncher.onInteractionBegin();
// Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging
- InstallShortcutReceiver.enableInstallQueue();
+ InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_DRAG_AND_DROP);
// Do not add a new page if it is a accessible drag which was not started by the workspace.
// We do not support accessibility drag from other sources and instead provide a direct
@@ -504,7 +504,8 @@
mLauncher.unlockScreenOrientation(false);
// Re-enable any Un/InstallShortcutReceiver and now process any queued items
- InstallShortcutReceiver.disableAndFlushInstallQueue(getContext());
+ InstallShortcutReceiver.disableAndFlushInstallQueue(
+ InstallShortcutReceiver.FLAG_DRAG_AND_DROP, getContext());
mOutlineProvider = null;
mDragInfo = null;
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index e8127c4..3433533 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -36,6 +36,7 @@
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.popup.PopupContainerWithArrow;
+import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.util.Thunk;
import java.util.ArrayList;
@@ -103,8 +104,7 @@
// If the request came from keyboard, do not add custom shortcuts as that is already
// exposed as a direct shortcut
- if (!fromKeyboard && host instanceof BubbleTextView
- && ((BubbleTextView) host).hasDeepShortcuts()) {
+ if (!fromKeyboard && DeepShortcutManager.supportsShortcuts(item)) {
info.addAction(mActions.get(DEEP_SHORTCUTS));
}
diff --git a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
index 2ad0edb..8161219 100644
--- a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
@@ -18,6 +18,7 @@
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.ItemInfo;
@@ -25,6 +26,7 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.notification.NotificationMainView;
import com.android.launcher3.shortcuts.DeepShortcutView;
import java.util.ArrayList;
@@ -35,14 +37,23 @@
*/
public class ShortcutMenuAccessibilityDelegate extends LauncherAccessibilityDelegate {
+ private static final int DISMISS_NOTIFICATION = R.id.action_dismiss_notification;
+
public ShortcutMenuAccessibilityDelegate(Launcher launcher) {
super(launcher);
+ mActions.put(DISMISS_NOTIFICATION, new AccessibilityAction(DISMISS_NOTIFICATION,
+ launcher.getText(R.string.action_dismiss_notification)));
}
@Override
public void addSupportedActions(View host, AccessibilityNodeInfo info, boolean fromKeyboard) {
if ((host.getParent() instanceof DeepShortcutView)) {
info.addAction(mActions.get(ADD_TO_WORKSPACE));
+ } else if (host instanceof NotificationMainView) {
+ NotificationMainView notificationView = (NotificationMainView) host;
+ if (notificationView.canChildBeDismissed(notificationView)) {
+ info.addAction(mActions.get(DISMISS_NOTIFICATION));
+ }
}
}
@@ -73,6 +84,14 @@
onComplete.run();
}
return true;
+ } else if (action == DISMISS_NOTIFICATION) {
+ if (!(host instanceof NotificationMainView)) {
+ return false;
+ }
+ NotificationMainView notificationView = (NotificationMainView) host;
+ notificationView.onChildDismissed(notificationView);
+ announceConfirmation(R.string.notification_dismissed);
+ return true;
}
return false;
}
diff --git a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
index 457b454..06097d0 100644
--- a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
+++ b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
@@ -54,7 +54,7 @@
});
}
- protected ArrayList<ComponentKey> getTitleMatchResult(String query) {
+ public ArrayList<ComponentKey> getTitleMatchResult(String query) {
// Do an intersection of the words in the query and each title, and filter out all the
// apps that don't match all of the words in the query.
final String queryTextLower = query.toLowerCase();
@@ -67,7 +67,7 @@
return result;
}
- protected boolean matches(AppInfo info, String query) {
+ public boolean matches(AppInfo info, String query) {
int queryLength = query.length();
String title = info.title.toString();
diff --git a/src/com/android/launcher3/anim/RoundedRectRevealOutlineProvider.java b/src/com/android/launcher3/anim/RoundedRectRevealOutlineProvider.java
index a0d1f8b..9c09477 100644
--- a/src/com/android/launcher3/anim/RoundedRectRevealOutlineProvider.java
+++ b/src/com/android/launcher3/anim/RoundedRectRevealOutlineProvider.java
@@ -42,7 +42,7 @@
@Override
public boolean shouldRemoveElevationDuringAnimation() {
- return true;
+ return false;
}
@Override
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java
index 472cfc9..26f4ae7 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompat.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java
@@ -26,13 +26,8 @@
import android.os.UserHandle;
import android.support.annotation.Nullable;
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherModel;
-import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.Utilities;
-import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
-import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.PackageUserKey;
import java.util.List;
@@ -88,62 +83,6 @@
public abstract List<ShortcutConfigActivityInfo> getCustomShortcutActivityList(
@Nullable PackageUserKey packageUser);
- /**
- * request.accept() will initiate the following flow:
- * -> go-to-system-process for actual processing (a)
- * -> callback-to-launcher on UI thread (b)
- * -> post callback on the worker thread (c)
- * -> Update model and unpin (in system) any shortcut not in out model. (d)
- *
- * Note that (b) will take at-least one frame as it involves posting callback from binder
- * thread to UI thread.
- * If (d) happens before we add this shortcut to our model, we will end up unpinning
- * the shortcut in the system.
- * Here its the caller's responsibility to add the newly created ShortcutInfo immediately
- * to the model (which may involves a single post-to-worker-thread). That will guarantee
- * that (d) happens after model is updated.
- */
- @Nullable
- public static ShortcutInfo createShortcutInfoFromPinItemRequest(
- Context context, final PinItemRequestCompat request, final long acceptDelay) {
- if (request != null &&
- request.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_SHORTCUT &&
- request.isValid()) {
-
- if (acceptDelay <= 0) {
- if (!request.accept()) {
- return null;
- }
- } else {
- // Block the worker thread until the accept() is called.
- new LooperExecutor(LauncherModel.getWorkerLooper()).execute(new Runnable() {
- @Override
- public void run() {
- try {
- Thread.sleep(acceptDelay);
- } catch (InterruptedException e) {
- // Ignore
- }
- if (request.isValid()) {
- request.accept();
- }
- }
- });
- }
-
- ShortcutInfoCompat compat = new ShortcutInfoCompat(request.getShortcutInfo());
- ShortcutInfo info = new ShortcutInfo(compat, context);
- // Apply the unbadged icon and fetch the actual icon asynchronously.
- info.iconBitmap = LauncherIcons
- .createShortcutIcon(compat, context, false /* badged */);
- LauncherAppState.getInstance(context).getModel()
- .updateAndBindShortcutInfo(info, compat);
- return info;
- } else {
- return null;
- }
- }
-
public void showAppDetailsForProfile(ComponentName component, UserHandle user) {
showAppDetailsForProfile(component, user, null, null);
}
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVO.java b/src/com/android/launcher3/compat/LauncherAppsCompatVO.java
index d145539..3214b46 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatVO.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVO.java
@@ -18,20 +18,27 @@
import android.annotation.TargetApi;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
+import android.content.pm.LauncherApps.PinItemRequest;
import android.content.pm.PackageManager;
import android.os.Build;
+import android.os.Parcelable;
import android.os.Process;
import android.os.UserHandle;
import android.support.annotation.Nullable;
-import android.util.Log;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel;
+import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.compat.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVO;
+import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.shortcuts.ShortcutInfoCompat;
+import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.PackageUserKey;
-import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
@@ -45,11 +52,6 @@
@Override
public ApplicationInfo getApplicationInfo(String packageName, int flags, UserHandle user) {
try {
- // TODO: Temporary workaround until the API signature is updated
- if (false) {
- throw new PackageManager.NameNotFoundException();
- }
-
ApplicationInfo info = mLauncherApps.getApplicationInfo(packageName, flags, user);
return (info.flags & ApplicationInfo.FLAG_INSTALLED) == 0 || !info.enabled
? null : info;
@@ -64,34 +66,89 @@
List<ShortcutConfigActivityInfo> result = new ArrayList<>();
UserHandle myUser = Process.myUserHandle();
- try {
- Method m = LauncherApps.class.getDeclaredMethod("getShortcutConfigActivityList",
- String.class, UserHandle.class);
- final List<UserHandle> users;
- final String packageName;
- if (packageUser == null) {
- users = UserManagerCompat.getInstance(mContext).getUserProfiles();
- packageName = null;
- } else {
- users = new ArrayList<>(1);
- users.add(packageUser.mUser);
- packageName = packageUser.mPackageName;
- }
- for (UserHandle user : users) {
- boolean ignoreTargetSdk = myUser.equals(user);
- List<LauncherActivityInfo> activities =
- (List<LauncherActivityInfo>) m.invoke(mLauncherApps, packageName, user);
- for (LauncherActivityInfo activityInfo : activities) {
- if (ignoreTargetSdk || activityInfo.getApplicationInfo().targetSdkVersion >=
- Build.VERSION_CODES.O) {
- result.add(new ShortcutConfigActivityInfoVO(activityInfo));
- }
+ final List<UserHandle> users;
+ final String packageName;
+ if (packageUser == null) {
+ users = UserManagerCompat.getInstance(mContext).getUserProfiles();
+ packageName = null;
+ } else {
+ users = new ArrayList<>(1);
+ users.add(packageUser.mUser);
+ packageName = packageUser.mPackageName;
+ }
+ for (UserHandle user : users) {
+ boolean ignoreTargetSdk = myUser.equals(user);
+ List<LauncherActivityInfo> activities =
+ mLauncherApps.getShortcutConfigActivityList(packageName, user);
+ for (LauncherActivityInfo activityInfo : activities) {
+ if (ignoreTargetSdk || activityInfo.getApplicationInfo().targetSdkVersion >=
+ Build.VERSION_CODES.O) {
+ result.add(new ShortcutConfigActivityInfoVO(activityInfo));
}
}
- } catch (Exception e) {
- Log.e("LauncherAppsCompatVO", "Error calling new API", e);
}
return result;
}
+
+ /**
+ * request.accept() will initiate the following flow:
+ * -> go-to-system-process for actual processing (a)
+ * -> callback-to-launcher on UI thread (b)
+ * -> post callback on the worker thread (c)
+ * -> Update model and unpin (in system) any shortcut not in out model. (d)
+ *
+ * Note that (b) will take at-least one frame as it involves posting callback from binder
+ * thread to UI thread.
+ * If (d) happens before we add this shortcut to our model, we will end up unpinning
+ * the shortcut in the system.
+ * Here its the caller's responsibility to add the newly created ShortcutInfo immediately
+ * to the model (which may involves a single post-to-worker-thread). That will guarantee
+ * that (d) happens after model is updated.
+ */
+ @Nullable
+ public static ShortcutInfo createShortcutInfoFromPinItemRequest(
+ Context context, final PinItemRequest request, final long acceptDelay) {
+ if (request != null &&
+ request.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT &&
+ request.isValid()) {
+
+ if (acceptDelay <= 0) {
+ if (!request.accept()) {
+ return null;
+ }
+ } else {
+ // Block the worker thread until the accept() is called.
+ new LooperExecutor(LauncherModel.getWorkerLooper()).execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(acceptDelay);
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ if (request.isValid()) {
+ request.accept();
+ }
+ }
+ });
+ }
+
+ ShortcutInfoCompat compat = new ShortcutInfoCompat(request.getShortcutInfo());
+ ShortcutInfo info = new ShortcutInfo(compat, context);
+ // Apply the unbadged icon and fetch the actual icon asynchronously.
+ info.iconBitmap = LauncherIcons
+ .createShortcutIcon(compat, context, false /* badged */);
+ LauncherAppState.getInstance(context).getModel()
+ .updateAndBindShortcutInfo(info, compat);
+ return info;
+ } else {
+ return null;
+ }
+ }
+
+ public static PinItemRequest getPinItemRequest(Intent intent) {
+ Parcelable extra = intent.getParcelableExtra(LauncherApps.EXTRA_PIN_ITEM_REQUEST);
+ return extra instanceof PinItemRequest ? (PinItemRequest) extra : null;
+ }
}
diff --git a/src/com/android/launcher3/compat/PinItemRequestCompat.java b/src/com/android/launcher3/compat/PinItemRequestCompat.java
deleted file mode 100644
index 1308cba..0000000
--- a/src/com/android/launcher3/compat/PinItemRequestCompat.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2017 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.compat;
-
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ShortcutInfo;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.launcher3.Utilities;
-
-/**
- * A wrapper around platform implementation of PinItemRequestCompat until the
- * updated SDK is available.
- */
-public class PinItemRequestCompat implements Parcelable {
-
- public static final String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST";
-
- public static final int REQUEST_TYPE_SHORTCUT = 1;
- public static final int REQUEST_TYPE_APPWIDGET = 2;
-
- private final Parcelable mObject;
-
- private PinItemRequestCompat(Parcelable object) {
- mObject = object;
- }
-
- public int getRequestType() {
- return (Integer) invokeMethod("getRequestType");
- }
-
- public ShortcutInfo getShortcutInfo() {
- return (ShortcutInfo) invokeMethod("getShortcutInfo");
- }
-
- public AppWidgetProviderInfo getAppWidgetProviderInfo(Context context) {
- try {
- return (AppWidgetProviderInfo) mObject.getClass()
- .getDeclaredMethod("getAppWidgetProviderInfo", Context.class)
- .invoke(mObject, context);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- public boolean isValid() {
- return (Boolean) invokeMethod("isValid");
- }
-
- public boolean accept() {
- return (Boolean) invokeMethod("accept");
- }
-
- public boolean accept(Bundle options) {
- try {
- return (Boolean) mObject.getClass().getDeclaredMethod("accept", Bundle.class)
- .invoke(mObject, options);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- public Bundle getExtras() {
- try {
- return (Bundle) mObject.getClass().getDeclaredMethod("getExtras").invoke(mObject);
- } catch (Exception e) {
- return null;
- }
- }
-
- private Object invokeMethod(String methodName) {
- try {
- return mObject.getClass().getDeclaredMethod(methodName).invoke(mObject);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int i) {
- parcel.writeParcelable(mObject, i);
- }
-
- public static final Parcelable.Creator<PinItemRequestCompat> CREATOR =
- new Parcelable.Creator<PinItemRequestCompat>() {
- public PinItemRequestCompat createFromParcel(Parcel source) {
- Parcelable object = source.readParcelable(null);
- return new PinItemRequestCompat(object);
- }
-
- public PinItemRequestCompat[] newArray(int size) {
- return new PinItemRequestCompat[size];
- }
- };
-
- public static PinItemRequestCompat getPinItemRequest(Intent intent) {
- if (!Utilities.isAtLeastO()) {
- return null;
- }
- Parcelable extra = intent.getParcelableExtra(EXTRA_PIN_ITEM_REQUEST);
- return extra == null ? null : new PinItemRequestCompat(extra);
- }
-}
diff --git a/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java b/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java
index 4a55e8c..6bdc627 100644
--- a/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java
+++ b/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java
@@ -37,8 +37,6 @@
import com.android.launcher3.R;
import com.android.launcher3.ShortcutInfo;
-import java.lang.reflect.Method;
-
/**
* Wrapper class for representing a shortcut configure activity.
*/
@@ -151,15 +149,13 @@
if (getUser().equals(Process.myUserHandle())) {
return super.startConfigActivity(activity, requestCode);
}
+ IntentSender is = activity.getSystemService(LauncherApps.class)
+ .getShortcutConfigActivityIntent(mInfo);
try {
- Method m = LauncherApps.class.getDeclaredMethod(
- "getShortcutConfigActivityIntent", LauncherActivityInfo.class);
- IntentSender is = (IntentSender) m.invoke(
- activity.getSystemService(LauncherApps.class), mInfo);
activity.startIntentSenderForResult(is, requestCode, null, 0, 0, 0);
return true;
- } catch (Exception e) {
- Log.e(TAG, "Error calling new API", e);
+ } catch (IntentSender.SendIntentException e) {
+ Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
return false;
}
}
diff --git a/src/com/android/launcher3/compat/UserManagerCompatVL.java b/src/com/android/launcher3/compat/UserManagerCompatVL.java
index 45525f5..c7f88f6 100644
--- a/src/com/android/launcher3/compat/UserManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/UserManagerCompatVL.java
@@ -22,8 +22,8 @@
import android.os.UserHandle;
import android.os.UserManager;
-import com.android.launcher3.Utilities;
import com.android.launcher3.util.LongArrayMap;
+import com.android.launcher3.util.ManagedProfileHeuristic;
import java.util.ArrayList;
import java.util.Collections;
@@ -122,7 +122,7 @@
@Override
public long getUserCreationTime(UserHandle user) {
- SharedPreferences prefs = Utilities.getPrefs(mContext);
+ SharedPreferences prefs = ManagedProfileHeuristic.prefs(mContext);
String key = USER_CREATION_TIME_KEY + getSerialNumberForUser(user);
if (!prefs.contains(key)) {
prefs.edit().putLong(key, System.currentTimeMillis()).apply();
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 09592a8..29789c8 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -28,6 +28,7 @@
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Intent;
+import android.content.pm.LauncherApps.PinItemRequest;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Point;
@@ -50,7 +51,7 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.compat.AppWidgetManagerCompat;
-import com.android.launcher3.compat.PinItemRequestCompat;
+import com.android.launcher3.compat.LauncherAppsCompatVO;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
@@ -60,7 +61,7 @@
import com.android.launcher3.widget.WidgetHostViewLoader;
import com.android.launcher3.widget.WidgetImageView;
-@TargetApi(Build.VERSION_CODES.N_MR1)
+@TargetApi(Build.VERSION_CODES.O)
public class AddItemActivity extends BaseActivity implements OnLongClickListener, OnTouchListener {
private static final int SHADOW_SIZE = 10;
@@ -70,7 +71,7 @@
private final PointF mLastTouchPos = new PointF();
- private PinItemRequestCompat mRequest;
+ private PinItemRequest mRequest;
private LauncherAppState mApp;
private InvariantDeviceProfile mIdp;
@@ -87,7 +88,7 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mRequest = PinItemRequestCompat.getPinItemRequest(getIntent());
+ mRequest = LauncherAppsCompatVO.getPinItemRequest(getIntent());
if (mRequest == null) {
finish();
return;
@@ -101,9 +102,9 @@
mDeviceProfile = mIdp.getDeviceProfile(getApplicationContext());
setContentView(R.layout.add_item_confirmation_activity);
- mWidgetCell = (LivePreviewWidgetCell) findViewById(R.id.widget_cell);
+ mWidgetCell = findViewById(R.id.widget_cell);
- if (mRequest.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_SHORTCUT) {
+ if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) {
setupShortcut();
} else {
if (!setupWidget()) {
@@ -226,7 +227,7 @@
* Called when place-automatically button is clicked.
*/
public void onPlaceAutomaticallyClick(View v) {
- if (mRequest.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_SHORTCUT) {
+ if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) {
InstallShortcutReceiver.queueShortcut(
new ShortcutInfoCompat(mRequest.getShortcutInfo()), this);
logCommand(Action.Command.CONFIRM);
diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
index df0c47c..f9f4e50 100644
--- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java
+++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
@@ -16,11 +16,14 @@
package com.android.launcher3.dragndrop;
+import android.annotation.TargetApi;
import android.appwidget.AppWidgetManager;
import android.content.ClipDescription;
import android.content.Intent;
+import android.content.pm.LauncherApps.PinItemRequest;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -40,7 +43,7 @@
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.PendingAddItemInfo;
import com.android.launcher3.R;
-import com.android.launcher3.compat.PinItemRequestCompat;
+import com.android.launcher3.Utilities;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -55,6 +58,7 @@
* {@link DragSource} for handling drop from a different window. This object is initialized
* in the source window and is passed on to the Launcher activity as an Intent extra.
*/
+@TargetApi(Build.VERSION_CODES.O)
public class PinItemDragListener
implements Parcelable, View.OnDragListener, DragSource, DragOptions.PreDragCondition {
@@ -63,7 +67,7 @@
private static final String MIME_TYPE_PREFIX = "com.android.launcher3.drag_and_drop/";
public static final String EXTRA_PIN_ITEM_DRAG_LISTENER = "pin_item_drag_listener";
- private final PinItemRequestCompat mRequest;
+ private final PinItemRequest mRequest;
// Position of preview relative to the touch location
private final Rect mPreviewRect;
@@ -78,7 +82,7 @@
private DragController mDragController;
private long mDragStartTime;
- public PinItemDragListener(PinItemRequestCompat request, Rect previewRect,
+ public PinItemDragListener(PinItemRequest request, Rect previewRect,
int previewBitmapWidth, int previewViewWidth) {
mRequest = request;
mPreviewRect = previewRect;
@@ -88,7 +92,7 @@
}
private PinItemDragListener(Parcel parcel) {
- mRequest = PinItemRequestCompat.CREATOR.createFromParcel(parcel);
+ mRequest = PinItemRequest.CREATOR.createFromParcel(parcel);
mPreviewRect = Rect.CREATOR.createFromParcel(parcel);
mPreviewBitmapWidth = parcel.readInt();
mPreviewViewWidth = parcel.readInt();
@@ -146,7 +150,7 @@
}
final PendingAddItemInfo item;
- if (mRequest.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_SHORTCUT) {
+ if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) {
item = new PendingAddShortcutInfo(
new PinShortcutRequestActivityInfo(mRequest, mLauncher));
} else {
@@ -177,7 +181,7 @@
// across windows, using drag position here give a good estimate for relative position
// to source window.
PendingItemDragHelper dragHelper = new PendingItemDragHelper(view);
- if (mRequest.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_APPWIDGET) {
+ if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_APPWIDGET) {
dragHelper.setPreview(getPreview(mRequest));
}
@@ -271,7 +275,7 @@
}
}
- public static RemoteViews getPreview(PinItemRequestCompat request) {
+ public static RemoteViews getPreview(PinItemRequest request) {
Bundle extras = request.getExtras();
if (extras != null &&
extras.get(AppWidgetManager.EXTRA_APPWIDGET_PREVIEW) instanceof RemoteViews) {
@@ -281,6 +285,9 @@
}
public static boolean handleDragRequest(Launcher launcher, Intent intent) {
+ if (!Utilities.isAtLeastO()) {
+ return false;
+ }
if (intent == null || !Intent.ACTION_MAIN.equals(intent.getAction())) {
return false;
}
diff --git a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
index bb5ac5b..52abbc7 100644
--- a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
+++ b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
@@ -21,6 +21,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.LauncherApps;
+import android.content.pm.LauncherApps.PinItemRequest;
import android.content.pm.ShortcutInfo;
import android.graphics.drawable.Drawable;
import android.os.Build;
@@ -30,26 +31,25 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
-import com.android.launcher3.compat.LauncherAppsCompat;
-import com.android.launcher3.compat.PinItemRequestCompat;
+import com.android.launcher3.compat.LauncherAppsCompatVO;
import com.android.launcher3.compat.ShortcutConfigActivityInfo;
/**
* Extension of ShortcutConfigActivityInfo to be used in the confirmation prompt for pin item
* request.
*/
-@TargetApi(Build.VERSION_CODES.N_MR1)
+@TargetApi(Build.VERSION_CODES.O)
class PinShortcutRequestActivityInfo extends ShortcutConfigActivityInfo {
// Class name used in the target component, such that it will never represent an
// actual existing class.
private static final String DUMMY_COMPONENT_CLASS = "pinned-shortcut";
- private final PinItemRequestCompat mRequest;
+ private final PinItemRequest mRequest;
private final ShortcutInfo mInfo;
private final Context mContext;
- public PinShortcutRequestActivityInfo(PinItemRequestCompat request, Context context) {
+ public PinShortcutRequestActivityInfo(PinItemRequest request, Context context) {
super(new ComponentName(request.getShortcutInfo().getPackage(), DUMMY_COMPONENT_CLASS),
request.getShortcutInfo().getUserHandle());
mRequest = request;
@@ -80,7 +80,7 @@
Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT +
mContext.getResources().getInteger(R.integer.config_overlayTransitionTime) / 2;
// Delay the actual accept() call until the drop animation is complete.
- return LauncherAppsCompat.createShortcutInfoFromPinItemRequest(
+ return LauncherAppsCompatVO.createShortcutInfoFromPinItemRequest(
mContext, mRequest, duration);
}
diff --git a/src/com/android/launcher3/dragndrop/PinWidgetFlowHandler.java b/src/com/android/launcher3/dragndrop/PinWidgetFlowHandler.java
index b6da6ad..9f617e4 100644
--- a/src/com/android/launcher3/dragndrop/PinWidgetFlowHandler.java
+++ b/src/com/android/launcher3/dragndrop/PinWidgetFlowHandler.java
@@ -16,15 +16,17 @@
package com.android.launcher3.dragndrop;
+import android.annotation.TargetApi;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
+import android.content.pm.LauncherApps.PinItemRequest;
+import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
-import com.android.launcher3.compat.PinItemRequestCompat;
import com.android.launcher3.widget.WidgetAddFlowHandler;
/**
@@ -33,18 +35,19 @@
* No config activity is shown even if it is defined in widget config. And a callback is sent when
* the widget is bound.
*/
+@TargetApi(Build.VERSION_CODES.O)
public class PinWidgetFlowHandler extends WidgetAddFlowHandler implements Parcelable {
- private final PinItemRequestCompat mRequest;
+ private final PinItemRequest mRequest;
- public PinWidgetFlowHandler(AppWidgetProviderInfo providerInfo, PinItemRequestCompat request) {
+ public PinWidgetFlowHandler(AppWidgetProviderInfo providerInfo, PinItemRequest request) {
super(providerInfo);
mRequest = request;
}
protected PinWidgetFlowHandler(Parcel parcel) {
super(parcel);
- mRequest = PinItemRequestCompat.CREATOR.createFromParcel(parcel);
+ mRequest = PinItemRequest.CREATOR.createFromParcel(parcel);
}
@Override
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index 10fb582..2e8e15b 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -17,6 +17,8 @@
import android.content.Context;
import android.content.Intent;
+import android.content.pm.LauncherActivityInfo;
+import android.os.Process;
import android.os.UserHandle;
import android.util.LongSparseArray;
import android.util.Pair;
@@ -35,9 +37,11 @@
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.GridOccupancy;
+import com.android.launcher3.util.ManagedProfileHeuristic.UserFolderInfo;
import com.android.launcher3.util.Provider;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
/**
@@ -45,18 +49,18 @@
*/
public class AddWorkspaceItemsTask extends ExtendedModelTask {
- private final Provider<List<ItemInfo>> mAppsProvider;
+ private final Provider<List<Pair<ItemInfo, Object>>> mAppsProvider;
/**
* @param appsProvider items to add on the workspace
*/
- public AddWorkspaceItemsTask(Provider<List<ItemInfo>> appsProvider) {
+ public AddWorkspaceItemsTask(Provider<List<Pair<ItemInfo, Object>>> appsProvider) {
mAppsProvider = appsProvider;
}
@Override
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
- List<ItemInfo> workspaceApps = mAppsProvider.get();
+ List<Pair<ItemInfo, Object>> workspaceApps = mAppsProvider.get();
if (workspaceApps.isEmpty()) {
return;
}
@@ -64,13 +68,17 @@
final ArrayList<ItemInfo> addedItemsFinal = new ArrayList<>();
final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<>();
+ HashMap<UserHandle, UserFolderInfo> userFolderMap = new HashMap<>();
// Get the list of workspace screens. We need to append to this list and
// can not use sBgWorkspaceScreens because loadWorkspace() may not have been
// called.
ArrayList<Long> workspaceScreens = LauncherModel.loadWorkspaceScreensDb(context);
synchronized(dataModel) {
- for (ItemInfo item : workspaceApps) {
+
+ List<ItemInfo> filteredItems = new ArrayList<>();
+ for (Pair<ItemInfo, Object> entry : workspaceApps) {
+ ItemInfo item = entry.first;
if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
// Short-circuit this logic if the icon exists somewhere on the workspace
@@ -79,6 +87,32 @@
}
}
+ if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
+ if (item instanceof AppInfo) {
+ item = ((AppInfo) item).makeShortcut();
+ }
+
+ if (!Process.myUserHandle().equals(item.user)) {
+ // Check if this belongs to a work folder.
+ if (!(entry.second instanceof LauncherActivityInfo)) {
+ continue;
+ }
+
+ UserFolderInfo userFolderInfo = userFolderMap.get(item.user);
+ if (userFolderInfo == null) {
+ userFolderInfo = new UserFolderInfo(context, item.user, dataModel);
+ userFolderMap.put(item.user, userFolderInfo);
+ }
+ item = userFolderInfo.convertToWorkspaceItem(
+ (ShortcutInfo) item, (LauncherActivityInfo) entry.second);
+ }
+ }
+ if (item != null) {
+ filteredItems.add(item);
+ }
+ }
+
+ for (ItemInfo item : filteredItems) {
// Find appropriate space for the item.
Pair<Long, int[]> coords = findSpaceForItem(app, dataModel, workspaceScreens,
addedWorkspaceScreensFinal, item.spanX, item.spanY);
@@ -130,6 +164,10 @@
}
});
}
+
+ for (UserFolderInfo userFolderInfo : userFolderMap.values()) {
+ userFolderInfo.applyPendingState(getModelWriter());
+ }
}
protected void updateScreens(Context context, ArrayList<Long> workspaceScreens) {
@@ -276,4 +314,5 @@
}
return occupied.findVacantCell(xy, spanX, spanY);
}
+
}
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index b58efb6..8380f01 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -35,6 +35,7 @@
import com.android.launcher3.LauncherModel.Callbacks;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.SessionCommitReceiver;
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.Utilities;
import com.android.launcher3.compat.LauncherAppsCompat;
@@ -43,7 +44,6 @@
import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.ManagedProfileHeuristic;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
@@ -100,11 +100,11 @@
appsList.removePackage(packages[i], Process.myUserHandle());
}
appsList.addPackage(context, packages[i], mUser);
- }
- ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(context, mUser);
- if (heuristic != null) {
- heuristic.processPackageAdd(mPackages);
+ // Automatically add homescreen icon for work profile apps for below O device.
+ if (!Utilities.isAtLeastO() && !Process.myUserHandle().equals(mUser)) {
+ SessionCommitReceiver.queueAppIconAddition(context, packages[i], mUser);
+ }
}
break;
}
@@ -119,10 +119,6 @@
flagOp = FlagOp.removeFlag(ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE);
break;
case OP_REMOVE: {
- ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(context, mUser);
- if (heuristic != null) {
- heuristic.processPackageRemoved(mPackages);
- }
for (int i = 0; i < N; i++) {
iconCache.removeIconsForPkg(packages[i], mUser);
}
diff --git a/src/com/android/launcher3/notification/NotificationFooterLayout.java b/src/com/android/launcher3/notification/NotificationFooterLayout.java
index 1eef743..051c033 100644
--- a/src/com/android/launcher3/notification/NotificationFooterLayout.java
+++ b/src/com/android/launcher3/notification/NotificationFooterLayout.java
@@ -141,6 +141,7 @@
icon.setBackground(info.getIconForBackground(getContext(), mBackgroundColor));
icon.setOnClickListener(info);
icon.setTag(info);
+ icon.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
mIconRow.addView(icon, 0, mIconLayoutParams);
return icon;
}
diff --git a/src/com/android/launcher3/notification/NotificationItemView.java b/src/com/android/launcher3/notification/NotificationItemView.java
index dd272b3..997def2 100644
--- a/src/com/android/launcher3/notification/NotificationItemView.java
+++ b/src/com/android/launcher3/notification/NotificationItemView.java
@@ -77,6 +77,10 @@
mSwipeHelper.setDisableHardwareLayers(true);
}
+ public NotificationMainView getMainView() {
+ return mMainView;
+ }
+
public int getHeightMinusFooter() {
int footerHeight = mFooter.getParent() == null ? 0 : mFooter.getHeight();
return getHeight() - footerHeight;
diff --git a/src/com/android/launcher3/notification/NotificationMainView.java b/src/com/android/launcher3/notification/NotificationMainView.java
index d6e0272..0d6da77 100644
--- a/src/com/android/launcher3/notification/NotificationMainView.java
+++ b/src/com/android/launcher3/notification/NotificationMainView.java
@@ -122,7 +122,7 @@
@Override
public boolean canChildBeDismissed(View v) {
- return mNotificationInfo.dismissable;
+ return mNotificationInfo != null && mNotificationInfo.dismissable;
}
@Override
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index d4ee3b8..ccead37 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -114,7 +114,6 @@
mStartDragThreshold = getResources().getDimensionPixelSize(
R.dimen.deep_shortcuts_start_drag_threshold);
- // TODO: make sure the delegate works for all items, not just shortcuts.
mAccessibilityDelegate = new ShortcutMenuAccessibilityDelegate(mLauncher);
mIsRtl = Utilities.isRtl(getResources());
}
@@ -176,7 +175,7 @@
// Add dummy views first, and populate with real info when ready.
PopupPopulator.Item[] itemsToPopulate = PopupPopulator
.getItemsToPopulate(shortcutIds, notificationKeys, systemShortcuts);
- addDummyViews(originalIcon, itemsToPopulate, notificationKeys.size() > 1);
+ addDummyViews(itemsToPopulate, notificationKeys.size() > 1);
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
orientAboutIcon(originalIcon, arrowHeight + arrowVerticalOffset);
@@ -187,7 +186,7 @@
mNotificationItemView = null;
mShortcutsItemView = null;
itemsToPopulate = PopupPopulator.reverseItems(itemsToPopulate);
- addDummyViews(originalIcon, itemsToPopulate, notificationKeys.size() > 1);
+ addDummyViews(itemsToPopulate, notificationKeys.size() > 1);
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
orientAboutIcon(originalIcon, arrowHeight + arrowVerticalOffset);
@@ -204,6 +203,17 @@
updateNotificationHeader();
}
+ int numShortcuts = shortcutViews.size() + systemShortcutViews.size();
+ int numNotifications = notificationKeys.size();
+ if (numNotifications == 0) {
+ setContentDescription(getContext().getString(R.string.shortcuts_menu_description,
+ numShortcuts, originalIcon.getContentDescription().toString()));
+ } else {
+ setContentDescription(getContext().getString(
+ R.string.shortcuts_menu_with_notifications_description, numShortcuts,
+ numNotifications, originalIcon.getContentDescription().toString()));
+ }
+
// Add the arrow.
final int arrowHorizontalOffset = resources.getDimensionPixelSize(isAlignedWithStart() ?
R.dimen.popup_arrow_horizontal_offset_start :
@@ -225,8 +235,8 @@
systemShortcuts, systemShortcutViews));
}
- private void addDummyViews(BubbleTextView originalIcon,
- PopupPopulator.Item[] itemTypesToPopulate, boolean notificationFooterHasIcons) {
+ private void addDummyViews(PopupPopulator.Item[] itemTypesToPopulate,
+ boolean notificationFooterHasIcons) {
final Resources res = getResources();
final int spacing = res.getDimensionPixelSize(R.dimen.popup_items_spacing);
final LayoutInflater inflater = mLauncher.getLayoutInflater();
@@ -243,12 +253,14 @@
int footerHeight = notificationFooterHasIcons ?
res.getDimensionPixelSize(R.dimen.notification_footer_height) : 0;
item.findViewById(R.id.footer).getLayoutParams().height = footerHeight;
+ mNotificationItemView.getMainView().setAccessibilityDelegate(mAccessibilityDelegate);
+ } else if (itemTypeToPopulate == PopupPopulator.Item.SHORTCUT) {
+ item.setAccessibilityDelegate(mAccessibilityDelegate);
}
boolean shouldAddBottomMargin = nextItemTypeToPopulate != null
&& itemTypeToPopulate.isShortcut ^ nextItemTypeToPopulate.isShortcut;
- item.setAccessibilityDelegate(mAccessibilityDelegate);
if (itemTypeToPopulate.isShortcut) {
if (mShortcutsItemView == null) {
mShortcutsItemView = (ShortcutsItemView) inflater.inflate(
@@ -266,9 +278,6 @@
}
}
}
- // TODO: update this, since not all items are shortcuts
- setContentDescription(getContext().getString(R.string.shortcuts_menu_description,
- numItems, originalIcon.getContentDescription().toString()));
}
protected PopupItemView getItemViewAt(int index) {
diff --git a/src/com/android/launcher3/util/CachedPackageTracker.java b/src/com/android/launcher3/util/CachedPackageTracker.java
deleted file mode 100644
index 314b4c0..0000000
--- a/src/com/android/launcher3/util/CachedPackageTracker.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * 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.Context;
-import android.content.SharedPreferences;
-import android.content.pm.LauncherActivityInfo;
-import android.os.UserHandle;
-
-import com.android.launcher3.Utilities;
-import com.android.launcher3.compat.LauncherAppsCompat;
-import com.android.launcher3.compat.LauncherAppsCompat.OnAppsChangedCallbackCompat;
-import com.android.launcher3.compat.UserManagerCompat;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Utility class to track list of installed packages. It persists the list so that apps
- * installed/uninstalled while Launcher was dead can also be handled properly.
- */
-public abstract class CachedPackageTracker implements OnAppsChangedCallbackCompat {
-
- protected static final String INSTALLED_PACKAGES_PREFIX = "installed_packages_for_user_";
-
- protected final SharedPreferences mPrefs;
- protected final UserManagerCompat mUserManager;
- protected final LauncherAppsCompat mLauncherApps;
-
- public CachedPackageTracker(Context context, String preferenceFileName) {
- mPrefs = context.getSharedPreferences(preferenceFileName, Context.MODE_PRIVATE);
- mUserManager = UserManagerCompat.getInstance(context);
- mLauncherApps = LauncherAppsCompat.getInstance(context);
- }
-
- /**
- * Checks the list of user apps, and generates package event accordingly.
- * {@see #onLauncherAppsAdded}, {@see #onLauncherPackageRemoved}
- */
- public void processUserApps(List<LauncherActivityInfo> apps, UserHandle user) {
- String prefKey = INSTALLED_PACKAGES_PREFIX + mUserManager.getSerialNumberForUser(user);
- HashSet<String> oldPackageSet = new HashSet<>();
- final boolean userAppsExisted = getUserApps(oldPackageSet, prefKey);
-
- HashSet<String> packagesRemoved = new HashSet<>(oldPackageSet);
- HashSet<String> newPackageSet = new HashSet<>();
- ArrayList<LauncherActivityInstallInfo> packagesAdded = new ArrayList<>();
-
- for (LauncherActivityInfo info : apps) {
- String packageName = info.getComponentName().getPackageName();
- newPackageSet.add(packageName);
- packagesRemoved.remove(packageName);
-
- if (!oldPackageSet.contains(packageName)) {
- oldPackageSet.add(packageName);
- packagesAdded.add(new LauncherActivityInstallInfo(
- info, info.getFirstInstallTime()));
- }
- }
-
- if (!packagesAdded.isEmpty() || !packagesRemoved.isEmpty()) {
- mPrefs.edit().putStringSet(prefKey, newPackageSet).apply();
-
- if (!packagesAdded.isEmpty()) {
- Collections.sort(packagesAdded);
- onLauncherAppsAdded(packagesAdded, user, userAppsExisted);
- }
-
- if (!packagesRemoved.isEmpty()) {
- for (String pkg : packagesRemoved) {
- onLauncherPackageRemoved(pkg, user);
- }
- }
- }
- }
-
- /**
- * Reads the list of user apps which have already been processed.
- * @return false if the list didn't exist, true otherwise
- */
- private boolean getUserApps(HashSet<String> outExistingApps, String prefKey) {
- Set<String> userApps = mPrefs.getStringSet(prefKey, null);
- if (userApps == null) {
- return false;
- } else {
- outExistingApps.addAll(userApps);
- return true;
- }
- }
-
- @Override
- public void onPackageRemoved(String packageName, UserHandle user) {
- String prefKey = INSTALLED_PACKAGES_PREFIX + mUserManager.getSerialNumberForUser(user);
- HashSet<String> packageSet = new HashSet<>();
- if (getUserApps(packageSet, prefKey) && packageSet.remove(packageName)) {
- mPrefs.edit().putStringSet(prefKey, packageSet).apply();
- }
-
- onLauncherPackageRemoved(packageName, user);
- }
-
- @Override
- public void onPackageAdded(String packageName, UserHandle user) {
- String prefKey = INSTALLED_PACKAGES_PREFIX + mUserManager.getSerialNumberForUser(user);
- HashSet<String> packageSet = new HashSet<>();
- final boolean userAppsExisted = getUserApps(packageSet, prefKey);
- if (!packageSet.contains(packageName)) {
- List<LauncherActivityInfo> activities =
- mLauncherApps.getActivityList(packageName, user);
- if (!activities.isEmpty()) {
- LauncherActivityInfo activityInfo = activities.get(0);
-
- packageSet.add(packageName);
- mPrefs.edit().putStringSet(prefKey, packageSet).apply();
- onLauncherAppsAdded(Arrays.asList(
- new LauncherActivityInstallInfo(activityInfo, System.currentTimeMillis())),
- user, userAppsExisted);
- }
- }
- }
-
- @Override
- public void onPackageChanged(String packageName, UserHandle user) { }
-
- @Override
- public void onPackagesAvailable(
- String[] packageNames, UserHandle user, boolean replacing) { }
-
- @Override
- public void onPackagesUnavailable(
- String[] packageNames, UserHandle user, boolean replacing) { }
-
- @Override
- public void onPackagesSuspended(String[] packageNames, UserHandle user) { }
-
- @Override
- public void onPackagesUnsuspended(String[] packageNames, UserHandle user) { }
-
- /**
- * Called when new launcher apps are added.
- * @param apps list of newly added activities. Only one entry per package is sent.
- * @param user the user for this event. All activities in {@param apps} will belong to
- * the same user.
- * @param userAppsExisted false if the list was processed for the first time, like in case
- * when Launcher was newly installed or a new user was added.
- */
- protected abstract void onLauncherAppsAdded(List<LauncherActivityInstallInfo> apps,
- UserHandle user, boolean userAppsExisted);
-
- /**
- * Called when apps are removed from the system.
- */
- protected abstract void onLauncherPackageRemoved(String packageName, UserHandle user);
-
- public static class LauncherActivityInstallInfo
- implements Comparable<LauncherActivityInstallInfo> {
- public final LauncherActivityInfo info;
- public final long installTime;
-
- public LauncherActivityInstallInfo(LauncherActivityInfo info, long installTime) {
- this.info = info;
- this.installTime = installTime;
- }
-
- @Override
- public int compareTo(LauncherActivityInstallInfo another) {
- return Utilities.longCompare(installTime, another.installTime);
- }
- }
-}
diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
index ce603c4..091dd84 100644
--- a/src/com/android/launcher3/util/ManagedProfileHeuristic.java
+++ b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
@@ -19,23 +19,23 @@
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.LauncherActivityInfo;
+import android.os.Handler;
import android.os.Process;
import android.os.UserHandle;
-import android.support.v4.os.BuildCompat;
-import com.android.launcher3.AppInfo;
import com.android.launcher3.FolderInfo;
-import com.android.launcher3.IconCache;
+import com.android.launcher3.InstallShortcutReceiver;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherFiles;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
import com.android.launcher3.SessionCommitReceiver;
import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.Utilities;
import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.shortcuts.ShortcutInfoCompat;
+import com.android.launcher3.model.BgDataModel;
+import com.android.launcher3.model.ModelWriter;
import java.util.ArrayList;
import java.util.HashSet;
@@ -47,11 +47,6 @@
*/
public class ManagedProfileHeuristic {
- /**
- * Maintain a set of packages installed per user.
- */
- private static final String INSTALLED_PACKAGES_PREFIX = "installed_packages_for_user_";
-
private static final String USER_FOLDER_ID_PREFIX = "user_folder_";
/**
@@ -59,165 +54,154 @@
*/
private static final long AUTO_ADD_TO_FOLDER_DURATION = 8 * 60 * 60 * 1000;
- public static ManagedProfileHeuristic get(Context context, UserHandle user) {
- if (!Process.myUserHandle().equals(user)) {
- return new ManagedProfileHeuristic(context, user);
- }
- return null;
- }
-
- private final Context mContext;
- private final LauncherModel mModel;
- private final UserHandle mUser;
- private final IconCache mIconCache;
- private final boolean mAddIconsToHomescreen;
-
- private ManagedProfileHeuristic(Context context, UserHandle user) {
- mContext = context;
- mUser = user;
- mModel = LauncherAppState.getInstance(context).getModel();
- mIconCache = LauncherAppState.getInstance(context).getIconCache();
- mAddIconsToHomescreen =
- !BuildCompat.isAtLeastO() || SessionCommitReceiver.isEnabled(context);
- }
-
- public void processPackageRemoved(String[] packages) {
- Preconditions.assertWorkerThread();
- ManagedProfilePackageHandler handler = new ManagedProfilePackageHandler();
- for (String pkg : packages) {
- handler.onPackageRemoved(pkg, mUser);
- }
- }
-
- public void processPackageAdd(String[] packages) {
- Preconditions.assertWorkerThread();
- ManagedProfilePackageHandler handler = new ManagedProfilePackageHandler();
- for (String pkg : packages) {
- handler.onPackageAdded(pkg, mUser);
- }
- }
-
- public void processUserApps(List<LauncherActivityInfo> apps) {
- Preconditions.assertWorkerThread();
- new ManagedProfilePackageHandler().processUserApps(apps, mUser);
- }
-
- private class ManagedProfilePackageHandler extends CachedPackageTracker {
-
- private ManagedProfilePackageHandler() {
- super(mContext, LauncherFiles.MANAGED_USER_PREFERENCES_KEY);
+ public static void onAllAppsLoaded(final Context context,
+ List<LauncherActivityInfo> apps, UserHandle user) {
+ if (Process.myUserHandle().equals(user)) {
+ return;
}
- protected void onLauncherAppsAdded(
- List<LauncherActivityInstallInfo> apps, UserHandle user, boolean userAppsExisted) {
- ArrayList<ShortcutInfo> workFolderApps = new ArrayList<>();
- ArrayList<ShortcutInfo> homescreenApps = new ArrayList<>();
+ UserFolderInfo ufi = new UserFolderInfo(context, user, null);
+ // We only handle folder creation once. Later icon additions are handled using package
+ // or session events.
+ if (ufi.folderAlreadyCreated) {
+ return;
+ }
- int count = apps.size();
- long folderCreationTime =
- mUserManager.getUserCreationTime(user) + AUTO_ADD_TO_FOLDER_DURATION;
+ if (Utilities.isAtLeastO() && !SessionCommitReceiver.isEnabled(context)) {
+ // Just mark the folder id preference to avoid new folder creation later.
+ ufi.prefs.edit().putLong(ufi.folderIdKey, ItemInfo.NO_ID).apply();
+ return;
+ }
- boolean quietModeEnabled = UserManagerCompat.getInstance(mContext)
- .isQuietModeEnabled(user);
- for (int i = 0; i < count; i++) {
- LauncherActivityInstallInfo info = apps.get(i);
- AppInfo appInfo = new AppInfo(info.info, user, quietModeEnabled);
- mIconCache.getTitleAndIcon(appInfo, info.info, false /* useLowResIcon */);
- ShortcutInfo si = appInfo.makeShortcut();
- ((info.installTime <= folderCreationTime) ? workFolderApps : homescreenApps).add(si);
- }
-
- finalizeWorkFolder(user, workFolderApps, homescreenApps);
-
- // Do not add shortcuts on the homescreen for the first time. This prevents the launcher
- // getting filled with the managed user apps, when it start with a fresh DB (or after
- // a very long time).
- if (userAppsExisted && !homescreenApps.isEmpty() && mAddIconsToHomescreen) {
- mModel.addAndBindAddedWorkspaceItems(new ArrayList<ItemInfo>(homescreenApps));
+ InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_BULK_ADD);
+ for (LauncherActivityInfo app : apps) {
+ // Queue all items which should go in the work folder.
+ if (app.getFirstInstallTime() < ufi.addIconToFolderTime) {
+ InstallShortcutReceiver.queueActivityInfo(app, context);
}
}
+ // Post the queue update on next frame, so that the loader gets finished.
+ new Handler(LauncherModel.getWorkerLooper()).post(new Runnable() {
+ @Override
+ public void run() {
+ InstallShortcutReceiver.disableAndFlushInstallQueue(
+ InstallShortcutReceiver.FLAG_BULK_ADD, context);
+ }
+ });
+ }
- @Override
- protected void onLauncherPackageRemoved(String packageName, UserHandle user) {
+
+ /**
+ * Utility class to help workspace icon addition.
+ */
+ public static class UserFolderInfo {
+
+ final ArrayList<ShortcutInfo> pendingShortcuts = new ArrayList<>();
+
+ final UserHandle user;
+
+ final long userSerial;
+ // Time until which icons will be added to folder instead.
+ final long addIconToFolderTime;
+
+ final String folderIdKey;
+ final SharedPreferences prefs;
+
+ final boolean folderAlreadyCreated;
+ final FolderInfo folderInfo;
+
+ boolean folderPendingAddition;
+
+ public UserFolderInfo(Context context, UserHandle user, BgDataModel dataModel) {
+ this.user = user;
+
+ UserManagerCompat um = UserManagerCompat.getInstance(context);
+ userSerial = um.getSerialNumberForUser(user);
+ addIconToFolderTime = um.getUserCreationTime(user) + AUTO_ADD_TO_FOLDER_DURATION;
+
+ folderIdKey = USER_FOLDER_ID_PREFIX + userSerial;
+ prefs = prefs(context);
+
+ folderAlreadyCreated = prefs.contains(folderIdKey);
+ if (dataModel != null) {
+ if (folderAlreadyCreated) {
+ long folderId = prefs.getLong(folderIdKey, ItemInfo.NO_ID);
+ folderInfo = dataModel.folders.get(folderId);
+ } else {
+ folderInfo = new FolderInfo();
+ folderInfo.title = context.getText(R.string.work_folder_name);
+ folderInfo.setOption(FolderInfo.FLAG_WORK_FOLDER, true, null);
+ folderPendingAddition = true;
+ }
+ } else {
+ folderInfo = null;
+ }
}
/**
- * Adds and binds shortcuts marked to be added to the work folder.
+ * Returns the ItemInfo which should be added to the workspace. In case the the provided
+ * {@link ShortcutInfo} or a wrapped {@link FolderInfo} or null.
*/
- private void finalizeWorkFolder(
- UserHandle user, final ArrayList<ShortcutInfo> workFolderApps,
- ArrayList<ShortcutInfo> homescreenApps) {
- if (workFolderApps.isEmpty()) {
+ public ItemInfo convertToWorkspaceItem(
+ ShortcutInfo shortcut, LauncherActivityInfo activityInfo) {
+ if (activityInfo.getFirstInstallTime() >= addIconToFolderTime) {
+ return shortcut;
+ }
+
+ if (folderAlreadyCreated) {
+ if (folderInfo == null) {
+ // Work folder was deleted by user, add icon to home screen.
+ return shortcut;
+ } else {
+ // Add item to work folder instead. Nothing needs to be added
+ // on the homescreen.
+ pendingShortcuts.add(shortcut);
+ return null;
+ }
+ }
+
+ pendingShortcuts.add(shortcut);
+ folderInfo.add(shortcut, false);
+ if (folderPendingAddition) {
+ folderPendingAddition = false;
+ return folderInfo;
+ } else {
+ // WorkFolder already requested to be added. Nothing new needs to be added.
+ return null;
+ }
+ }
+
+ public void applyPendingState(ModelWriter writer) {
+ if (folderInfo == null) {
return;
}
- // Try to get a work folder.
- String folderIdKey = USER_FOLDER_ID_PREFIX + mUserManager.getSerialNumberForUser(user);
- if (!mAddIconsToHomescreen) {
- if (!mPrefs.contains(folderIdKey)) {
- // Just mark the folder id preference to avoid new folder creation later.
- mPrefs.edit().putLong(folderIdKey, -1).apply();
- }
- return;
+
+ int startingRank = 0;
+ if (folderAlreadyCreated) {
+ startingRank = folderInfo.contents.size();
}
- if (mPrefs.contains(folderIdKey)) {
- long folderId = mPrefs.getLong(folderIdKey, 0);
- final FolderInfo workFolder = mModel.findFolderById(folderId);
- if (workFolder == null || !workFolder.hasOption(FolderInfo.FLAG_WORK_FOLDER)) {
- // Could not get a work folder. Add all the icons to homescreen.
- homescreenApps.addAll(0, workFolderApps);
- return;
- }
- saveWorkFolderShortcuts(folderId, workFolder.contents.size(), workFolderApps);
+ for (ShortcutInfo info : pendingShortcuts) {
+ info.rank = startingRank++;
+ writer.addItemToDatabase(info, folderInfo.id, 0, 0, 0);
+ }
+ if (folderAlreadyCreated) {
// FolderInfo could already be bound. We need to add shortcuts on the UI thread.
new MainThreadExecutor().execute(new Runnable() {
@Override
public void run() {
- workFolder.prepareAutoUpdate();
- for (ShortcutInfo info : workFolderApps) {
- workFolder.add(info, false);
+ folderInfo.prepareAutoUpdate();
+ for (ShortcutInfo info : pendingShortcuts) {
+ folderInfo.add(info, false);
}
}
});
} else {
- // Create a new folder.
- final FolderInfo workFolder = new FolderInfo();
- workFolder.title = mContext.getText(R.string.work_folder_name);
- workFolder.setOption(FolderInfo.FLAG_WORK_FOLDER, true, null);
-
- // Add all shortcuts before adding it to the UI, as an empty folder might get deleted.
- for (ShortcutInfo info : workFolderApps) {
- workFolder.add(info, false);
- }
-
- // Add the item to home screen and DB. This also generates an item id synchronously.
- ArrayList<ItemInfo> itemList = new ArrayList<>(1);
- itemList.add(workFolder);
- mModel.addAndBindAddedWorkspaceItems(itemList);
- mPrefs.edit().putLong(folderIdKey, workFolder.id).apply();
-
- saveWorkFolderShortcuts(workFolder.id, 0, workFolderApps);
+ prefs.edit().putLong(folderIdKey, folderInfo.id).apply();
}
}
-
- @Override
- public void onShortcutsChanged(String packageName, List<ShortcutInfoCompat> shortcuts,
- UserHandle user) {
- // Do nothing
- }
- }
-
- /**
- * Add work folder shortcuts to the DB.
- */
- private void saveWorkFolderShortcuts(
- long workFolderId, int startingRank, ArrayList<ShortcutInfo> workFolderApps) {
- for (ItemInfo info : workFolderApps) {
- info.rank = startingRank++;
- mModel.getWriter(false).addItemToDatabase(info, workFolderId, 0, 0, 0);
- }
}
/**
@@ -225,14 +209,12 @@
*/
public static void processAllUsers(List<UserHandle> users, Context context) {
UserManagerCompat userManager = UserManagerCompat.getInstance(context);
- HashSet<String> validKeys = new HashSet<String>();
+ HashSet<String> validKeys = new HashSet<>();
for (UserHandle user : users) {
- addAllUserKeys(userManager.getSerialNumberForUser(user), validKeys);
+ validKeys.add(USER_FOLDER_ID_PREFIX + userManager.getSerialNumberForUser(user));
}
- SharedPreferences prefs = context.getSharedPreferences(
- LauncherFiles.MANAGED_USER_PREFERENCES_KEY,
- Context.MODE_PRIVATE);
+ SharedPreferences prefs = prefs(context);
SharedPreferences.Editor editor = prefs.edit();
for (String key : prefs.getAll().keySet()) {
if (!validKeys.contains(key)) {
@@ -242,11 +224,6 @@
editor.apply();
}
- private static void addAllUserKeys(long userSerial, HashSet<String> keysOut) {
- keysOut.add(INSTALLED_PACKAGES_PREFIX + userSerial);
- keysOut.add(USER_FOLDER_ID_PREFIX + userSerial);
- }
-
/**
* For each user, if a work folder has not been created, mark it such that the folder will
* never get created.
@@ -260,11 +237,8 @@
if (myUser.equals(user)) {
continue;
}
-
if (prefs == null) {
- prefs = context.getSharedPreferences(
- LauncherFiles.MANAGED_USER_PREFERENCES_KEY,
- Context.MODE_PRIVATE);
+ prefs = prefs(context);
}
String folderIdKey = USER_FOLDER_ID_PREFIX + userManager.getSerialNumberForUser(user);
if (!prefs.contains(folderIdKey)) {
@@ -272,4 +246,9 @@
}
}
}
+
+ public static SharedPreferences prefs(Context context) {
+ return context.getSharedPreferences(
+ LauncherFiles.MANAGED_USER_PREFERENCES_KEY, Context.MODE_PRIVATE);
+ }
}
diff --git a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
index 883be5a..4c80902 100644
--- a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
+++ b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
@@ -21,6 +21,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.verify;
@@ -50,7 +51,11 @@
}
private AddWorkspaceItemsTask newTask(ItemInfo... items) {
- return new AddWorkspaceItemsTask(Provider.of(Arrays.asList(items))) {
+ List<Pair<ItemInfo, Object>> list = new ArrayList<>();
+ for (ItemInfo item : items) {
+ list.add(Pair.create(item, null));
+ }
+ return new AddWorkspaceItemsTask(Provider.of(list)) {
@Override
protected void updateScreens(Context context, ArrayList<Long> workspaceScreens) { }