summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/layout/search_drop_target_bar.xml20
-rw-r--r--res/layout/widget_cell.xml11
-rw-r--r--res/layout/widgets_list_row_view.xml6
-rw-r--r--res/values/dimens.xml6
-rw-r--r--res/values/strings.xml4
-rw-r--r--src/com/android/launcher3/AppWidgetResizeFrame.java2
-rw-r--r--src/com/android/launcher3/ButtonDropTarget.java19
-rw-r--r--src/com/android/launcher3/CellLayout.java2
-rw-r--r--src/com/android/launcher3/DeferredHandler.java47
-rw-r--r--src/com/android/launcher3/DeleteDropTarget.java14
-rw-r--r--src/com/android/launcher3/DragController.java5
-rw-r--r--src/com/android/launcher3/Folder.java11
-rw-r--r--src/com/android/launcher3/FolderPagedView.java2
-rw-r--r--src/com/android/launcher3/IconCache.java16
-rw-r--r--src/com/android/launcher3/InfoDropTarget.java11
-rw-r--r--src/com/android/launcher3/InstallShortcutReceiver.java8
-rw-r--r--src/com/android/launcher3/Launcher.java53
-rw-r--r--src/com/android/launcher3/LauncherAccessibilityDelegate.java53
-rw-r--r--src/com/android/launcher3/LauncherAppState.java11
-rw-r--r--src/com/android/launcher3/LauncherFiles.java3
-rw-r--r--src/com/android/launcher3/LauncherModel.java313
-rw-r--r--src/com/android/launcher3/SearchDropTargetBar.java15
-rw-r--r--src/com/android/launcher3/ShortcutInfo.java1
-rw-r--r--src/com/android/launcher3/UninstallDropTarget.java17
-rw-r--r--src/com/android/launcher3/Workspace.java89
-rw-r--r--src/com/android/launcher3/compat/PackageInstallerCompat.java17
-rw-r--r--src/com/android/launcher3/compat/PackageInstallerCompatV16.java151
-rw-r--r--src/com/android/launcher3/compat/PackageInstallerCompatVL.java144
-rw-r--r--src/com/android/launcher3/util/LongArrayMap.java65
-rw-r--r--src/com/android/launcher3/widget/WidgetCell.java212
-rw-r--r--src/com/android/launcher3/widget/WidgetHostViewLoader.java197
-rw-r--r--src/com/android/launcher3/widget/WidgetsContainerView.java67
-rw-r--r--src/com/android/launcher3/widget/WidgetsListAdapter.java5
33 files changed, 792 insertions, 805 deletions
diff --git a/res/layout/search_drop_target_bar.xml b/res/layout/search_drop_target_bar.xml
index 9b0da1d4e..fe18edc84 100644
--- a/res/layout/search_drop_target_bar.xml
+++ b/res/layout/search_drop_target_bar.xml
@@ -45,26 +45,26 @@
style="@style/DropTargetButtonContainer"
android:layout_weight="1" >
- <!-- Uninstall target -->
+ <!-- Info target -->
- <com.android.launcher3.UninstallDropTarget
- android:id="@+id/uninstall_target_text"
+ <com.android.launcher3.InfoDropTarget
+ android:id="@+id/info_target_text"
style="@style/DropTargetButton"
- android:drawableStart="@drawable/uninstall_target_selector"
- android:text="@string/delete_target_uninstall_label" />
+ android:drawableStart="@drawable/info_target_selector"
+ android:text="@string/info_target_label" />
</FrameLayout>
<FrameLayout
style="@style/DropTargetButtonContainer"
android:layout_weight="1" >
- <!-- Info target -->
+ <!-- Uninstall target -->
- <com.android.launcher3.InfoDropTarget
- android:id="@+id/info_target_text"
+ <com.android.launcher3.UninstallDropTarget
+ android:id="@+id/uninstall_target_text"
style="@style/DropTargetButton"
- android:drawableStart="@drawable/info_target_selector"
- android:text="@string/info_target_label" />
+ android:drawableStart="@drawable/uninstall_target_selector"
+ android:text="@string/delete_target_uninstall_label" />
</FrameLayout>
</LinearLayout>
diff --git a/res/layout/widget_cell.xml b/res/layout/widget_cell.xml
index f53b74ef8..64ddea1ae 100644
--- a/res/layout/widget_cell.xml
+++ b/res/layout/widget_cell.xml
@@ -19,9 +19,11 @@
android:layout_width="@dimen/widget_preview_container_width"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:paddingTop="@dimen/widget_preview_padding_top"
+ android:layout_marginTop="@dimen/widget_preview_padding_top"
+ android:layout_marginLeft="8dp"
+ android:layout_marginBottom="8dp"
android:orientation="vertical"
- android:background="@drawable/focusable_view_bg"
+ android:background="@color/bubble_dark_background"
android:focusable="true">
<LinearLayout
@@ -45,7 +47,7 @@
android:fadingEdge="horizontal"
android:textColor="#FFFFFFFF"
- android:textSize="12sp"
+ android:textSize="16sp"
android:textAlignment="viewStart"
android:fontFamily="sans-serif-condensed"
android:shadowRadius="2.0"
@@ -61,9 +63,8 @@
android:layout_marginLeft="5dp"
android:layout_weight="0"
android:gravity="start"
-
android:textColor="#FFFFFFFF"
- android:textSize="12sp"
+ android:textSize="16sp"
android:textAlignment="viewStart"
android:fontFamily="sans-serif-condensed"
android:shadowRadius="2.0"
diff --git a/res/layout/widgets_list_row_view.xml b/res/layout/widgets_list_row_view.xml
index 017b45066..f94d02330 100644
--- a/res/layout/widgets_list_row_view.xml
+++ b/res/layout/widgets_list_row_view.xml
@@ -19,10 +19,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_marginTop="8dp"
- android:layout_marginBottom="8dp"
android:focusable="true"
android:background="@drawable/focusable_view_bg"
android:descendantFocusability="afterDescendants">
@@ -49,7 +45,6 @@
android:id="@+id/section"
android:layout_width="match_parent"
android:layout_height="@dimen/widget_section_height"
- android:paddingTop="8dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:singleLine="true"
@@ -80,6 +75,7 @@
android:id="@+id/widgets_scroll_container"
android:layout_width="match_parent"
android:layout_height="@dimen/widget_cell_height"
+ android:paddingLeft="40dp"
android:scrollbars="none" >
<LinearLayout
android:id="@+id/widgets_cell_list"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index cad60fbae..da1108271 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -80,7 +80,7 @@
<!-- Widget tray -->
<dimen name="widget_container_inset">8dp</dimen>
- <dimen name="widget_preview_size">140dp</dimen>
+ <dimen name="widget_preview_size">120dp</dimen>
<dimen name="widget_preview_padding_top">8dp</dimen>
<dimen name="widget_preview_label_vertical_padding">8dp</dimen>
<dimen name="widget_preview_label_horizontal_padding">8dp</dimen>
@@ -90,8 +90,8 @@
<dimen name="widget_section_icon_padding">8dp</dimen>
<!-- Equation: widget_preview_size + 2 * widget_preview_padding_horizontal -->
- <dimen name="widget_preview_container_width">156dp</dimen>
- <dimen name="widget_cell_height">160dp</dimen>
+ <dimen name="widget_preview_container_width">136dp</dimen>
+ <dimen name="widget_cell_height">150dp</dimen>
<!-- Padding applied to shortcut previews -->
<dimen name="shortcut_preview_padding_left">0dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 52306e30e..bfe7e36f2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -309,13 +309,13 @@ s -->
<!-- Strings for accessibility actions -->
<!-- Accessibility action to add an app to workspace. [CHAR_LIMIT=30] [DO NOT TRANSLATE] -->
- <string name="action_add_to_workspace">Add To Workspace</string>
+ <string name="action_add_to_workspace">Add to workspace</string>
<!-- Accessibility confirmation for item added to workspace [DO NOT TRANSLATE] -->
<string name="item_added_to_workspace">Item added to workspace</string>
<!-- Accessibility confirmation for item removed [DO NOT TRANSLATE] -->
- <string name="item_removed_from_workspace">Item removed from workspace</string>
+ <string name="item_removed">Item removed</string>
<!-- Accessibility action to move an item on the workspace. [CHAR_LIMIT=30] [DO NOT TRANSLATE] -->
<string name="action_move">Move Item</string>
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 240250750..3c698c014 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -349,7 +349,7 @@ public class AppWidgetResizeFrame extends FrameLayout {
mTmpRect.right, mTmpRect.bottom);
}
- static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) {
+ public static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) {
if (rect == null) {
rect = new Rect();
}
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 5b399087a..fb49df5df 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -26,18 +26,19 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.util.AttributeSet;
import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.widget.TextView;
-import com.android.launcher3.R;
import com.android.launcher3.util.Thunk;
/**
* Implements a DropTarget.
*/
-public abstract class ButtonDropTarget extends TextView implements DropTarget, DragController.DragListener {
+public abstract class ButtonDropTarget extends TextView
+ implements DropTarget, DragController.DragListener, OnClickListener {
private static int DRAG_VIEW_DROP_DURATION = 285;
@@ -256,4 +257,18 @@ public abstract class ButtonDropTarget extends TextView implements DropTarget, D
public void getLocationInDragLayer(int[] loc) {
mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
}
+
+ public void enableAccessibleDrag(boolean enable) {
+ setOnClickListener(enable ? this : null);
+ }
+
+ protected String getAccessibilityDropConfirmation() {
+ return null;
+ }
+
+ @Override
+ public void onClick(View v) {
+ LauncherAppState.getInstance().getAccessibilityDelegate()
+ .handleAccessibleDrop(this, null, getAccessibilityDropConfirmation());
+ }
}
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index f4afb954d..f08f25fb2 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -557,7 +557,7 @@ public class CellLayout extends ViewGroup {
Resources res = getContext().getResources();
View child = getChildAt(x, y);
if (child == null || child == dragInfo.item) {
- return res.getString(R.string.move_to_empty_cell, x, y);
+ return res.getString(R.string.move_to_empty_cell, x + 1, y + 1);
} else {
ItemInfo info = (ItemInfo) child.getTag();
if (info instanceof AppInfo || info instanceof ShortcutInfo) {
diff --git a/src/com/android/launcher3/DeferredHandler.java b/src/com/android/launcher3/DeferredHandler.java
index eb7c26a28..a43ab6723 100644
--- a/src/com/android/launcher3/DeferredHandler.java
+++ b/src/com/android/launcher3/DeferredHandler.java
@@ -20,12 +20,10 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
-import android.util.Pair;
import com.android.launcher3.util.Thunk;
import java.util.LinkedList;
-import java.util.ListIterator;
/**
* Queue of things to run on a looper thread. Items posted with {@link #post} will not
@@ -35,20 +33,18 @@ import java.util.ListIterator;
* This class is fifo.
*/
public class DeferredHandler {
- @Thunk LinkedList<Pair<Runnable, Integer>> mQueue = new LinkedList<Pair<Runnable, Integer>>();
+ @Thunk LinkedList<Runnable> mQueue = new LinkedList<>();
private MessageQueue mMessageQueue = Looper.myQueue();
private Impl mHandler = new Impl();
@Thunk class Impl extends Handler implements MessageQueue.IdleHandler {
public void handleMessage(Message msg) {
- Pair<Runnable, Integer> p;
Runnable r;
synchronized (mQueue) {
if (mQueue.size() == 0) {
return;
}
- p = mQueue.removeFirst();
- r = p.first;
+ r = mQueue.removeFirst();
}
r.run();
synchronized (mQueue) {
@@ -79,11 +75,8 @@ public class DeferredHandler {
/** Schedule runnable to run after everything that's on the queue right now. */
public void post(Runnable runnable) {
- post(runnable, 0);
- }
- public void post(Runnable runnable, int type) {
synchronized (mQueue) {
- mQueue.add(new Pair<Runnable, Integer>(runnable, type));
+ mQueue.add(runnable);
if (mQueue.size() == 1) {
scheduleNextLocked();
}
@@ -92,31 +85,10 @@ public class DeferredHandler {
/** Schedule runnable to run when the queue goes idle. */
public void postIdle(final Runnable runnable) {
- postIdle(runnable, 0);
- }
- public void postIdle(final Runnable runnable, int type) {
- post(new IdleRunnable(runnable), type);
- }
-
- public void cancelRunnable(Runnable runnable) {
- synchronized (mQueue) {
- while (mQueue.remove(runnable)) { }
- }
- }
- public void cancelAllRunnablesOfType(int type) {
- synchronized (mQueue) {
- ListIterator<Pair<Runnable, Integer>> iter = mQueue.listIterator();
- Pair<Runnable, Integer> p;
- while (iter.hasNext()) {
- p = iter.next();
- if (p.second == type) {
- iter.remove();
- }
- }
- }
+ post(new IdleRunnable(runnable));
}
- public void cancel() {
+ public void cancelAll() {
synchronized (mQueue) {
mQueue.clear();
}
@@ -124,20 +96,19 @@ public class DeferredHandler {
/** Runs all queued Runnables from the calling thread. */
public void flush() {
- LinkedList<Pair<Runnable, Integer>> queue = new LinkedList<Pair<Runnable, Integer>>();
+ LinkedList<Runnable> queue = new LinkedList<>();
synchronized (mQueue) {
queue.addAll(mQueue);
mQueue.clear();
}
- for (Pair<Runnable, Integer> p : queue) {
- p.first.run();
+ for (Runnable r : queue) {
+ r.run();
}
}
void scheduleNextLocked() {
if (mQueue.size() > 0) {
- Pair<Runnable, Integer> p = mQueue.getFirst();
- Runnable peek = p.first;
+ Runnable peek = mQueue.getFirst();
if (peek instanceof IdleRunnable) {
mMessageQueue.addIdleHandler(mHandler);
} else {
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index aa3e66c09..e741b9787 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -29,7 +29,6 @@ import android.view.ViewConfiguration;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
-import com.android.launcher3.R;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.widget.WidgetsContainerView;
@@ -59,13 +58,15 @@ public class DeleteDropTarget extends ButtonDropTarget {
setDrawable(R.drawable.remove_target_selector);
}
- public static boolean willAcceptDrop(DragSource source, Object info) {
- return (info instanceof ItemInfo) && source.supportsDeleteDropTarget();
+ public static boolean supportsDrop(Object info) {
+ return (info instanceof ShortcutInfo)
+ || (info instanceof LauncherAppWidgetInfo)
+ || (info instanceof FolderInfo);
}
@Override
protected boolean supportsDrop(DragSource source, Object info) {
- return willAcceptDrop(source, info);
+ return source.supportsDeleteDropTarget() && supportsDrop(info);
}
@Override
@@ -304,4 +305,9 @@ public class DeleteDropTarget extends ButtonDropTarget {
dragLayer.animateView(d.dragView, updateCb, duration, tInterpolator, onAnimationEndRunnable,
DragLayer.ANIMATION_END_DISAPPEAR, null);
}
+
+ @Override
+ protected String getAccessibilityDropConfirmation() {
+ return getResources().getString(R.string.item_removed);
+ }
}
diff --git a/src/com/android/launcher3/DragController.java b/src/com/android/launcher3/DragController.java
index b24608cb1..196886895 100644
--- a/src/com/android/launcher3/DragController.java
+++ b/src/com/android/launcher3/DragController.java
@@ -462,8 +462,7 @@ public class DragController {
mLastTouchUpTime = System.currentTimeMillis();
if (mDragging) {
PointF vec = isFlingingToDelete(mDragObject.dragSource);
- if (!DeleteDropTarget.willAcceptDrop(mDragObject.dragSource,
- mDragObject.dragInfo)) {
+ if (!DeleteDropTarget.supportsDrop(mDragObject.dragInfo)) {
vec = null;
}
if (vec != null) {
@@ -617,7 +616,7 @@ public class DragController {
if (mDragging) {
PointF vec = isFlingingToDelete(mDragObject.dragSource);
- if (!DeleteDropTarget.willAcceptDrop(mDragObject.dragSource, mDragObject.dragInfo)) {
+ if (!DeleteDropTarget.supportsDrop(mDragObject.dragInfo)) {
vec = null;
}
if (vec != null) {
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index c35ce944f..dff47c256 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -745,9 +745,18 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
replaceFolderWithFinalItem();
}
} else {
- rearrangeChildren();
// The drag failed, we need to return the item to the folder
+ ShortcutInfo info = (ShortcutInfo) d.dragInfo;
+ View icon = (mCurrentDragView != null && mCurrentDragView.getTag() == info)
+ ? mCurrentDragView : mContent.createNewView(info);
+ ArrayList<View> views = getItemsInReadingOrder();
+ views.add(info.rank, icon);
+ mContent.arrangeChildren(views, views.size());
+ mItemsInvalidated = true;
+
+ mSuppressOnAdd = true;
mFolderIcon.onDrop(d);
+ mSuppressOnAdd = false;
}
if (target != this) {
diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java
index 617489271..3f08f43c2 100644
--- a/src/com/android/launcher3/FolderPagedView.java
+++ b/src/com/android/launcher3/FolderPagedView.java
@@ -363,7 +363,7 @@ public class FolderPagedView extends PagedView {
}
@SuppressLint("InflateParams")
- private View createNewView(ShortcutInfo item) {
+ public View createNewView(ShortcutInfo item) {
final BubbleTextView textView = (BubbleTextView) mInflater.inflate(
R.layout.folder_application, null, false);
textView.applyFromShortcutInfo(item, mIconCache, false);
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 48b38f182..fd4571482 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -101,7 +101,7 @@ public class IconCache {
mIconDpi = activityManager.getLauncherLargeIconDensity();
mIconDb = new IconDB(context);
- mWorkerHandler = new Handler(LauncherModel.sWorkerThread.getLooper());
+ mWorkerHandler = new Handler(LauncherModel.getWorkerLooper());
}
private Drawable getFullResDefaultActivityIcon() {
@@ -388,16 +388,20 @@ public class IconCache {
return new IconLoadRequest(request, mWorkerHandler);
}
+ private Bitmap getNonNullIcon(CacheEntry entry, UserHandleCompat user) {
+ return entry.icon == null ? getDefaultIcon(user) : entry.icon;
+ }
+
/**
* Fill in "application" with the icon and label for "info."
*/
public synchronized void getTitleAndIcon(AppInfo application,
LauncherActivityInfoCompat info, boolean useLowResIcon) {
- CacheEntry entry = cacheLocked(application.componentName, info,
- info == null ? application.user : info.getUser(),
+ UserHandleCompat user = info == null ? application.user : info.getUser();
+ CacheEntry entry = cacheLocked(application.componentName, info, user,
false, useLowResIcon);
application.title = entry.title;
- application.iconBitmap = entry.icon;
+ application.iconBitmap = getNonNullIcon(entry, user);
application.contentDescription = entry.contentDescription;
application.usingLowResIcon = entry.isLowResIcon;
}
@@ -445,7 +449,7 @@ public class IconCache {
ShortcutInfo shortcutInfo, ComponentName component, LauncherActivityInfoCompat info,
UserHandleCompat user, boolean usePkgIcon, boolean useLowResIcon) {
CacheEntry entry = cacheLocked(component, info, user, usePkgIcon, useLowResIcon);
- shortcutInfo.setIcon(entry.icon);
+ shortcutInfo.setIcon(getNonNullIcon(entry, user));
shortcutInfo.title = entry.title;
shortcutInfo.usingFallbackIcon = isDefaultIcon(entry.icon, user);
shortcutInfo.usingLowResIcon = entry.isLowResIcon;
@@ -458,7 +462,7 @@ public class IconCache {
String packageName, UserHandleCompat user, boolean useLowResIcon,
PackageItemInfo infoOut) {
CacheEntry entry = getEntryForPackageLocked(packageName, user, useLowResIcon);
- infoOut.iconBitmap = entry.icon;
+ infoOut.iconBitmap = getNonNullIcon(entry, user);
infoOut.title = entry.title;
infoOut.usingLowResIcon = entry.isLowResIcon;
infoOut.contentDescription = entry.contentDescription;
diff --git a/src/com/android/launcher3/InfoDropTarget.java b/src/com/android/launcher3/InfoDropTarget.java
index e48640c93..f1ff48da3 100644
--- a/src/com/android/launcher3/InfoDropTarget.java
+++ b/src/com/android/launcher3/InfoDropTarget.java
@@ -21,7 +21,6 @@ import android.content.Context;
import android.provider.Settings;
import android.util.AttributeSet;
-import com.android.launcher3.R;
import com.android.launcher3.compat.UserHandleCompat;
public class InfoDropTarget extends ButtonDropTarget {
@@ -66,9 +65,13 @@ public class InfoDropTarget extends ButtonDropTarget {
@Override
protected boolean supportsDrop(DragSource source, Object info) {
- return source.supportsAppInfoDropTarget() &&
- Settings.Global.getInt(getContext().getContentResolver(),
- Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) == 1;
+ return source.supportsAppInfoDropTarget() && supportsDrop(getContext(), info);
+ }
+
+ public static boolean supportsDrop(Context context, Object info) {
+ return (Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) == 1) &&
+ (info instanceof AppInfo || info instanceof PendingAddItemInfo);
}
@Override
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index 0c69154aa..27dda6404 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -199,12 +199,8 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
}
}
- final boolean exists = LauncherModel.shortcutExists(context, pendingInfo.label,
- intent, pendingInfo.user);
- if (!exists) {
- // Generate a shortcut info to add into the model
- addShortcuts.add(pendingInfo.getShortcutInfo());
- }
+ // Generate a shortcut info to add into the model
+ addShortcuts.add(pendingInfo.getShortcutInfo());
}
// Add the new apps to the model and bind them
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 7364a9f20..8c920f0b8 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -98,12 +98,12 @@ import com.android.launcher3.PagedView.PageSwitchListener;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
-import com.android.launcher3.compat.PackageInstallerCompat;
-import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.LongArrayMap;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.widget.PendingAddWidgetInfo;
+import com.android.launcher3.widget.WidgetHostViewLoader;
import com.android.launcher3.widget.WidgetsContainerView;
import java.io.DataInputStream;
@@ -304,7 +304,7 @@ public class Launcher extends Activity
@Thunk static LocaleConfiguration sLocaleConfiguration = null;
- private static HashMap<Long, FolderInfo> sFolders = new HashMap<Long, FolderInfo>();
+ private static LongArrayMap<FolderInfo> sFolders = new LongArrayMap<>();
private View.OnTouchListener mHapticFeedbackTouchListener;
@@ -1060,9 +1060,6 @@ public class Launcher extends Activity
getWorkspace().reinflateWidgetsIfNecessary();
reinflateQSBIfNecessary();
- // Process any items that were added while Launcher was away.
- InstallShortcutReceiver.disableAndFlushInstallQueue(this);
-
if (DEBUG_RESUME_TIME) {
Log.d(TAG, "Time spent in onResume: " + (System.currentTimeMillis() - startTime));
}
@@ -1078,7 +1075,10 @@ public class Launcher extends Activity
mWorkspace.updateInteractionForState();
mWorkspace.onResume();
- PackageInstallerCompat.getInstance(this).onResume();
+ if (!isWorkspaceLoading()) {
+ // Process any items that were added while Launcher was away.
+ InstallShortcutReceiver.disableAndFlushInstallQueue(this);
+ }
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onResume();
@@ -1089,7 +1089,6 @@ public class Launcher extends Activity
protected void onPause() {
// Ensure that items added to Launcher are queued until Launcher returns
InstallShortcutReceiver.enableInstallQueue();
- PackageInstallerCompat.getInstance(this).onPause();
super.onPause();
mPaused = true;
@@ -2050,12 +2049,6 @@ public class Launcher extends Activity
TextKeyListener.getInstance().release();
- // Disconnect any of the callbacks and drawables associated with ItemInfos on the workspace
- // to prevent leaking Launcher activities on orientation change.
- if (mModel != null) {
- mModel.unbindItemInfosAndClearQueuedBindRunnables();
- }
-
getContentResolver().unregisterContentObserver(mWidgetObserver);
unregisterReceiver(mCloseSystemDialogsReceiver);
@@ -3895,7 +3888,7 @@ public class Launcher extends Activity
/**
* Implementation of the method from LauncherModel.Callbacks.
*/
- public void bindFolders(final HashMap<Long, FolderInfo> folders) {
+ public void bindFolders(final LongArrayMap<FolderInfo> folders) {
Runnable r = new Runnable() {
public void run() {
bindFolders(folders);
@@ -3904,8 +3897,7 @@ public class Launcher extends Activity
if (waitUntilResume(r)) {
return;
}
- sFolders.clear();
- sFolders.putAll(folders);
+ sFolders = folders.clone();
}
/**
@@ -3953,7 +3945,7 @@ public class Launcher extends Activity
pendingInfo.minSpanX = item.minSpanX;
pendingInfo.minSpanY = item.minSpanY;
Bundle options = null;
- // AppsCustomizePagedView.getDefaultOptionsForWidget(this, pendingInfo);
+ WidgetHostViewLoader.getDefaultOptionsForWidget(this, pendingInfo);
int newWidgetId = mAppWidgetHost.allocateAppWidgetId();
boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed(
@@ -4084,7 +4076,7 @@ public class Launcher extends Activity
sPendingAddItem = null;
}
- PackageInstallerCompat.getInstance(this).onFinishBind();
+ InstallShortcutReceiver.disableAndFlushInstallQueue(this);
if (mLauncherCallbacks != null) {
mLauncherCallbacks.finishBindingItems(false);
@@ -4236,22 +4228,17 @@ public class Launcher extends Activity
* Implementation of the method from LauncherModel.Callbacks.
*/
@Override
- public void updatePackageState(ArrayList<PackageInstallInfo> installInfo) {
- if (mWorkspace != null) {
- mWorkspace.updatePackageState(installInfo);
+ public void bindRestoreItemsChange(final HashSet<ItemInfo> updates) {
+ Runnable r = new Runnable() {
+ public void run() {
+ bindRestoreItemsChange(updates);
+ }
+ };
+ if (waitUntilResume(r)) {
+ return;
}
- }
- /**
- * Update the label and icon of all the icons in a package
- *
- * Implementation of the method from LauncherModel.Callbacks.
- */
- @Override
- public void updatePackageBadge(String packageName) {
- if (mWorkspace != null) {
- mWorkspace.updatePackageBadge(packageName, UserHandleCompat.myUserHandle());
- }
+ mWorkspace.updateRestoreItems(updates);
}
/**
diff --git a/src/com/android/launcher3/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/LauncherAccessibilityDelegate.java
index 8ba02ea5f..a60e16024 100644
--- a/src/com/android/launcher3/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/LauncherAccessibilityDelegate.java
@@ -1,16 +1,13 @@
package com.android.launcher3;
import android.annotation.TargetApi;
-import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
-import android.support.v4.view.accessibility.AccessibilityEventCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.text.TextUtils;
import android.util.SparseArray;
import android.view.View;
import android.view.View.AccessibilityDelegate;
-import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
@@ -68,18 +65,21 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate {
if (!(host.getTag() instanceof ItemInfo)) return;
ItemInfo item = (ItemInfo) host.getTag();
+ if (DeleteDropTarget.supportsDrop(item)) {
+ info.addAction(mActions.get(REMOVE));
+ }
+ if (UninstallDropTarget.supportsDrop(host.getContext(), item)) {
+ info.addAction(mActions.get(UNINSTALL));
+ }
+ if (InfoDropTarget.supportsDrop(host.getContext(), item)) {
+ info.addAction(mActions.get(INFO));
+ }
+
if ((item instanceof ShortcutInfo)
|| (item instanceof LauncherAppWidgetInfo)
|| (item instanceof FolderInfo)) {
- // Workspace shortcut / widget
- info.addAction(mActions.get(REMOVE));
info.addAction(mActions.get(MOVE));
- } else if ((item instanceof AppInfo) || (item instanceof PendingAddItemInfo)) {
- // App or Widget from customization tray
- if (item instanceof AppInfo) {
- info.addAction(mActions.get(UNINSTALL));
- }
- info.addAction(mActions.get(INFO));
+ } if ((item instanceof AppInfo) || (item instanceof PendingAddItemInfo)) {
info.addAction(mActions.get(ADD_TO_WORKSPACE));
}
}
@@ -94,10 +94,9 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate {
}
public boolean performAction(View host, ItemInfo item, int action) {
- Resources res = mLauncher.getResources();
if (action == REMOVE) {
if (DeleteDropTarget.removeWorkspaceOrFolderItem(mLauncher, item, host)) {
- announceConfirmation(R.string.item_removed_from_workspace);
+ announceConfirmation(R.string.item_removed);
return true;
}
return false;
@@ -105,9 +104,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate {
InfoDropTarget.startDetailsActivityForInfo(item, mLauncher);
return true;
} else if (action == UNINSTALL) {
- AppInfo info = (AppInfo) item;
- mLauncher.startApplicationUninstallActivity(info.componentName, info.flags, info.user);
- return true;
+ return UninstallDropTarget.startUninstallActivity(mLauncher, item);
} else if (action == MOVE) {
beginAccessibleDrag(host, item);
} else if (action == ADD_TO_WORKSPACE) {
@@ -158,19 +155,31 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate {
return mDragInfo;
}
- public void handleAccessibleDrop(CellLayout targetContainer, Rect dropLocation,
+ /**
+ * @param clickedTarget the actual view that was clicked
+ * @param dropLocation relative to {@param clickedTarget}. If provided, its center is used
+ * as the actual drop location otherwise the views center is used.
+ */
+ public void handleAccessibleDrop(View clickedTarget, Rect dropLocation,
String confirmation) {
if (!isInAccessibleDrag()) return;
int[] loc = new int[2];
- loc[0] = dropLocation.centerX();
- loc[1] = dropLocation.centerY();
+ if (dropLocation == null) {
+ loc[0] = clickedTarget.getWidth() / 2;
+ loc[1] = clickedTarget.getHeight() / 2;
+ } else {
+ loc[0] = dropLocation.centerX();
+ loc[1] = dropLocation.centerY();
+ }
- mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(targetContainer, loc);
+ mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(clickedTarget, loc);
mLauncher.getDragController().completeAccessibleDrag(loc);
endAccessibleDrag();
- announceConfirmation(confirmation);
+ if (!TextUtils.isEmpty(confirmation)) {
+ announceConfirmation(confirmation);
+ }
}
public void beginAccessibleDrag(View item, ItemInfo info) {
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 6e77d0628..7f31e4999 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -256,15 +256,4 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks {
public static boolean isDogfoodBuild() {
return getInstance().mBuildInfo.isDogfoodBuild();
}
-
- public void setPackageState(ArrayList<PackageInstallInfo> installInfo) {
- mModel.setPackageState(installInfo);
- }
-
- /**
- * Updates the icons and label of all icons for the provided package name.
- */
- public void updatePackageBadge(String packageName) {
- mModel.updatePackageBadge(packageName);
- }
}
diff --git a/src/com/android/launcher3/LauncherFiles.java b/src/com/android/launcher3/LauncherFiles.java
index 9dd8dc50c..03ec4bf7a 100644
--- a/src/com/android/launcher3/LauncherFiles.java
+++ b/src/com/android/launcher3/LauncherFiles.java
@@ -42,5 +42,6 @@ public class LauncherFiles {
// TODO: Delete these files on upgrade
public static final List<String> OBSOLETE_FILES = Collections.unmodifiableList(Arrays.asList(
"launches.log",
- "stats.log"));
+ "stats.log",
+ "com.android.launcher3.compat.PackageInstallerCompatV16.queue"));
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index e5561e219..d5dce51df 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -28,7 +28,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.Intent.ShortcutIconResource;
import android.content.IntentFilter;
-import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
@@ -42,6 +41,7 @@ import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.Looper;
import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
@@ -60,6 +60,7 @@ import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.LongArrayMap;
import com.android.launcher3.util.ManagedProfileHeuristic;
import com.android.launcher3.util.Thunk;
@@ -108,11 +109,6 @@ public class LauncherModel extends BroadcastReceiver
@Thunk LoaderTask mLoaderTask;
@Thunk boolean mIsLoaderTaskRunning;
- // Specific runnable types that are run on the main thread deferred handler, this allows us to
- // clear all queued binding runnables when the Launcher activity is destroyed.
- private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0;
- private static final int MAIN_THREAD_BINDING_RUNNABLE = 1;
-
private static final String MIGRATE_AUTHORITY = "com.android.launcher2.settings";
@Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
@@ -146,7 +142,7 @@ public class LauncherModel extends BroadcastReceiver
// sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by
// LauncherModel to their ids
- static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();
+ static final LongArrayMap<ItemInfo> sBgItemsIdMap = new LongArrayMap<>();
// sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts
// created by LauncherModel that are directly on the home screen (however, no widgets or
@@ -158,7 +154,7 @@ public class LauncherModel extends BroadcastReceiver
new ArrayList<LauncherAppWidgetInfo>();
// sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()
- static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();
+ static final LongArrayMap<FolderInfo> sBgFolders = new LongArrayMap<>();
// sBgWorkspaceScreens is the ordered set of workspace screens.
static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();
@@ -187,7 +183,7 @@ public class LauncherModel extends BroadcastReceiver
boolean forceAnimateIcons);
public void bindScreens(ArrayList<Long> orderedScreenIds);
public void bindAddScreens(ArrayList<Long> orderedScreenIds);
- public void bindFolders(HashMap<Long,FolderInfo> folders);
+ public void bindFolders(LongArrayMap<FolderInfo> folders);
public void finishBindingItems();
public void bindAppWidget(LauncherAppWidgetInfo info);
public void bindAllApplications(ArrayList<AppInfo> apps);
@@ -199,8 +195,7 @@ public class LauncherModel extends BroadcastReceiver
public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated,
ArrayList<ShortcutInfo> removed, UserHandleCompat user);
public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);
- public void updatePackageState(ArrayList<PackageInstallInfo> installInfo);
- public void updatePackageBadge(String packageName);
+ public void bindRestoreItemsChange(HashSet<ItemInfo> updates);
public void bindComponentsRemoved(ArrayList<String> packageNames,
ArrayList<AppInfo> appInfos, UserHandleCompat user, int reason);
public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);
@@ -256,9 +251,6 @@ public class LauncherModel extends BroadcastReceiver
/** Runs the specified runnable immediately if called from the main thread, otherwise it is
* posted on the main thread handler. */
@Thunk void runOnMainThread(Runnable r) {
- runOnMainThread(r, 0);
- }
- @Thunk void runOnMainThread(Runnable r, int type) {
if (sWorkerThread.getThreadId() == Process.myTid()) {
// If we are on the worker thread, post onto the main handler
mHandler.post(r);
@@ -282,30 +274,110 @@ public class LauncherModel extends BroadcastReceiver
return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ;
}
- public void setPackageState(final ArrayList<PackageInstallInfo> installInfo) {
- // Process the updated package state
- Runnable r = new Runnable() {
+ public void setPackageState(final PackageInstallInfo installInfo) {
+ Runnable updateRunnable = new Runnable() {
+
+ @Override
public void run() {
- Callbacks callbacks = getCallback();
- if (callbacks != null) {
- callbacks.updatePackageState(installInfo);
+ synchronized (sBgLock) {
+ final HashSet<ItemInfo> updates = new HashSet<>();
+
+ if (installInfo.state == PackageInstallerCompat.STATUS_INSTALLED) {
+ // Ignore install success events as they are handled by Package add events.
+ return;
+ }
+
+ for (ItemInfo info : sBgItemsIdMap) {
+ if (info instanceof ShortcutInfo) {
+ ShortcutInfo si = (ShortcutInfo) info;
+ ComponentName cn = si.getTargetComponent();
+ if (si.isPromise() && (cn != null)
+ && installInfo.packageName.equals(cn.getPackageName())) {
+ si.setInstallProgress(installInfo.progress);
+
+ if (installInfo.state == PackageInstallerCompat.STATUS_FAILED) {
+ // Mark this info as broken.
+ si.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;
+ }
+ updates.add(si);
+ }
+ }
+ }
+
+ for (LauncherAppWidgetInfo widget : sBgAppWidgets) {
+ if (widget.providerName.getPackageName().equals(installInfo.packageName)) {
+ widget.installProgress = installInfo.progress;
+ updates.add(widget);
+ }
+ }
+
+ if (!updates.isEmpty()) {
+ // Push changes to the callback.
+ Runnable r = new Runnable() {
+ public void run() {
+ Callbacks callbacks = getCallback();
+ if (callbacks != null) {
+ callbacks.bindRestoreItemsChange(updates);
+ }
+ }
+ };
+ mHandler.post(r);
+ }
}
}
};
- mHandler.post(r);
+ runOnWorkerThread(updateRunnable);
}
- public void updatePackageBadge(final String packageName) {
- // Process the updated package badge
- Runnable r = new Runnable() {
+ /**
+ * Updates the icons and label of all pending icons for the provided package name.
+ */
+ public void updateSessionDisplayInfo(final String packageName) {
+ Runnable updateRunnable = new Runnable() {
+
+ @Override
public void run() {
- Callbacks callbacks = getCallback();
- if (callbacks != null) {
- callbacks.updatePackageBadge(packageName);
+ synchronized (sBgLock) {
+ final ArrayList<ShortcutInfo> updates = new ArrayList<>();
+ final UserHandleCompat user = UserHandleCompat.myUserHandle();
+
+ for (ItemInfo info : sBgItemsIdMap) {
+ if (info instanceof ShortcutInfo) {
+ ShortcutInfo si = (ShortcutInfo) info;
+ ComponentName cn = si.getTargetComponent();
+ if (si.isPromise() && (cn != null)
+ && packageName.equals(cn.getPackageName())) {
+ if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {
+ // For auto install apps update the icon as well as label.
+ mIconCache.getTitleAndIcon(si,
+ si.promisedIntent, user,
+ si.shouldUseLowResIcon());
+ } else {
+ // Only update the icon for restored apps.
+ si.updateIcon(mIconCache);
+ }
+ updates.add(si);
+ }
+ }
+ }
+
+ 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);
+ }
}
}
};
- mHandler.post(r);
+ runOnWorkerThread(updateRunnable);
}
public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {
@@ -537,8 +609,7 @@ public class LauncherModel extends BroadcastReceiver
for (ItemInfo item : workspaceApps) {
if (!allowDuplicate && item instanceof ShortcutInfo) {
// Short-circuit this logic if the icon exists somewhere on the workspace
- if (shortcutExists(context, item.title.toString(),
- item.getIntent(), item.user)) {
+ if (shortcutExists(context, item.getIntent(), item.user)) {
continue;
}
}
@@ -600,7 +671,7 @@ public class LauncherModel extends BroadcastReceiver
runOnWorkerThread(r);
}
- public void unbindItemInfosAndClearQueuedBindRunnables() {
+ private void unbindItemInfosAndClearQueuedBindRunnables() {
if (sWorkerThread.getThreadId() == Process.myTid()) {
throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +
"main thread");
@@ -610,8 +681,9 @@ public class LauncherModel extends BroadcastReceiver
synchronized (mDeferredBindRunnables) {
mDeferredBindRunnables.clear();
}
- // Remove any queued bind runnables
- mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE);
+
+ // Remove any queued UI runnables
+ mHandler.cancelAll();
// Unbind all the workspace items
unbindWorkspaceItemsOnMainThread();
}
@@ -620,19 +692,15 @@ public class LauncherModel extends BroadcastReceiver
void unbindWorkspaceItemsOnMainThread() {
// Ensure that we don't use the same workspace items data structure on the main thread
// by making a copy of workspace items first.
- final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>();
- final ArrayList<ItemInfo> tmpAppWidgets = new ArrayList<ItemInfo>();
+ final ArrayList<ItemInfo> tmpItems = new ArrayList<ItemInfo>();
synchronized (sBgLock) {
- tmpWorkspaceItems.addAll(sBgWorkspaceItems);
- tmpAppWidgets.addAll(sBgAppWidgets);
+ tmpItems.addAll(sBgWorkspaceItems);
+ tmpItems.addAll(sBgAppWidgets);
}
Runnable r = new Runnable() {
@Override
public void run() {
- for (ItemInfo item : tmpWorkspaceItems) {
- item.unbind();
- }
- for (ItemInfo item : tmpAppWidgets) {
+ for (ItemInfo item : tmpItems) {
item.unbind();
}
}
@@ -904,47 +972,48 @@ public class LauncherModel extends BroadcastReceiver
}
/**
- * Returns true if the shortcuts already exists in the database.
- * we identify a shortcut by its title and intent.
+ * Returns true if the shortcuts already exists on the workspace. This must be called after
+ * the workspace has been loaded. We identify a shortcut by its intent.
+ * TODO: Throw exception is above condition is not met.
*/
- static boolean shortcutExists(Context context, String title, Intent intent,
- UserHandleCompat user) {
- final ContentResolver cr = context.getContentResolver();
+ @Thunk static boolean shortcutExists(Context context, Intent intent, UserHandleCompat user) {
final Intent intentWithPkg, intentWithoutPkg;
-
+ final String packageName;
if (intent.getComponent() != null) {
// If component is not null, an intent with null package will produce
// the same result and should also be a match.
+ packageName = intent.getComponent().getPackageName();
if (intent.getPackage() != null) {
intentWithPkg = intent;
intentWithoutPkg = new Intent(intent).setPackage(null);
} else {
- intentWithPkg = new Intent(intent).setPackage(
- intent.getComponent().getPackageName());
+ intentWithPkg = new Intent(intent).setPackage(packageName);
intentWithoutPkg = intent;
}
} else {
intentWithPkg = intent;
intentWithoutPkg = intent;
+ packageName = intent.getPackage();
}
- String userSerial = Long.toString(UserManagerCompat.getInstance(context)
- .getSerialNumberForUser(user));
- Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
- new String[] { "title", "intent", "profileId" },
- "title=? and (intent=? or intent=?) and profileId=?",
- new String[] { title, intentWithPkg.toUri(0), intentWithoutPkg.toUri(0), userSerial },
- null);
- try {
- return c.moveToFirst();
- } finally {
- c.close();
+
+ synchronized (sBgLock) {
+ for (ItemInfo item : sBgItemsIdMap) {
+ if (item instanceof ShortcutInfo) {
+ ShortcutInfo info = (ShortcutInfo) item;
+ if (intentWithPkg.equals(info.getIntent())
+ || intentWithoutPkg.equals(info.getIntent())) {
+ return true;
+ }
+ }
+ }
}
+ return false;
}
/**
* Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.
*/
- FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {
+ FolderInfo getFolderById(Context context, LongArrayMap<FolderInfo> folderList, long id) {
final ContentResolver cr = context.getContentResolver();
Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,
"_id=? and (itemType=? or itemType=?)",
@@ -1064,7 +1133,7 @@ public class LauncherModel extends BroadcastReceiver
return cn.getPackageName().equals(pn) && info.user.equals(user);
}
};
- return filterItemInfos(sBgItemsIdMap.values(), filter);
+ return filterItemInfos(sBgItemsIdMap, filter);
}
/**
@@ -1104,7 +1173,7 @@ public class LauncherModel extends BroadcastReceiver
switch (item.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
sBgFolders.remove(item.id);
- for (ItemInfo info: sBgItemsIdMap.values()) {
+ for (ItemInfo info: sBgItemsIdMap) {
if (info.container == item.id) {
// We are deleting a folder which still contains items that
// think they are contained by that folder.
@@ -1217,6 +1286,9 @@ public class LauncherModel extends BroadcastReceiver
*/
public void initialize(Callbacks callbacks) {
synchronized (mLock) {
+ // Disconnect any of the callbacks and drawables associated with ItemInfos on the
+ // workspace to prevent leaking Launcher activities on orientation change.
+ unbindItemInfosAndClearQueuedBindRunnables();
mCallbacks = new WeakReference<Callbacks>(callbacks);
}
}
@@ -1366,6 +1438,8 @@ public class LauncherModel extends BroadcastReceiver
}
public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {
+ // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems
+ InstallShortcutReceiver.enableInstallQueue();
synchronized (mLock) {
if (DEBUG_LOADERS) {
Log.d(TAG, "startLoader isLaunching=" + isLaunching);
@@ -1404,7 +1478,7 @@ public class LauncherModel extends BroadcastReceiver
mDeferredBindRunnables.clear();
}
for (final Runnable r : deferredBindRunnables) {
- mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE);
+ mHandler.post(r);
}
}
}
@@ -1676,7 +1750,7 @@ public class LauncherModel extends BroadcastReceiver
}
// check & update map of what's occupied; used to discard overlapping/invalid items
- private boolean checkItemPlacement(HashMap<Long, ItemInfo[][]> occupied, ItemInfo item) {
+ private boolean checkItemPlacement(LongArrayMap<ItemInfo[][]> occupied, ItemInfo item) {
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
final int countX = (int) grid.numColumns;
@@ -1812,7 +1886,7 @@ public class LauncherModel extends BroadcastReceiver
synchronized (sBgLock) {
clearSBgDataStructures();
- final HashSet<String> installingPkgs = PackageInstallerCompat
+ final HashMap<String, Integer> installingPkgs = PackageInstallerCompat
.getInstance(mContext).updateAndGetActiveSessionCache();
final ArrayList<Long> itemsToRemove = new ArrayList<Long>();
@@ -1824,7 +1898,7 @@ public class LauncherModel extends BroadcastReceiver
// +1 for the hotseat (it can be larger than the workspace)
// Load workspace in reverse order to ensure that latest items are loaded first (and
// before any earlier duplicates)
- final HashMap<Long, ItemInfo[][]> occupied = new HashMap<Long, ItemInfo[][]>();
+ final LongArrayMap<ItemInfo[][]> occupied = new LongArrayMap<>();
try {
final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
@@ -1951,7 +2025,7 @@ public class LauncherModel extends BroadcastReceiver
if ((promiseType & ShortcutInfo.FLAG_RESTORE_STARTED) != 0) {
// Restore has started once.
- } else if (installingPkgs.contains(cn.getPackageName())) {
+ } else if (installingPkgs.containsKey(cn.getPackageName())) {
// App restore has started. Update the flag
promiseType |= ShortcutInfo.FLAG_RESTORE_STARTED;
ContentValues values = new ContentValues();
@@ -2093,6 +2167,18 @@ public class LauncherModel extends BroadcastReceiver
break;
}
+ if (restored) {
+ ComponentName cn = info.getTargetComponent();
+ if (cn != null) {
+ Integer progress = installingPkgs.get(cn.getPackageName());
+ if (progress != null) {
+ info.setInstallProgress(progress);
+ } else {
+ info.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;
+ }
+ }
+ }
+
switch (container) {
case LauncherSettings.Favorites.CONTAINER_DESKTOP:
case LauncherSettings.Favorites.CONTAINER_HOTSEAT:
@@ -2220,10 +2306,11 @@ public class LauncherModel extends BroadcastReceiver
appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
component);
appWidgetInfo.restoreStatus = restoreStatus;
+ Integer installProgress = installingPkgs.get(component.getPackageName());
if ((restoreStatus & LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) != 0) {
// Restore has started once.
- } else if (installingPkgs.contains(component.getPackageName())) {
+ } else if (installProgress != null) {
// App restore has started. Update the flag
appWidgetInfo.restoreStatus |=
LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
@@ -2233,6 +2320,9 @@ public class LauncherModel extends BroadcastReceiver
itemsToRemove.add(id);
continue;
}
+
+ appWidgetInfo.installProgress =
+ installProgress == null ? 0 : installProgress;
}
appWidgetInfo.id = id;
@@ -2347,7 +2437,7 @@ public class LauncherModel extends BroadcastReceiver
// Remove any empty screens
ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);
- for (ItemInfo item: sBgItemsIdMap.values()) {
+ for (ItemInfo item: sBgItemsIdMap) {
long screenId = item.screenId;
if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
unusedScreens.contains(screenId)) {
@@ -2372,14 +2462,13 @@ public class LauncherModel extends BroadcastReceiver
for (int y = 0; y < countY; y++) {
String line = "";
- Iterator<Long> iter = occupied.keySet().iterator();
- while (iter.hasNext()) {
- long screenId = iter.next();
+ for (int i = 0; i < nScreens; i++) {
+ long screenId = occupied.keyAt(i);
if (screenId > 0) {
line += " | ";
}
+ ItemInfo[][] screen = occupied.valueAt(i);
for (int x = 0; x < countX; x++) {
- ItemInfo[][] screen = occupied.get(screenId);
if (x < screen.length && y < screen[x].length) {
line += (screen[x][y] != null) ? "#" : ".";
} else {
@@ -2470,14 +2559,17 @@ public class LauncherModel extends BroadcastReceiver
/** Filters the set of folders which are on the specified screen. */
private void filterCurrentFolders(long currentScreenId,
- HashMap<Long, ItemInfo> itemsIdMap,
- HashMap<Long, FolderInfo> folders,
- HashMap<Long, FolderInfo> currentScreenFolders,
- HashMap<Long, FolderInfo> otherScreenFolders) {
+ LongArrayMap<ItemInfo> itemsIdMap,
+ LongArrayMap<FolderInfo> folders,
+ LongArrayMap<FolderInfo> currentScreenFolders,
+ LongArrayMap<FolderInfo> otherScreenFolders) {
+
+ int total = folders.size();
+ for (int i = 0; i < total; i++) {
+ long id = folders.keyAt(i);
+ FolderInfo folder = folders.valueAt(i);
- for (long id : folders.keySet()) {
ItemInfo info = itemsIdMap.get(id);
- FolderInfo folder = folders.get(id);
if (info == null || folder == null) continue;
if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
info.screenId == currentScreenId) {
@@ -2521,13 +2613,13 @@ public class LauncherModel extends BroadcastReceiver
}
}
};
- runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+ runOnMainThread(r);
}
private void bindWorkspaceItems(final Callbacks oldCallbacks,
final ArrayList<ItemInfo> workspaceItems,
final ArrayList<LauncherAppWidgetInfo> appWidgets,
- final HashMap<Long, FolderInfo> folders,
+ final LongArrayMap<FolderInfo> folders,
ArrayList<Runnable> deferredBindRunnables) {
final boolean postOnMainThread = (deferredBindRunnables != null);
@@ -2552,7 +2644,7 @@ public class LauncherModel extends BroadcastReceiver
deferredBindRunnables.add(r);
}
} else {
- runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+ runOnMainThread(r);
}
}
@@ -2571,7 +2663,7 @@ public class LauncherModel extends BroadcastReceiver
deferredBindRunnables.add(r);
}
} else {
- runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+ runOnMainThread(r);
}
}
@@ -2590,7 +2682,7 @@ public class LauncherModel extends BroadcastReceiver
if (postOnMainThread) {
deferredBindRunnables.add(r);
} else {
- runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+ runOnMainThread(r);
}
}
}
@@ -2615,15 +2707,18 @@ public class LauncherModel extends BroadcastReceiver
ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();
ArrayList<LauncherAppWidgetInfo> appWidgets =
new ArrayList<LauncherAppWidgetInfo>();
- HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();
- HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();
ArrayList<Long> orderedScreenIds = new ArrayList<Long>();
+
+ final LongArrayMap<FolderInfo> folders;
+ final LongArrayMap<ItemInfo> itemsIdMap;
+
synchronized (sBgLock) {
workspaceItems.addAll(sBgWorkspaceItems);
appWidgets.addAll(sBgAppWidgets);
- folders.putAll(sBgFolders);
- itemsIdMap.putAll(sBgItemsIdMap);
orderedScreenIds.addAll(sBgWorkspaceScreens);
+
+ folders = sBgFolders.clone();
+ itemsIdMap = sBgItemsIdMap.clone();
}
final boolean isLoadingSynchronously =
@@ -2649,8 +2744,8 @@ public class LauncherModel extends BroadcastReceiver
new ArrayList<LauncherAppWidgetInfo>();
ArrayList<LauncherAppWidgetInfo> otherAppWidgets =
new ArrayList<LauncherAppWidgetInfo>();
- HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();
- HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();
+ LongArrayMap<FolderInfo> currentFolders = new LongArrayMap<>();
+ LongArrayMap<FolderInfo> otherFolders = new LongArrayMap<>();
filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,
otherWorkspaceItems);
@@ -2670,7 +2765,7 @@ public class LauncherModel extends BroadcastReceiver
}
}
};
- runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+ runOnMainThread(r);
bindWorkspaceScreens(oldCallbacks, orderedScreenIds);
@@ -2686,7 +2781,7 @@ public class LauncherModel extends BroadcastReceiver
}
}
};
- runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+ runOnMainThread(r);
}
// Load all the remaining pages (if we are loading synchronously, we want to defer this
@@ -2719,7 +2814,7 @@ public class LauncherModel extends BroadcastReceiver
mDeferredBindRunnables.add(r);
}
} else {
- runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+ runOnMainThread(r);
}
}
@@ -2790,8 +2885,6 @@ public class LauncherModel extends BroadcastReceiver
// Clear the list of apps
mBgAllAppsList.clear();
- SharedPreferences prefs = mContext.getSharedPreferences(
- LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);
for (UserHandleCompat user : profiles) {
// Query for the set of apps
final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
@@ -2815,7 +2908,7 @@ public class LauncherModel extends BroadcastReceiver
if (!updatedPackages.isEmpty()) {
final ArrayList<ShortcutInfo> updates = new ArrayList<ShortcutInfo>();
synchronized (sBgLock) {
- for (ItemInfo info : sBgItemsIdMap.values()) {
+ for (ItemInfo info : sBgItemsIdMap) {
if (info instanceof ShortcutInfo && user.equals(info.user)
&& info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
ShortcutInfo si = (ShortcutInfo) info;
@@ -3064,7 +3157,7 @@ public class LauncherModel extends BroadcastReceiver
HashSet<String> packageSet = new HashSet<String>(Arrays.asList(packages));
synchronized (sBgLock) {
- for (ItemInfo info : sBgItemsIdMap.values()) {
+ for (ItemInfo info : sBgItemsIdMap) {
if (info instanceof ShortcutInfo && mUser.equals(info.user)) {
ShortcutInfo si = (ShortcutInfo) info;
boolean infoUpdated = false;
@@ -3112,15 +3205,13 @@ public class LauncherModel extends BroadcastReceiver
}
// Restore the shortcut.
- si.intent = si.promisedIntent;
- si.promisedIntent = null;
- si.status &= ~ShortcutInfo.FLAG_RESTORED_ICON
- & ~ShortcutInfo.FLAG_AUTOINTALL_ICON
- & ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;
if (appInfo != null) {
si.flags = appInfo.flags;
}
+ si.intent = si.promisedIntent;
+ si.promisedIntent = null;
+ si.status = ShortcutInfo.DEFAULT;
infoUpdated = true;
si.updateIcon(mIconCache);
}
@@ -3353,12 +3444,10 @@ public class LauncherModel extends BroadcastReceiver
if (!TextUtils.isEmpty(title)) {
info.title = title;
}
- info.status = ShortcutInfo.FLAG_RESTORED_ICON;
} else if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {
if (TextUtils.isEmpty(info.title)) {
info.title = (cursor != null) ? cursor.getString(titleIndex) : "";
}
- info.status = ShortcutInfo.FLAG_AUTOINTALL_ICON;
} else {
throw new InvalidParameterException("Invalid restoreType " + promiseType);
}
@@ -3367,6 +3456,7 @@ public class LauncherModel extends BroadcastReceiver
info.title.toString(), info.user);
info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
info.promisedIntent = intent;
+ info.status = promiseType;
return info;
}
@@ -3443,7 +3533,7 @@ public class LauncherModel extends BroadcastReceiver
return info;
}
- static ArrayList<ItemInfo> filterItemInfos(Collection<ItemInfo> infos,
+ static ArrayList<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos,
ItemInfoFilter f) {
HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();
for (ItemInfo i : infos) {
@@ -3484,7 +3574,7 @@ public class LauncherModel extends BroadcastReceiver
}
}
};
- return filterItemInfos(sBgItemsIdMap.values(), filter);
+ return filterItemInfos(sBgItemsIdMap, filter);
}
/**
@@ -3594,7 +3684,7 @@ public class LauncherModel extends BroadcastReceiver
* Return an existing FolderInfo object if we have encountered this ID previously,
* or make a new one.
*/
- @Thunk static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {
+ @Thunk static FolderInfo findOrMakeFolder(LongArrayMap<FolderInfo> folders, long id) {
// See if a placeholder was created for us already
FolderInfo folderInfo = folders.get(id);
if (folderInfo == null) {
@@ -3669,4 +3759,11 @@ public class LauncherModel extends BroadcastReceiver
return sBgFolders.get(folderId);
}
}
+
+ /**
+ * @return the looper for the worker thread which can be used to start background tasks.
+ */
+ public static Looper getWorkerLooper() {
+ return sWorkerThread.getLooper();
+ }
}
diff --git a/src/com/android/launcher3/SearchDropTargetBar.java b/src/com/android/launcher3/SearchDropTargetBar.java
index af8bc7580..44a76b73b 100644
--- a/src/com/android/launcher3/SearchDropTargetBar.java
+++ b/src/com/android/launcher3/SearchDropTargetBar.java
@@ -180,6 +180,9 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
prepareStartAnimation(mDropTargetBar);
mShowDropTargetBarAnim.start();
hideSearchBar(true);
+ if (mQSBSearchBar != null) {
+ mQSBSearchBar.setVisibility(View.GONE);
+ }
}
/**
@@ -190,6 +193,9 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
prepareStartAnimation(mDropTargetBar);
mShowDropTargetBarAnim.reverse();
showSearchBar(true);
+ if (mQSBSearchBar != null) {
+ mQSBSearchBar.setVisibility(View.VISIBLE);
+ }
}
/*
@@ -228,4 +234,13 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
return null;
}
}
+
+ public void enableAccessibleDrag(boolean enable) {
+ if (mQSBSearchBar != null) {
+ mQSBSearchBar.setVisibility(enable ? View.GONE : View.VISIBLE);
+ }
+ mInfoDropTarget.enableAccessibleDrag(enable);
+ mDeleteDropTarget.enableAccessibleDrag(enable);
+ mUninstallDropTarget.enableAccessibleDrag(enable);
+ }
}
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index 5bef845bb..6354fcd28 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -214,6 +214,7 @@ public class ShortcutInfo extends ItemInfo {
String uri = promisedIntent != null ? promisedIntent.toUri(0)
: (intent != null ? intent.toUri(0) : null);
values.put(LauncherSettings.BaseLauncherColumns.INTENT, uri);
+ values.put(LauncherSettings.Favorites.RESTORED, status);
if (customIcon) {
values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE,
diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/UninstallDropTarget.java
index 4a7fffeb2..4c52d7e0f 100644
--- a/src/com/android/launcher3/UninstallDropTarget.java
+++ b/src/com/android/launcher3/UninstallDropTarget.java
@@ -33,9 +33,12 @@ public class UninstallDropTarget extends ButtonDropTarget {
@Override
protected boolean supportsDrop(DragSource source, Object info) {
+ return supportsDrop(getContext(), info);
+ }
+
+ public static boolean supportsDrop(Context context, Object info) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
- UserManager userManager = (UserManager)
- getContext().getSystemService(Context.USER_SERVICE);
+ UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
Bundle restrictions = userManager.getUserRestrictions();
if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false)
|| restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false)) {
@@ -78,8 +81,7 @@ public class UninstallDropTarget extends ButtonDropTarget {
void completeDrop(final DragObject d) {
final Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(d.dragInfo);
final UserHandleCompat user = ((ItemInfo) d.dragInfo).user;
- if (mLauncher.startApplicationUninstallActivity(
- componentInfo.first, componentInfo.second, user)) {
+ if (startUninstallActivity(mLauncher, d.dragInfo)) {
final Runnable checkIfUninstallWasSuccess = new Runnable() {
@Override
@@ -96,6 +98,13 @@ public class UninstallDropTarget extends ButtonDropTarget {
}
}
+ public static boolean startUninstallActivity(Launcher launcher, Object info) {
+ final Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(info);
+ final UserHandleCompat user = ((ItemInfo) info).user;
+ return launcher.startApplicationUninstallActivity(
+ componentInfo.first, componentInfo.second, user);
+ }
+
@Thunk void sendUninstallResult(DragSource target, boolean result) {
if (target instanceof UninstallSource) {
((UninstallSource) target).onUninstallActivityReturned(result);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 9e680fb82..2efd20739 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -62,9 +62,8 @@ import com.android.launcher3.Launcher.CustomContentCallbacks;
import com.android.launcher3.Launcher.LauncherOverlay;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.UninstallDropTarget.UninstallSource;
-import com.android.launcher3.compat.PackageInstallerCompat;
-import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.util.LongArrayMap;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.WallpaperUtils;
import com.android.launcher3.widget.PendingAddShortcutInfo;
@@ -73,7 +72,6 @@ import com.android.launcher3.widget.PendingAddWidgetInfo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -122,7 +120,7 @@ public class Workspace extends SmoothPagedView
final static long EXTRA_EMPTY_SCREEN_ID = -201;
private final static long CUSTOM_CONTENT_SCREEN_ID = -301;
- @Thunk HashMap<Long, CellLayout> mWorkspaceScreens = new HashMap<Long, CellLayout>();
+ @Thunk LongArrayMap<CellLayout> mWorkspaceScreens = new LongArrayMap<>();
@Thunk ArrayList<Long> mScreenOrder = new ArrayList<Long>();
@Thunk Runnable mRemoveEmptyScreenRunnable;
@@ -836,12 +834,9 @@ public class Workspace extends SmoothPagedView
}
public long getIdForScreen(CellLayout layout) {
- Iterator<Long> iter = mWorkspaceScreens.keySet().iterator();
- while (iter.hasNext()) {
- long id = iter.next();
- if (mWorkspaceScreens.get(id) == layout) {
- return id;
- }
+ int index = mWorkspaceScreens.indexOfValue(layout);
+ if (index != -1) {
+ return mWorkspaceScreens.keyAt(index);
}
return -1;
}
@@ -876,8 +871,10 @@ public class Workspace extends SmoothPagedView
int currentPage = getNextPage();
ArrayList<Long> removeScreens = new ArrayList<Long>();
- for (Long id: mWorkspaceScreens.keySet()) {
- CellLayout cl = mWorkspaceScreens.get(id);
+ int total = mWorkspaceScreens.size();
+ for (int i = 0; i < total; i++) {
+ long id = mWorkspaceScreens.keyAt(i);
+ CellLayout cl = mWorkspaceScreens.valueAt(i);
if (id >= 0 && cl.getShortcutsAndWidgets().getChildCount() == 0) {
removeScreens.add(id);
}
@@ -1617,6 +1614,7 @@ public class Workspace extends SmoothPagedView
// Reset our click listener
setOnClickListener(mLauncher);
}
+ mLauncher.getSearchBar().enableAccessibleDrag(enable);
mLauncher.getHotseat().getLayout().enableAccessibleDrag(enable);
}
@@ -4358,32 +4356,17 @@ public class Workspace extends SmoothPagedView
removeItemsByPackageName(packages, user);
}
- public void updatePackageBadge(final String packageName, final UserHandleCompat user) {
+ public void updateRestoreItems(final HashSet<ItemInfo> updates) {
mapOverItems(MAP_RECURSE, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v, View parent) {
- if (info instanceof ShortcutInfo && v instanceof BubbleTextView) {
- ShortcutInfo shortcutInfo = (ShortcutInfo) info;
- ComponentName cn = shortcutInfo.getTargetComponent();
- if (user.equals(shortcutInfo.user) && cn != null
- && shortcutInfo.isPromise()
- && packageName.equals(cn.getPackageName())) {
- if (shortcutInfo.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {
- // For auto install apps update the icon as well as label.
- mIconCache.getTitleAndIcon(shortcutInfo,
- shortcutInfo.promisedIntent, user,
- shortcutInfo.shouldUseLowResIcon());
- } else {
- // Only update the icon for restored apps.
- shortcutInfo.updateIcon(mIconCache);
- }
- BubbleTextView shortcut = (BubbleTextView) v;
- shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache, true, false);
-
- if (parent != null) {
- parent.invalidate();
- }
- }
+ if (info instanceof ShortcutInfo && v instanceof BubbleTextView
+ && updates.contains(info)) {
+ ((BubbleTextView) v).applyState(false);
+ } else if (v instanceof PendingAppWidgetHostView
+ && info instanceof LauncherAppWidgetInfo
+ && updates.contains(info)) {
+ ((PendingAppWidgetHostView) v).applyState();
}
// process all the shortcuts
return false;
@@ -4391,42 +4374,6 @@ public class Workspace extends SmoothPagedView
});
}
- public void updatePackageState(ArrayList<PackageInstallInfo> installInfos) {
- for (final PackageInstallInfo installInfo : installInfos) {
- if (installInfo.state == PackageInstallerCompat.STATUS_INSTALLED) {
- continue;
- }
-
- mapOverItems(MAP_RECURSE, new ItemOperator() {
- @Override
- public boolean evaluate(ItemInfo info, View v, View parent) {
- if (info instanceof ShortcutInfo && v instanceof BubbleTextView) {
- ShortcutInfo si = (ShortcutInfo) info;
- ComponentName cn = si.getTargetComponent();
- if (si.isPromise() && (cn != null)
- && installInfo.packageName.equals(cn.getPackageName())) {
- si.setInstallProgress(installInfo.progress);
- if (installInfo.state == PackageInstallerCompat.STATUS_FAILED) {
- // Mark this info as broken.
- si.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;
- }
- ((BubbleTextView)v).applyState(false);
- }
- } else if (v instanceof PendingAppWidgetHostView
- && info instanceof LauncherAppWidgetInfo
- && ((LauncherAppWidgetInfo) info).providerName.getPackageName()
- .equals(installInfo.packageName)) {
- ((LauncherAppWidgetInfo) info).installProgress = installInfo.progress;
- ((PendingAppWidgetHostView) v).applyState();
- }
-
- // process all the shortcuts
- return false;
- }
- });
- }
- }
-
void widgetsRestored(ArrayList<LauncherAppWidgetInfo> changedInfo) {
if (!changedInfo.isEmpty()) {
DeferredWidgetRefresh widgetRefresh = new DeferredWidgetRefresh(changedInfo,
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompat.java b/src/com/android/launcher3/compat/PackageInstallerCompat.java
index 0eb8754e8..c49908328 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompat.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompat.java
@@ -20,7 +20,7 @@ import android.content.Context;
import com.android.launcher3.Utilities;
-import java.util.HashSet;
+import java.util.HashMap;
public abstract class PackageInstallerCompat {
@@ -37,25 +37,20 @@ public abstract class PackageInstallerCompat {
if (Utilities.isLmpOrAbove()) {
sInstance = new PackageInstallerCompatVL(context);
} else {
- sInstance = new PackageInstallerCompatV16(context) { };
+ sInstance = new PackageInstallerCompatV16();
}
}
return sInstance;
}
}
- public abstract HashSet<String> updateAndGetActiveSessionCache();
-
- public abstract void onPause();
-
- public abstract void onResume();
-
- public abstract void onFinishBind();
+ /**
+ * @return a map of active installs to their progress
+ */
+ public abstract HashMap<String, Integer> updateAndGetActiveSessionCache();
public abstract void onStop();
- public abstract void recordPackageUpdate(String packageName, int state, int progress);
-
public static final class PackageInstallInfo {
public final String packageName;
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatV16.java b/src/com/android/launcher3/compat/PackageInstallerCompatV16.java
index 1910d22ae..654e34968 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompatV16.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompatV16.java
@@ -16,160 +16,17 @@
package com.android.launcher3.compat;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.launcher3.LauncherAppState;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.json.JSONStringer;
-import org.json.JSONTokener;
-
-import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.HashMap;
public class PackageInstallerCompatV16 extends PackageInstallerCompat {
- private static final String TAG = "PackageInstallerCompatV16";
- private static final boolean DEBUG = false;
-
- private static final String KEY_PROGRESS = "progress";
- private static final String KEY_STATE = "state";
-
- private static final String PREFS =
- "com.android.launcher3.compat.PackageInstallerCompatV16.queue";
-
- protected final SharedPreferences mPrefs;
-
- boolean mUseQueue;
- boolean mFinishedBind;
- boolean mReplayPending;
-
- PackageInstallerCompatV16(Context context) {
- mPrefs = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE);
- }
-
- @Override
- public void onPause() {
- mUseQueue = true;
- if (DEBUG) Log.d(TAG, "updates paused");
- }
-
- @Override
- public void onResume() {
- mUseQueue = false;
- if (mFinishedBind) {
- replayUpdates();
- }
- }
-
- @Override
- public void onFinishBind() {
- mFinishedBind = true;
- if (!mUseQueue) {
- replayUpdates();
- }
- }
+ PackageInstallerCompatV16() { }
@Override
public void onStop() { }
- private void replayUpdates() {
- if (DEBUG) Log.d(TAG, "updates resumed");
- LauncherAppState app = LauncherAppState.getInstanceNoCreate();
- if (app == null) {
- mReplayPending = true; // try again later
- if (DEBUG) Log.d(TAG, "app is null, delaying send");
- return;
- }
- mReplayPending = false;
- ArrayList<PackageInstallInfo> updates = new ArrayList<PackageInstallInfo>();
- for (String packageName: mPrefs.getAll().keySet()) {
- final String json = mPrefs.getString(packageName, null);
- if (!TextUtils.isEmpty(json)) {
- updates.add(infoFromJson(packageName, json));
- }
- }
- if (!updates.isEmpty()) {
- sendUpdate(app, updates);
- }
- }
-
- /**
- * This should be called by the implementations to register a package update.
- */
- @Override
- public synchronized void recordPackageUpdate(String packageName, int state, int progress) {
- SharedPreferences.Editor editor = mPrefs.edit();
- PackageInstallInfo installInfo = new PackageInstallInfo(packageName);
- installInfo.progress = progress;
- installInfo.state = state;
- if (state == STATUS_INSTALLED) {
- // no longer necessary to track this package
- editor.remove(packageName);
- if (DEBUG) Log.d(TAG, "no longer tracking " + packageName);
- } else {
- editor.putString(packageName, infoToJson(installInfo));
- if (DEBUG)
- Log.d(TAG, "saved state: " + infoToJson(installInfo)
- + " for package: " + packageName);
-
- }
- editor.commit();
-
- if (!mUseQueue) {
- if (mReplayPending) {
- replayUpdates();
- } else if (state != STATUS_INSTALLED) {
- LauncherAppState app = LauncherAppState.getInstanceNoCreate();
- ArrayList<PackageInstallInfo> update = new ArrayList<PackageInstallInfo>();
- update.add(installInfo);
- sendUpdate(app, update);
- }
- }
- }
-
- private void sendUpdate(LauncherAppState app, ArrayList<PackageInstallInfo> updates) {
- if (app == null) {
- mReplayPending = true; // try again later
- if (DEBUG) Log.d(TAG, "app is null, delaying send");
- } else {
- app.setPackageState(updates);
- }
- }
-
- private static PackageInstallInfo infoFromJson(String packageName, String json) {
- PackageInstallInfo info = new PackageInstallInfo(packageName);
- try {
- JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
- info.state = object.getInt(KEY_STATE);
- info.progress = object.getInt(KEY_PROGRESS);
- } catch (JSONException e) {
- Log.e(TAG, "failed to deserialize app state update", e);
- }
- return info;
- }
-
- private static String infoToJson(PackageInstallInfo info) {
- String value = null;
- try {
- JSONStringer json = new JSONStringer()
- .object()
- .key(KEY_STATE).value(info.state)
- .key(KEY_PROGRESS).value(info.progress)
- .endObject();
- value = json.toString();
- } catch (JSONException e) {
- Log.e(TAG, "failed to serialize app state update", e);
- }
- return value;
- }
-
@Override
- public HashSet<String> updateAndGetActiveSessionCache() {
- return new HashSet<String>();
+ public HashMap<String, Integer> updateAndGetActiveSessionCache() {
+ return new HashMap<>();
}
}
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
index d6d4b8287..395d5f9e2 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
@@ -21,63 +21,41 @@ import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionCallback;
import android.content.pm.PackageInstaller.SessionInfo;
import android.os.Handler;
-import android.util.Log;
import android.util.SparseArray;
import com.android.launcher3.IconCache;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel;
import com.android.launcher3.util.Thunk;
-import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.HashMap;
-public class PackageInstallerCompatVL extends PackageInstallerCompat implements Runnable {
+public class PackageInstallerCompatVL extends PackageInstallerCompat {
- private static final String TAG = "PackageInstallerCompatVL";
- private static final boolean DEBUG = false;
-
- // All updates to these sets must happen on the {@link #mWorker} thread.
- @Thunk final SparseArray<SessionInfo> mPendingReplays = new SparseArray<SessionInfo>();
- @Thunk final HashSet<String> mPendingBadgeUpdates = new HashSet<String>();
+ @Thunk final SparseArray<String> mActiveSessions = new SparseArray<>();
@Thunk final PackageInstaller mInstaller;
private final IconCache mCache;
private final Handler mWorker;
- private boolean mResumed;
- private boolean mBound;
-
PackageInstallerCompatVL(Context context) {
mInstaller = context.getPackageManager().getPackageInstaller();
LauncherAppState.setApplicationContext(context.getApplicationContext());
mCache = LauncherAppState.getInstance().getIconCache();
- mWorker = new Handler();
-
- mResumed = false;
- mBound = false;
+ mWorker = new Handler(LauncherModel.getWorkerLooper());
mInstaller.registerSessionCallback(mCallback, mWorker);
-
- // On start, send updates for all active sessions
- mWorker.post(new Runnable() {
-
- @Override
- public void run() {
- for (SessionInfo info : mInstaller.getAllSessions()) {
- mPendingReplays.append(info.getSessionId(), info);
- }
- }
- });
}
@Override
- public HashSet<String> updateAndGetActiveSessionCache() {
- HashSet<String> activePackages = new HashSet<String>();
+ public HashMap<String, Integer> updateAndGetActiveSessionCache() {
+ HashMap<String, Integer> activePackages = new HashMap<>();
UserHandleCompat user = UserHandleCompat.myUserHandle();
for (SessionInfo info : mInstaller.getAllSessions()) {
addSessionInfoToCahce(info, user);
if (info.getAppPackageName() != null) {
- activePackages.add(info.getAppPackageName());
+ activePackages.put(info.getAppPackageName(), (int) (info.getProgress() * 100));
+ mActiveSessions.put(info.getSessionId(), info.getAppPackageName());
}
}
return activePackages;
@@ -96,74 +74,10 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat implements
mInstaller.unregisterSessionCallback(mCallback);
}
- @Override
- public void onFinishBind() {
- mBound = true;
- mWorker.post(this);
- }
-
- @Override
- public void onPause() {
- mResumed = false;
- }
-
- @Override
- public void onResume() {
- mResumed = true;
- mWorker.post(this);
- }
-
- @Override
- public void recordPackageUpdate(String packageName, int state, int progress) {
- // No op
- }
-
- @Override
- public void run() {
- // Called on mWorker thread.
- replayUpdates(null);
- }
-
- @Thunk void replayUpdates(PackageInstallInfo newInfo) {
- if (DEBUG) Log.d(TAG, "updates resumed");
- if (!mResumed || !mBound) {
- // Not yet ready
- return;
- }
- if ((mPendingReplays.size() == 0) && (newInfo == null)) {
- // Nothing to update
- return;
- }
-
+ @Thunk void sendUpdate(PackageInstallInfo info) {
LauncherAppState app = LauncherAppState.getInstanceNoCreate();
- if (app == null) {
- // Try again later
- if (DEBUG) Log.d(TAG, "app is null, delaying send");
- return;
- }
-
- ArrayList<PackageInstallInfo> updates = new ArrayList<PackageInstallInfo>();
- if ((newInfo != null) && (newInfo.state != STATUS_INSTALLED)) {
- updates.add(newInfo);
- }
- for (int i = mPendingReplays.size() - 1; i >= 0; i--) {
- SessionInfo session = mPendingReplays.valueAt(i);
- if (session.getAppPackageName() != null) {
- updates.add(new PackageInstallInfo(session.getAppPackageName(),
- STATUS_INSTALLING,
- (int) (session.getProgress() * 100)));
- }
- }
- mPendingReplays.clear();
- if (!updates.isEmpty()) {
- app.setPackageState(updates);
- }
-
- if (!mPendingBadgeUpdates.isEmpty()) {
- for (String pkg : mPendingBadgeUpdates) {
- app.updatePackageBadge(pkg);
- }
- mPendingBadgeUpdates.clear();
+ if (app != null) {
+ app.getModel().setPackageState(info);
}
}
@@ -171,19 +85,18 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat implements
@Override
public void onCreated(int sessionId) {
- pushSessionBadgeToLauncher(sessionId);
+ pushSessionDisplayToLauncher(sessionId);
}
@Override
public void onFinished(int sessionId, boolean success) {
- mPendingReplays.remove(sessionId);
- SessionInfo session = mInstaller.getSessionInfo(sessionId);
- if ((session != null) && (session.getAppPackageName() != null)) {
- mPendingBadgeUpdates.remove(session.getAppPackageName());
- // Replay all updates with a one time update for this installed package. No
- // need to store this record for future updates, as the app list will get
- // refreshed on resume.
- replayUpdates(new PackageInstallInfo(session.getAppPackageName(),
+ // For a finished session, we can't get the session info. So use the
+ // packageName from our local cache.
+ String packageName = mActiveSessions.get(sessionId);
+ mActiveSessions.remove(sessionId);
+
+ if (packageName != null) {
+ sendUpdate(new PackageInstallInfo(packageName,
success ? STATUS_INSTALLED : STATUS_FAILED, 0));
}
}
@@ -192,8 +105,9 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat implements
public void onProgressChanged(int sessionId, float progress) {
SessionInfo session = mInstaller.getSessionInfo(sessionId);
if (session != null) {
- mPendingReplays.put(sessionId, session);
- replayUpdates(null);
+ sendUpdate(new PackageInstallInfo(session.getAppPackageName(),
+ STATUS_INSTALLING,
+ (int) (session.getProgress() * 100)));
}
}
@@ -202,18 +116,18 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat implements
@Override
public void onBadgingChanged(int sessionId) {
- pushSessionBadgeToLauncher(sessionId);
+ pushSessionDisplayToLauncher(sessionId);
}
- private void pushSessionBadgeToLauncher(int sessionId) {
+ private void pushSessionDisplayToLauncher(int sessionId) {
SessionInfo session = mInstaller.getSessionInfo(sessionId);
if (session != null) {
addSessionInfoToCahce(session, UserHandleCompat.myUserHandle());
- if (session.getAppPackageName() != null) {
- mPendingBadgeUpdates.add(session.getAppPackageName());
+ LauncherAppState app = LauncherAppState.getInstanceNoCreate();
+
+ if (app != null) {
+ app.getModel().updateSessionDisplayInfo(session.getAppPackageName());
}
- mPendingReplays.put(sessionId, session);
- replayUpdates(null);
}
}
};
diff --git a/src/com/android/launcher3/util/LongArrayMap.java b/src/com/android/launcher3/util/LongArrayMap.java
new file mode 100644
index 000000000..e3c96cd42
--- /dev/null
+++ b/src/com/android/launcher3/util/LongArrayMap.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 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.util.LongSparseArray;
+
+import java.util.Iterator;
+
+/**
+ * Extension of {@link LongSparseArray} with some utility methods.
+ */
+public class LongArrayMap<E> extends LongSparseArray<E> implements Iterable<E> {
+
+ public boolean containsKey(long key) {
+ return indexOfKey(key) >= 0;
+ }
+
+ public boolean isEmpty() {
+ return size() <= 0;
+ }
+
+ @Override
+ public LongArrayMap<E> clone() {
+ return (LongArrayMap<E>) super.clone();
+ }
+
+ @Override
+ public Iterator<E> iterator() {
+ return new ValueIterator();
+ }
+
+ private class ValueIterator implements Iterator<E> {
+
+ private int mNextIndex = 0;
+
+ @Override
+ public boolean hasNext() {
+ return mNextIndex < size();
+ }
+
+ @Override
+ public E next() {
+ return valueAt(mNextIndex ++);
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 1ae75c3cc..0bc7333ec 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -24,8 +24,6 @@ import android.graphics.Bitmap;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
-import android.util.TypedValue;
-import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLayoutChangeListener;
import android.widget.ImageView;
@@ -43,7 +41,7 @@ import com.android.launcher3.WidgetPreviewLoader.PreviewLoadRequest;
import com.android.launcher3.compat.AppWidgetManagerCompat;
/**
- * The linear layout used strictly for the widget tray.
+ * Represents the individual cell of the widget inside the widget tray.
*/
public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
@@ -53,14 +51,12 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
private static final int FADE_IN_DURATION_MS = 70;
private int mPresetPreviewSize;
- private static WidgetCell sShortpressTarget = null;
-
+ private ImageView mWidgetImage;
+ private TextView mWidgetName;
+ private TextView mWidgetDims;
private final Rect mOriginalImagePadding = new Rect();
private String mDimensionsFormatString;
- private CheckForShortPress mPendingCheckForShortPress = null;
- private ShortPressListener mShortPressListener = null;
- private boolean mShortPressTriggered = false;
private boolean mIsAppWidget;
private Object mInfo;
@@ -92,57 +88,27 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
protected void onFinishInflate() {
super.onFinishInflate();
- final ImageView image = (ImageView) findViewById(R.id.widget_preview);
- mOriginalImagePadding.left = image.getPaddingLeft();
- mOriginalImagePadding.top = image.getPaddingTop();
- mOriginalImagePadding.right = image.getPaddingRight();
- mOriginalImagePadding.bottom = image.getPaddingBottom();
+ mWidgetImage = (ImageView) findViewById(R.id.widget_preview);
+ mOriginalImagePadding.left = mWidgetImage.getPaddingLeft();
+ mOriginalImagePadding.top = mWidgetImage.getPaddingTop();
+ mOriginalImagePadding.right = mWidgetImage.getPaddingRight();
+ mOriginalImagePadding.bottom = mWidgetImage.getPaddingBottom();
// Ensure we are using the right text size
- LauncherAppState app = LauncherAppState.getInstance();
- DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
- TextView name = (TextView) findViewById(R.id.widget_name);
- if (name != null) {
- name.setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
- }
- TextView dims = (TextView) findViewById(R.id.widget_dims);
- if (dims != null) {
- dims.setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
- }
- }
-
- @Override
- protected void onDetachedFromWindow() {
- if (DEBUG) {
- Log.d(TAG, String.format("[tag=%s] onDetachedFromWindow", getTagToString()));
- }
- super.onDetachedFromWindow();
- deletePreview(false);
+ DeviceProfile profile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile();
+ mWidgetName = ((TextView) findViewById(R.id.widget_name));
+ mWidgetDims = ((TextView) findViewById(R.id.widget_dims));
}
public void reset() {
- ImageView image = (ImageView) findViewById(R.id.widget_preview);
- final TextView name = (TextView) findViewById(R.id.widget_name);
- final TextView dims = (TextView) findViewById(R.id.widget_dims);
- image.setImageDrawable(null);
- name.setText(null);
- dims.setText(null);
- }
-
- public void deletePreview(boolean recycleImage) {
- if (recycleImage) {
- final ImageView image = (ImageView) findViewById(R.id.widget_preview);
- if (image != null) {
- image.setImageDrawable(null);
- }
- }
-
- if (mActiveRequest != null) {
- mActiveRequest.cancel(recycleImage);
- mActiveRequest = null;
- }
+ mWidgetImage.setImageDrawable(null);
+ mWidgetName.setText(null);
+ mWidgetDims.setText(null);
}
+ /**
+ * Apply the widget provider info to the view.
+ */
public void applyFromAppWidgetProviderInfo(LauncherAppWidgetProviderInfo info,
int maxWidth, WidgetPreviewLoader loader) {
LauncherAppState app = LauncherAppState.getInstance();
@@ -150,37 +116,41 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
mIsAppWidget = true;
mInfo = info;
- final ImageView image = (ImageView) findViewById(R.id.widget_preview);
if (maxWidth > -1) {
- image.setMaxWidth(maxWidth);
- }
- final TextView name = (TextView) findViewById(R.id.widget_name);
- name.setText(AppWidgetManagerCompat.getInstance(getContext()).loadLabel(info));
- final TextView dims = (TextView) findViewById(R.id.widget_dims);
- if (dims != null) {
- int hSpan = Math.min(info.spanX, (int) grid.numColumns);
- int vSpan = Math.min(info.spanY, (int) grid.numRows);
- dims.setText(String.format(mDimensionsFormatString, hSpan, vSpan));
+ mWidgetImage.setMaxWidth(maxWidth);
}
+ // TODO(hyunyoungs): setup a cache for these labels.
+ mWidgetName.setText(AppWidgetManagerCompat.getInstance(getContext()).loadLabel(info));
+ int hSpan = Math.min(info.spanX, (int) grid.numColumns);
+ int vSpan = Math.min(info.spanY, (int) grid.numRows);
+ mWidgetDims.setText(String.format(mDimensionsFormatString, hSpan, vSpan));
mWidgetPreviewLoader = loader;
}
+ /**
+ * Apply the resolve info to the view.
+ */
public void applyFromResolveInfo(
PackageManager pm, ResolveInfo info, WidgetPreviewLoader loader) {
mIsAppWidget = false;
mInfo = info;
CharSequence label = info.loadLabel(pm);
- final TextView name = (TextView) findViewById(R.id.widget_name);
- name.setText(label);
- final TextView dims = (TextView) findViewById(R.id.widget_dims);
- if (dims != null) {
- dims.setText(String.format(mDimensionsFormatString, 1, 1));
- }
+ mWidgetName.setText(label);
+ mWidgetDims.setText(String.format(mDimensionsFormatString, 1, 1));
mWidgetPreviewLoader = loader;
}
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ deletePreview(false);
+
+ if (DEBUG) {
+ Log.d(TAG, String.format("[tag=%s] onDetachedFromWindow", getTagToString()));
+ }
+ }
+
public int[] getPreviewSize() {
- final ImageView i = (ImageView) findViewById(R.id.widget_preview);
int[] maxSize = new int[2];
maxSize[0] = mPresetPreviewSize;
maxSize[1] = mPresetPreviewSize;
@@ -189,110 +159,28 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
public void applyPreview(Bitmap bitmap) {
FastBitmapDrawable preview = new FastBitmapDrawable(bitmap);
- final WidgetImageView image =
- (WidgetImageView) findViewById(R.id.widget_preview);
if (DEBUG) {
Log.d(TAG, String.format("[tag=%s] applyPreview preview: %s",
getTagToString(), preview));
}
if (preview != null) {
- image.mAllowRequestLayout = false;
- image.setImageDrawable(preview);
+ mWidgetImage.setImageDrawable(preview);
if (mIsAppWidget) {
// center horizontally
int[] imageSize = getPreviewSize();
int centerAmount = (imageSize[0] - preview.getIntrinsicWidth()) / 2;
- image.setPadding(mOriginalImagePadding.left + centerAmount,
+ mWidgetImage.setPadding(mOriginalImagePadding.left + centerAmount,
mOriginalImagePadding.top,
mOriginalImagePadding.right,
mOriginalImagePadding.bottom);
}
- image.setAlpha(0f);
- image.animate().alpha(1.0f).setDuration(FADE_IN_DURATION_MS);
- image.mAllowRequestLayout = true;
- image.requestLayout();
- }
- }
-
- void setShortPressListener(ShortPressListener listener) {
- mShortPressListener = listener;
- }
-
- interface ShortPressListener {
- void onShortPress(View v);
- void cleanUpShortPress(View v);
- }
-
- class CheckForShortPress implements Runnable {
- public void run() {
- if (sShortpressTarget != null) return;
- if (mShortPressListener != null) {
- mShortPressListener.onShortPress(WidgetCell.this);
- sShortpressTarget = WidgetCell.this;
- }
- mShortPressTriggered = true;
+ mWidgetImage.setAlpha(0f);
+ mWidgetImage.animate().alpha(1.0f).setDuration(FADE_IN_DURATION_MS);
+ // TODO(hyunyoungs): figure out why this has to be called explicitly.
+ mWidgetImage.requestLayout();
}
}
- private void checkForShortPress() {
- if (sShortpressTarget != null) return;
- if (mPendingCheckForShortPress == null) {
- mPendingCheckForShortPress = new CheckForShortPress();
- }
- postDelayed(mPendingCheckForShortPress, 120);
- }
-
- /**
- * Remove the longpress detection timer.
- */
- private void removeShortPressCallback() {
- if (mPendingCheckForShortPress != null) {
- removeCallbacks(mPendingCheckForShortPress);
- }
- }
-
- private void cleanUpShortPress() {
- removeShortPressCallback();
- if (mShortPressTriggered) {
- if (mShortPressListener != null) {
- mShortPressListener.cleanUpShortPress(WidgetCell.this);
- }
- mShortPressTriggered = false;
- }
- }
-
- static void resetShortPressTarget() {
- sShortpressTarget = null;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- super.onTouchEvent(event);
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_UP:
- cleanUpShortPress();
- break;
- case MotionEvent.ACTION_DOWN:
- checkForShortPress();
- break;
- case MotionEvent.ACTION_CANCEL:
- cleanUpShortPress();
- break;
- case MotionEvent.ACTION_MOVE:
- break;
- }
-
- // We eat up the touch events here, since the PagedView (which uses the same swiping
- // touch code as Workspace previously) uses onInterceptTouchEvent() to determine when
- // the user is scrolling between pages. This means that if the pages themselves don't
- // handle touch events, it gets forwarded up to PagedView itself, and it's own
- // onTouchEvent() handling will prevent further intercept touch events from being called
- // (it's the same view in that case). This is not ideal, but to prevent more changes,
- // we just always mark the touch event as handled.
- return true;
- }
-
public void ensurePreview() {
if (mActiveRequest != null) {
return;
@@ -331,6 +219,16 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
return Math.min(size[0], info.spanX * cellWidth);
}
+
+ private void deletePreview(boolean recycleImage) {
+ mWidgetImage.setImageDrawable(null);
+
+ if (mActiveRequest != null) {
+ mActiveRequest.cancel(recycleImage);
+ mActiveRequest = null;
+ }
+ }
+
/**
* Helper method to get the string info of the tag.
*/
diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
new file mode 100644
index 000000000..d65455053
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
@@ -0,0 +1,197 @@
+package com.android.launcher3.widget;
+
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.view.View;
+
+import com.android.launcher3.AppWidgetResizeFrame;
+import com.android.launcher3.DragLayer;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+
+public class WidgetHostViewLoader {
+
+ private static final boolean DEBUG = false;
+ private static final String TAG = "WidgetHostViewLoader";
+
+ /* constants used for widget loading state. */
+ private static final int WIDGET_NO_CLEANUP_REQUIRED = -1;
+ private static final int WIDGET_PRELOAD_PENDING = 0;
+ private static final int WIDGET_BOUND = 1;
+ private static final int WIDGET_INFLATED = 2;
+
+ int mState = WIDGET_NO_CLEANUP_REQUIRED;
+
+ /* Runnables to handle inflation and binding. */
+ private Runnable mInflateWidgetRunnable = null;
+ private Runnable mBindWidgetRunnable = null;
+
+ /* Id of the widget being handled. */
+ int mWidgetLoadingId = -1;
+ PendingAddWidgetInfo mCreateWidgetInfo = null;
+
+ // TODO: technically, this class should not have to know the existence of the launcher.
+ private Launcher mLauncher;
+ private Handler mHandler;
+
+ public WidgetHostViewLoader(Launcher launcher) {
+ mLauncher = launcher;
+ mHandler = new Handler();
+ }
+
+ /**
+ * Start loading the widget.
+ */
+ public void load(View v) {
+ if (mCreateWidgetInfo != null) {
+ // Just in case the cleanup process wasn't properly executed.
+ finish(false);
+ }
+ boolean status = false;
+ if (v.getTag() instanceof PendingAddWidgetInfo) {
+ mCreateWidgetInfo = new PendingAddWidgetInfo((PendingAddWidgetInfo) v.getTag());
+ status = preloadWidget(v, mCreateWidgetInfo);
+ }
+ if (DEBUG) {
+ Log.d(TAG, String.format("load started on [state=%d, status=%s]", mState, status));
+ }
+ }
+
+
+ /**
+ * Clean up according to what the last known state was.
+ * @param widgetIdUsed {@code true} if the widgetId was consumed which can happen only
+ * when view is fully inflated
+ */
+ public void finish(boolean widgetIdUsed) {
+ if (DEBUG) {
+ Log.d(TAG, String.format("cancel on state [%d] widgetId=[%d]",
+ mState, mWidgetLoadingId));
+ }
+
+ // If the widget was not added, we may need to do further cleanup.
+ PendingAddWidgetInfo info = mCreateWidgetInfo;
+ mCreateWidgetInfo = null;
+
+ if (mState == WIDGET_PRELOAD_PENDING) {
+ // We never did any preloading, so just remove pending callbacks to do so
+ mHandler.removeCallbacks(mBindWidgetRunnable);
+ mHandler.removeCallbacks(mInflateWidgetRunnable);
+ } else if (mState == WIDGET_BOUND) {
+ // Delete the widget id which was allocated
+ if (mWidgetLoadingId != -1 && !info.isCustomWidget()) {
+ mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
+ }
+
+ // We never got around to inflating the widget, so remove the callback to do so.
+ mHandler.removeCallbacks(mInflateWidgetRunnable);
+ } else if (mState == WIDGET_INFLATED && !widgetIdUsed) {
+ // Delete the widget id which was allocated
+ if (mWidgetLoadingId != -1 && !info.isCustomWidget()) {
+ mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
+ }
+
+ // The widget was inflated and added to the DragLayer -- remove it.
+ AppWidgetHostView widget = info.boundWidget;
+ mLauncher.getDragLayer().removeView(widget);
+ }
+ setState(WIDGET_NO_CLEANUP_REQUIRED);
+ mWidgetLoadingId = -1;
+ }
+
+ private boolean preloadWidget(final View v, final PendingAddWidgetInfo info) {
+ final LauncherAppWidgetProviderInfo pInfo = info.info;
+
+ final Bundle options = pInfo.isCustomWidget ? null :
+ getDefaultOptionsForWidget(mLauncher, info);
+
+ // If there is a configuration activity, do not follow thru bound and inflate.
+ if (pInfo.configure != null) {
+ info.bindOptions = options;
+ return false;
+ }
+ setState(WIDGET_PRELOAD_PENDING);
+ mBindWidgetRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (pInfo.isCustomWidget) {
+ setState(WIDGET_BOUND);
+ return;
+ }
+
+ mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId();
+ if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed(
+ mWidgetLoadingId, pInfo, options)) {
+ setState(WIDGET_BOUND);
+ }
+ }
+ };
+ mHandler.post(mBindWidgetRunnable);
+
+ mInflateWidgetRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (mState != WIDGET_BOUND) {
+ return;
+ }
+ AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView(
+ (Context) mLauncher, mWidgetLoadingId, pInfo);
+ info.boundWidget = hostView;
+ setState(WIDGET_INFLATED);
+ hostView.setVisibility(View.INVISIBLE);
+ int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(info, false);
+
+ // We want the first widget layout to be the correct size. This will be important
+ // for width size reporting to the AppWidgetManager.
+ DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0],
+ unScaledSize[1]);
+ lp.x = lp.y = 0;
+ lp.customPosition = true;
+ hostView.setLayoutParams(lp);
+ mLauncher.getDragLayer().addView(hostView);
+ v.setTag(info);
+ }
+ };
+ mHandler.post(mInflateWidgetRunnable);
+ return true;
+ }
+
+ public static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
+ Bundle options = null;
+ Rect rect = new Rect();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ AppWidgetResizeFrame.getWidgetSizeRanges(launcher, info.spanX, info.spanY, rect);
+ Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(launcher,
+ info.componentName, null);
+
+ float density = launcher.getResources().getDisplayMetrics().density;
+ int xPaddingDips = (int) ((padding.left + padding.right) / density);
+ int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
+
+ options = new Bundle();
+ options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
+ rect.left - xPaddingDips);
+ options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
+ rect.top - yPaddingDips);
+ options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
+ rect.right - xPaddingDips);
+ options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
+ rect.bottom - yPaddingDips);
+ }
+ return options;
+ }
+
+ private void setState(int state) {
+ if (DEBUG) {
+ Log.d(TAG, String.format(" state [%d -> %d]", mState, state));
+ }
+ mState = state;
+ }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 292a5de20..27a3ea13d 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -30,6 +30,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
+import android.widget.Toast;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeleteDropTarget;
@@ -54,15 +55,17 @@ import java.util.ArrayList;
/**
* The widgets list view container.
*/
-public class WidgetsContainerView extends FrameLayout implements Insettable, View.OnTouchListener,
- View.OnLongClickListener, DragSource{
+public class WidgetsContainerView extends FrameLayout implements Insettable,
+ View.OnLongClickListener, View.OnClickListener, DragSource{
- private static final String TAG = "WidgetContainerView";
+ private static final String TAG = "WidgetsContainerView";
private static final boolean DEBUG = false;
/* {@link RecyclerView} will keep following # of views in cache, before recycling. */
private static final int WIDGET_CACHE_SIZE = 2;
+ private static final int SPRING_MODE_DELAY_MS = 150;
+
/* Global instances that are used inside this container. */
private Launcher mLauncher;
private DragController mDragController;
@@ -75,12 +78,13 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
private RecyclerView mView;
private WidgetsListAdapter mAdapter;
- /* Dragging related. */
- private boolean mDraggingWidget = false; // TODO(hyunyoungs): seems not needed? check!
- private Point mLastTouchDownPos = new Point();
+ /* Touch handling related member variables. */
+ private Toast mWidgetInstructionToast;
/* Rendering related. */
private WidgetPreviewLoader mWidgetPreviewLoader;
+ private WidgetHostViewLoader mWidgetHostViewLoader;
+
private Rect mPadding = new Rect();
public WidgetsContainerView(Context context) {
@@ -95,8 +99,8 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
super(context, attrs, defStyleAttr);
mLauncher = (Launcher) context;
mDragController = mLauncher.getDragController();
-
- mAdapter = new WidgetsListAdapter(context, this, mLauncher, this, mLauncher);
+ mWidgetHostViewLoader = new WidgetHostViewLoader(mLauncher);
+ mAdapter = new WidgetsListAdapter(context, this, this, mLauncher);
mWidgets = new WidgetsModel(context, mAdapter);
mAdapter.setWidgetsModel(mWidgets);
mIconCache = (LauncherAppState.getInstance()).getIconCache();
@@ -147,11 +151,26 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
//
@Override
+ public void onClick(View v) {
+ // When we have exited widget tray or are in transition, disregard clicks
+ if (!mLauncher.isWidgetsViewVisible()
+ || mLauncher.getWorkspace().isSwitchingState()
+ || !(v instanceof WidgetCell)) return;
+
+ // Let the user know that they have to long press to add a widget
+ if (mWidgetInstructionToast != null) {
+ mWidgetInstructionToast.cancel();
+ }
+ mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add,
+ Toast.LENGTH_SHORT);
+ mWidgetInstructionToast.show();
+ }
+
+ @Override
public boolean onLongClick(View v) {
if (DEBUG) {
Log.d(TAG, String.format("onLonglick [v=%s]", v));
}
-
// Return early if this is not initiated from a touch
if (!v.isInTouchMode()) return false;
// When we have exited all apps or are in transition, disregard long clicks
@@ -161,7 +180,11 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
Log.d(TAG, String.format("onLonglick dragging enabled?.", v));
if (!mLauncher.isDraggingEnabled()) return false;
- return beginDragging(v);
+ boolean status = beginDragging(v);
+ if (status) {
+ mWidgetHostViewLoader.load(v);
+ }
+ return status;
}
private boolean beginDragging(View v) {
@@ -174,7 +197,7 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
}
// We delay entering spring-loaded mode slightly to make sure the UI
- // thready is free of any work.
+ // thread is free of any work.
postDelayed(new Runnable() {
@Override
public void run() {
@@ -184,13 +207,12 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
mLauncher.enterSpringLoadedDragMode();
}
}
- }, 150);
+ }, SPRING_MODE_DELAY_MS);
return true;
}
private boolean beginDraggingWidget(WidgetCell v) {
- mDraggingWidget = true;
// Get the widget preview as the drag representation
ImageView image = (ImageView) v.findViewById(R.id.widget_preview);
PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
@@ -198,7 +220,6 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
// If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
// we abort the drag.
if (image.getDrawable() == null) {
- mDraggingWidget = false;
return false;
}
@@ -259,19 +280,6 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
return true;
}
- /*
- * @see android.view.View.OnTouchListener#onTouch(android.view.View, android.view.MotionEvent)
- */
- @Override
- public boolean onTouch(View v, MotionEvent ev) {
- Log.d(TAG, String.format("onTouch [MotionEvent=%s]", ev));
- if (ev.getAction() == MotionEvent.ACTION_DOWN ||
- ev.getAction() == MotionEvent.ACTION_MOVE) {
- mLastTouchDownPos.set((int) ev.getX(), (int) ev.getY());
- }
- return false;
- }
-
//
// Drag related handling methods that implement {@link DragSource} interface.
//
@@ -340,6 +348,10 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
}
d.deferDragViewCleanupPostAnimation = false;
}
+ //TODO(hyunyoungs): if drop fails, this call cleans up correctly.
+ // However, in rare corner case where drop succeeds but doesn't end up using the widget
+ // id created by the loader, this finish will leave dangling widget id.
+ mWidgetHostViewLoader.finish(success);
}
//
@@ -368,5 +380,4 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
}
return mWidgetPreviewLoader;
}
-
} \ No newline at end of file
diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java
index afeb2d385..f6ab21eb4 100644
--- a/src/com/android/launcher3/widget/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java
@@ -56,20 +56,16 @@ public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> {
private WidgetsModel mWidgetsModel;
private WidgetPreviewLoader mWidgetPreviewLoader;
- private View.OnTouchListener mTouchListener;
private View.OnClickListener mIconClickListener;
private View.OnLongClickListener mIconLongClickListener;
-
public WidgetsListAdapter(Context context,
- View.OnTouchListener touchListener,
View.OnClickListener iconClickListener,
View.OnLongClickListener iconLongClickListener,
Launcher launcher) {
mLayoutInflater = LayoutInflater.from(context);
mContext = context;
- mTouchListener = touchListener;
mIconClickListener = iconClickListener;
mIconLongClickListener = iconLongClickListener;
@@ -109,7 +105,6 @@ public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> {
// set up touch.
widget.setOnClickListener(mIconClickListener);
widget.setOnLongClickListener(mIconLongClickListener);
- widget.setOnTouchListener(mTouchListener);
row.addView(widget);
}
} else if (diff < 0) {