summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/layout-port/launcher.xml3
-rw-r--r--res/layout-sw720dp/launcher.xml3
-rw-r--r--res/layout/all_apps.xml6
-rw-r--r--res/values/dimens.xml5
-rw-r--r--src/com/android/launcher3/AllAppsList.java9
-rw-r--r--src/com/android/launcher3/AppWidgetResizeFrame.java59
-rw-r--r--src/com/android/launcher3/AutoInstallsLayout.java3
-rw-r--r--src/com/android/launcher3/BaseContainerView.java90
-rw-r--r--src/com/android/launcher3/BaseRecyclerViewFastScrollPopup.java4
-rw-r--r--src/com/android/launcher3/BubbleTextView.java5
-rw-r--r--src/com/android/launcher3/DeviceProfile.java2
-rw-r--r--src/com/android/launcher3/IconCache.java11
-rw-r--r--src/com/android/launcher3/Launcher.java86
-rw-r--r--src/com/android/launcher3/LauncherClings.java30
-rw-r--r--src/com/android/launcher3/LauncherModel.java519
-rw-r--r--src/com/android/launcher3/LauncherProvider.java7
-rw-r--r--src/com/android/launcher3/PagedView.java19
-rw-r--r--src/com/android/launcher3/PinchToOverviewListener.java4
-rw-r--r--src/com/android/launcher3/ShortcutInfo.java9
-rw-r--r--src/com/android/launcher3/Utilities.java236
-rw-r--r--src/com/android/launcher3/Workspace.java98
-rw-r--r--src/com/android/launcher3/allapps/AllAppsContainerView.java205
-rw-r--r--src/com/android/launcher3/allapps/AllAppsRecyclerViewContainerView.java3
-rw-r--r--src/com/android/launcher3/allapps/AllAppsTransitionController.java4
-rw-r--r--src/com/android/launcher3/dragndrop/DragController.java4
-rw-r--r--src/com/android/launcher3/dragndrop/DragLayer.java91
-rw-r--r--src/com/android/launcher3/dragndrop/ExternalDragPreviewProvider.java4
-rw-r--r--src/com/android/launcher3/graphics/DragPreviewProvider.java3
-rw-r--r--src/com/android/launcher3/graphics/HolographicOutlineHelper.java (renamed from src/com/android/launcher3/HolographicOutlineHelper.java)12
-rw-r--r--src/com/android/launcher3/graphics/IconNormalizer.java (renamed from src/com/android/launcher3/util/IconNormalizer.java)2
-rw-r--r--src/com/android/launcher3/graphics/LauncherIcons.java258
-rw-r--r--src/com/android/launcher3/model/BgDataModel.java197
-rw-r--r--src/com/android/launcher3/model/SdCardAvailableReceiver.java88
-rw-r--r--src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java1
-rw-r--r--src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java4
-rw-r--r--src/com/android/launcher3/util/CursorIconInfo.java5
-rw-r--r--src/com/android/launcher3/util/ItemInfoMatcher.java42
-rw-r--r--src/com/android/launcher3/util/StringFilter.java31
-rw-r--r--src/com/android/launcher3/util/TouchController.java28
-rw-r--r--src/com/android/launcher3/widget/PendingItemPreviewProvider.java4
-rw-r--r--src/com/android/launcher3/widget/WidgetsContainerView.java25
-rw-r--r--tests/src/com/android/launcher3/BindWidgetTest.java1
-rw-r--r--tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java2
43 files changed, 1061 insertions, 1161 deletions
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index a2e2f9bba..dd981dd20 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -77,8 +77,7 @@
android:id="@+id/apps_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:visibility="invisible"
- launcher:layout_ignoreInsets="true" />
+ android:visibility="invisible" />
</com.android.launcher3.dragndrop.DragLayer>
</com.android.launcher3.LauncherRootView>
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index 12c01b77d..06cb55040 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -76,8 +76,7 @@
android:id="@+id/apps_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:visibility="invisible"
- launcher:layout_ignoreInsets="true" />
+ android:visibility="invisible" />
</com.android.launcher3.dragndrop.DragLayer>
</com.android.launcher3.LauncherRootView>
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 4909eb38b..926883927 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -46,10 +46,10 @@
<!-- DO NOT CHANGE THE ID -->
<com.android.launcher3.allapps.AllAppsRecyclerView
android:id="@+id/apps_list_view"
+ android:layout_below="@+id/search_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal|top"
- android:layout_marginTop="@dimen/all_apps_search_bar_height"
android:clipToPadding="false"
android:descendantFocusability="afterDescendants"
android:focusable="true"
@@ -60,7 +60,6 @@
android:layout_width="match_parent"
android:layout_height="@dimen/all_apps_search_bar_height"
android:layout_gravity="center|top"
- android:paddingTop="@dimen/all_apps_search_bar_margin_top"
android:gravity="center|bottom"
android:orientation="horizontal"
android:saveEnabled="false">
@@ -68,8 +67,9 @@
<com.android.launcher3.ExtendedEditText
android:id="@+id/search_box_input"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="@dimen/all_apps_search_bar_field_height"
android:background="@android:color/transparent"
+ android:layout_gravity="bottom"
android:focusableInTouchMode="true"
android:gravity="center"
android:imeOptions="actionSearch|flagNoExtractUi"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c112949ba..47edadd0d 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -64,8 +64,8 @@
<dimen name="all_apps_grid_view_start_margin">0dp</dimen>
<dimen name="all_apps_grid_section_y_offset">8dp</dimen>
<dimen name="all_apps_grid_section_text_size">24sp</dimen>
+ <dimen name="all_apps_search_bar_field_height">48dp</dimen>
<dimen name="all_apps_search_bar_height">60dp</dimen>
- <dimen name="all_apps_search_bar_margin_top">12dp</dimen>
<dimen name="all_apps_search_bar_icon_margin_right">4dp</dimen>
<dimen name="all_apps_search_bar_icon_margin_top">1dp</dimen>
<dimen name="all_apps_list_bottom_padding">8dp</dimen>
@@ -182,6 +182,9 @@
also happens to equal 19dp-->
<dimen name="deep_shortcuts_arrow_horizontal_offset">19dp</dimen>
+<!-- Touch handling -->
+ <dimen name="edge_of_screen_threshold">8dp</dimen>
+
<!-- Other -->
<!-- Approximates the system status bar height. Not guaranteed to be always be correct. -->
<dimen name="status_bar_height">24dp</dimen>
diff --git a/src/com/android/launcher3/AllAppsList.java b/src/com/android/launcher3/AllAppsList.java
index c4315936c..c427ddc93 100644
--- a/src/com/android/launcher3/AllAppsList.java
+++ b/src/com/android/launcher3/AllAppsList.java
@@ -23,7 +23,7 @@ import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.util.FlagOp;
-import com.android.launcher3.util.StringFilter;
+import com.android.launcher3.util.ItemInfoMatcher;
import java.util.ArrayList;
import java.util.HashSet;
@@ -121,14 +121,13 @@ class AllAppsList {
}
/**
- * Updates the apps for the given packageName and user based on {@param op}.
+ * Updates the disabled flags of apps matching {@param matcher} based on {@param op}.
*/
- public void updatePackageFlags(StringFilter pkgFilter, UserHandleCompat user, FlagOp op) {
+ public void updateDisabledFlags(ItemInfoMatcher matcher, FlagOp op) {
final List<AppInfo> data = this.data;
for (int i = data.size() - 1; i >= 0; i--) {
AppInfo info = data.get(i);
- final ComponentName component = info.intent.getComponent();
- if (info.user.equals(user) && pkgFilter.matches(component.getPackageName())) {
+ if (matcher.matches(info, info.intent.getComponent())) {
info.isDisabled = op.apply(info.isDisabled);
modified.add(info);
}
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index daeca3bef..f0ec50343 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -15,14 +15,17 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.view.Gravity;
import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.android.launcher3.accessibility.DragViewStateAnnouncer;
import com.android.launcher3.util.FocusLogic;
+import com.android.launcher3.util.TouchController;
-public class AppWidgetResizeFrame extends FrameLayout implements View.OnKeyListener {
+public class AppWidgetResizeFrame extends FrameLayout
+ implements View.OnKeyListener, TouchController {
private static final int SNAP_DURATION = 150;
private static final float DIMMED_HANDLE_ALPHA = 0f;
private static final float RESIZE_THRESHOLD = 0.66f;
@@ -76,6 +79,8 @@ public class AppWidgetResizeFrame extends FrameLayout implements View.OnKeyListe
private int mTopTouchRegionAdjustment = 0;
private int mBottomTouchRegionAdjustment = 0;
+ private int mXDown, mYDown;
+
public AppWidgetResizeFrame(Context context,
LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) {
@@ -205,7 +210,7 @@ public class AppWidgetResizeFrame extends FrameLayout implements View.OnKeyListe
}
}
- public void visualizeResizeForDelta(int deltaX, int deltaY) {
+ private void visualizeResizeForDelta(int deltaX, int deltaY) {
visualizeResizeForDelta(deltaX, deltaY, false);
}
@@ -398,7 +403,7 @@ public class AppWidgetResizeFrame extends FrameLayout implements View.OnKeyListe
requestLayout();
}
- public void onTouchUp() {
+ private void onTouchUp() {
int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
@@ -493,10 +498,56 @@ public class AppWidgetResizeFrame extends FrameLayout implements View.OnKeyListe
public boolean onKey(View v, int keyCode, KeyEvent event) {
// Clear the frame and give focus to the widget host view when a directional key is pressed.
if (FocusLogic.shouldConsume(keyCode)) {
- mDragLayer.clearAllResizeFrames();
+ mDragLayer.clearResizeFrame();
mWidgetView.requestFocus();
return true;
}
return false;
}
+
+ private boolean handleTouchDown(MotionEvent ev) {
+ Rect hitRect = new Rect();
+ int x = (int) ev.getX();
+ int y = (int) ev.getY();
+
+ getHitRect(hitRect);
+ if (hitRect.contains(x, y)) {
+ if (beginResizeIfPointInRegion(x - getLeft(), y - getTop())) {
+ mXDown = x;
+ mYDown = y;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onControllerTouchEvent(MotionEvent ev) {
+ int action = ev.getAction();
+ int x = (int) ev.getX();
+ int y = (int) ev.getY();
+
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ return handleTouchDown(ev);
+ case MotionEvent.ACTION_MOVE:
+ visualizeResizeForDelta(x - mXDown, y - mYDown);
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ visualizeResizeForDelta(x - mXDown, y - mYDown);
+ onTouchUp();
+ mXDown = mYDown = 0;
+ break;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN && handleTouchDown(ev)) {
+ return true;
+ }
+ return false;
+ }
}
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index d5309b4f0..8b5a8a863 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -38,6 +38,7 @@ import android.util.Patterns;
import com.android.launcher3.LauncherProvider.SqlArguments;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.util.Thunk;
import org.xmlpull.v1.XmlPullParser;
@@ -436,7 +437,7 @@ public class AutoInstallsLayout {
return -1;
}
- ItemInfo.writeBitmap(mValues, Utilities.createIconBitmap(icon, mContext));
+ ItemInfo.writeBitmap(mValues, LauncherIcons.createIconBitmap(icon, mContext));
mValues.put(Favorites.ICON_PACKAGE, mIconRes.getResourcePackageName(iconId));
mValues.put(Favorites.ICON_RESOURCE, mIconRes.getResourceName(iconId));
diff --git a/src/com/android/launcher3/BaseContainerView.java b/src/com/android/launcher3/BaseContainerView.java
index 96942ee6f..b7321d94f 100644
--- a/src/com/android/launcher3/BaseContainerView.java
+++ b/src/com/android/launcher3/BaseContainerView.java
@@ -16,17 +16,24 @@
package com.android.launcher3;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.util.AttributeSet;
+import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import android.widget.FrameLayout;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.util.TransformingTouchDelegate;
/**
* A base container view, which supports resizing.
@@ -39,12 +46,16 @@ public abstract class BaseContainerView extends FrameLayout
protected int mContainerPaddingTop;
protected int mContainerPaddingBottom;
- private InsetDrawable mRevealDrawable;
protected final Drawable mBaseDrawable;
+ private final Rect mBgPaddingRect = new Rect();
private View mRevealView;
private View mContent;
+ private TransformingTouchDelegate mTouchDelegate;
+
+ private final PointF mLastTouchDownPosPx = new PointF(-1.0f, -1.0f);
+
public BaseContainerView(Context context) {
this(context, null);
}
@@ -72,6 +83,12 @@ public abstract class BaseContainerView extends FrameLayout
DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
grid.addLauncherLayoutChangedListener(this);
+
+ View touchDelegateTargetView = getTouchDelegateTargetView();
+ if (touchDelegateTargetView != null) {
+ mTouchDelegate = new TransformingTouchDelegate(touchDelegateTargetView);
+ ((View) touchDelegateTargetView.getParent()).setTouchDelegate(mTouchDelegate);
+ }
}
@Override
@@ -93,10 +110,36 @@ public abstract class BaseContainerView extends FrameLayout
}
@Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ getRevealView().getBackground().getPadding(mBgPaddingRect);
+
+ View touchDelegateTargetView = getTouchDelegateTargetView();
+ if (touchDelegateTargetView != null) {
+ mTouchDelegate.setBounds(
+ touchDelegateTargetView.getLeft() - mBgPaddingRect.left,
+ touchDelegateTargetView.getTop() - mBgPaddingRect.top,
+ touchDelegateTargetView.getRight() + mBgPaddingRect.right,
+ touchDelegateTargetView.getBottom() + mBgPaddingRect.bottom);
+ }
+ }
+
+ @Override
public void onLauncherLayoutChanged() {
updatePaddings();
}
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ return handleTouchEvent(ev);
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ return handleTouchEvent(ev);
+ }
+
public void setRevealDrawableColor(int color) {
((ColorDrawable) mBaseDrawable).setColor(color);
}
@@ -130,14 +173,47 @@ public abstract class BaseContainerView extends FrameLayout
}
}
- mRevealDrawable = new InsetDrawable(mBaseDrawable,
+ InsetDrawable revealDrawable = new InsetDrawable(mBaseDrawable,
mContainerPaddingLeft, mContainerPaddingTop, mContainerPaddingRight,
mContainerPaddingBottom);
- mRevealView.setBackground(mRevealDrawable);
- if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && this instanceof AllAppsContainerView) {
- // Skip updating the content background
- } else {
- mContent.setBackground(mRevealDrawable);
+ mRevealView.setBackground(revealDrawable);
+ mContent.setBackground(revealDrawable);
+ }
+
+ /**
+ * Handles the touch events that shows the workspace when clicking outside the bounds of the
+ * touch delegate target view.
+ */
+ private boolean handleTouchEvent(MotionEvent ev) {
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ // Check if the touch is outside touch delegate target view
+ View touchDelegateTargetView = getTouchDelegateTargetView();
+ float leftBoundPx = touchDelegateTargetView.getLeft();
+ if (ev.getX() < leftBoundPx ||
+ ev.getX() > (touchDelegateTargetView.getWidth() + leftBoundPx)) {
+ mLastTouchDownPosPx.set((int) ev.getX(), (int) ev.getY());
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ if (mLastTouchDownPosPx.x > -1) {
+ ViewConfiguration viewConfig = ViewConfiguration.get(getContext());
+ float dx = ev.getX() - mLastTouchDownPosPx.x;
+ float dy = ev.getY() - mLastTouchDownPosPx.y;
+ float distance = PointF.length(dx, dy);
+ if (distance < viewConfig.getScaledTouchSlop()) {
+ // The background was clicked, so just go home
+ Launcher.getLauncher(getContext()).showWorkspace(true);
+ return true;
+ }
+ }
+ // Fall through
+ case MotionEvent.ACTION_CANCEL:
+ mLastTouchDownPosPx.set(-1, -1);
+ break;
}
+ return false;
}
+
+ public abstract View getTouchDelegateTargetView();
}
diff --git a/src/com/android/launcher3/BaseRecyclerViewFastScrollPopup.java b/src/com/android/launcher3/BaseRecyclerViewFastScrollPopup.java
index b9e627775..b9b044db9 100644
--- a/src/com/android/launcher3/BaseRecyclerViewFastScrollPopup.java
+++ b/src/com/android/launcher3/BaseRecyclerViewFastScrollPopup.java
@@ -25,6 +25,8 @@ import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import com.android.launcher3.graphics.HolographicOutlineHelper;
+
/**
* The fast scroller popup that shows the section name the list will jump to.
*/
@@ -116,7 +118,7 @@ public class BaseRecyclerViewFastScrollPopup {
mBgBounds.bottom = mBgBounds.top + bgHeight;
// Generate a bitmap for a shadow matching these bounds
- mShadow = HolographicOutlineHelper.obtain(
+ mShadow = HolographicOutlineHelper.getInstance(
mRv.getContext()).createMediumDropShadow(mBg, false /* shouldCache */);
} else {
mShadow = null;
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index a294fa538..7d693ec2b 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -42,6 +42,7 @@ import android.widget.TextView;
import com.android.launcher3.IconCache.IconLoadRequest;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.graphics.HolographicOutlineHelper;
import com.android.launcher3.model.PackageItemInfo;
import java.text.NumberFormat;
@@ -150,7 +151,7 @@ public class BubbleTextView extends TextView
mLongPressHelper = new CheckLongPressHelper(this);
mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
- mOutlineHelper = HolographicOutlineHelper.obtain(getContext());
+ mOutlineHelper = HolographicOutlineHelper.getInstance(getContext());
setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
}
@@ -328,7 +329,7 @@ public class BubbleTextView extends TextView
void setStayPressed(boolean stayPressed) {
mStayPressed = stayPressed;
if (!stayPressed) {
- HolographicOutlineHelper.obtain(getContext()).recycleShadowBitmap(mPressedBackground);
+ HolographicOutlineHelper.getInstance(getContext()).recycleShadowBitmap(mPressedBackground);
mPressedBackground = null;
} else {
if (mPressedBackground == null) {
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index c4e6ed119..8e4567bd8 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -104,7 +104,7 @@ public class DeviceProfile {
public int hotseatCellWidthPx;
public int hotseatCellHeightPx;
public int hotseatIconSizePx;
- private int hotseatBarHeightPx;
+ public int hotseatBarHeightPx;
private int hotseatBarTopPaddingPx;
private int hotseatLandGutterPx;
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index d3fb38ede..8edfdf593 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -47,6 +47,7 @@ import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.SQLiteCacheHelper;
@@ -187,7 +188,7 @@ public class IconCache {
private Bitmap makeDefaultIcon(UserHandleCompat user) {
Drawable unbadged = getFullResDefaultActivityIcon();
- return Utilities.createBadgedIconBitmap(unbadged, user, mContext);
+ return LauncherIcons.createBadgedIconBitmap(unbadged, user, mContext);
}
/**
@@ -387,7 +388,7 @@ public class IconCache {
}
if (entry == null) {
entry = new CacheEntry();
- entry.icon = Utilities.createBadgedIconBitmap(
+ entry.icon = LauncherIcons.createBadgedIconBitmap(
mIconProvider.getIcon(app, mIconDpi), app.getUser(),
mContext);
}
@@ -555,7 +556,7 @@ public class IconCache {
// Check the DB first.
if (!getEntryFromDB(cacheKey, entry, useLowResIcon) || DEBUG_IGNORE_CACHE) {
if (info != null) {
- entry.icon = Utilities.createBadgedIconBitmap(
+ entry.icon = LauncherIcons.createBadgedIconBitmap(
mIconProvider.getIcon(info, mIconDpi), info.getUser(),
mContext);
} else {
@@ -606,7 +607,7 @@ public class IconCache {
entry.title = title;
}
if (icon != null) {
- entry.icon = Utilities.createIconBitmap(icon, mContext);
+ entry.icon = LauncherIcons.createIconBitmap(icon, mContext);
}
}
@@ -641,7 +642,7 @@ public class IconCache {
// Load the full res icon for the application, but if useLowResIcon is set, then
// only keep the low resolution icon instead of the larger full-sized icon
- Bitmap icon = Utilities.createBadgedIconBitmap(
+ Bitmap icon = LauncherIcons.createBadgedIconBitmap(
appInfo.loadIcon(mPackageManager), user, mContext);
Bitmap lowResIcon = generateLowResIcon(icon, mPackageBgColor);
entry.title = appInfo.loadLabel(mPackageManager);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index d059da2e5..bd150da7d 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -254,7 +254,6 @@ public class Launcher extends Activity
@Thunk WidgetsContainerView mWidgetsView;
@Thunk WidgetsModel mWidgetsModel;
- private Bundle mSavedState;
// We set the state in both onCreate and then onNewIntent in some cases, which causes both
// scroll issues (because the workspace may not have been measured yet) and extra work.
// Instead, just save the state that we need to restore Launcher to, and commit it in onResume.
@@ -355,6 +354,9 @@ public class Launcher extends Activity
private UserEventDispatcher mUserEventDispatcher;
+ private float mLastDispatchTouchEventX = 0.0f;
+ private float mEdgeOfScreenThresholdPx = 0.0f;
+
public ViewGroupFocusHelper mFocusHandler;
private boolean mRotationEnabled = false;
@@ -425,6 +427,9 @@ public class Launcher extends Activity
setContentView(R.layout.launcher);
+ mEdgeOfScreenThresholdPx = getResources()
+ .getDimensionPixelSize(R.dimen.edge_of_screen_threshold);
+
setupViews();
mDeviceProfile.layout(this, false /* notifyListeners */);
mExtractedColors = new ExtractedColors();
@@ -435,8 +440,7 @@ public class Launcher extends Activity
lockAllApps();
- mSavedState = savedInstanceState;
- restoreState(mSavedState);
+ restoreState(savedInstanceState);
if (LauncherAppState.PROFILE_STARTUP) {
Trace.endSection();
@@ -444,11 +448,18 @@ public class Launcher extends Activity
// We only load the page synchronously if the user rotates (or triggers a
// configuration change) while launcher is in the foreground
- if (!mModel.startLoader(mWorkspace.getRestorePage())) {
+ int currentScreen = PagedView.INVALID_RESTORE_PAGE;
+ if (savedInstanceState != null) {
+ currentScreen = savedInstanceState.getInt(RUNTIME_STATE_CURRENT_SCREEN, currentScreen);
+ }
+ if (!mModel.startLoader(currentScreen)) {
// If we are not binding synchronously, show a fade in animation when
// the first page bind completes.
mDragLayer.setAlpha(0);
} else {
+ // Pages bound synchronously.
+ mWorkspace.setCurrentPage(currentScreen);
+
setWorkspaceLoading(true);
}
@@ -611,7 +622,7 @@ public class Launcher extends Activity
}
/**
- * Invoked by subclasses to signal a change to the {@link #addCustomContentToLeft} value to
+ * Invoked by subclasses to signal a change to the {@link #addToCustomContentPage} value to
* ensure the custom content page is added or removed if necessary.
*/
protected void invalidateHasCustomContentToLeft() {
@@ -1263,22 +1274,6 @@ public class Launcher extends Activity
}
/**
- * Given the integer (ordinal) value of a State enum instance, convert it to a variable of type
- * State
- */
- private static State intToState(int stateOrdinal) {
- State state = State.WORKSPACE;
- final State[] stateValues = State.values();
- for (int i = 0; i < stateValues.length; i++) {
- if (stateValues[i].ordinal() == stateOrdinal) {
- state = stateValues[i];
- break;
- }
- }
- return state;
- }
-
- /**
* Restores the previous state, if it exists.
*
* @param savedState The previous state.
@@ -1288,17 +1283,14 @@ public class Launcher extends Activity
return;
}
- State state = intToState(savedState.getInt(RUNTIME_STATE, State.WORKSPACE.ordinal()));
+ int stateOrdinal = savedState.getInt(RUNTIME_STATE, State.WORKSPACE.ordinal());
+ State[] stateValues = State.values();
+ State state = (stateOrdinal >= 0 && stateOrdinal < stateValues.length)
+ ? stateValues[stateOrdinal] : State.WORKSPACE;
if (state == State.APPS || state == State.WIDGETS) {
mOnResumeState = state;
}
- int currentScreen = savedState.getInt(RUNTIME_STATE_CURRENT_SCREEN,
- PagedView.INVALID_RESTORE_PAGE);
- if (currentScreen != PagedView.INVALID_RESTORE_PAGE) {
- mWorkspace.setRestorePage(currentScreen);
- }
-
PendingRequestArgs requestArgs = savedState.getParcelable(RUNTIME_STATE_PENDING_REQUEST_ARGS);
if (requestArgs != null) {
setWaitingForResult(requestArgs);
@@ -1588,7 +1580,7 @@ public class Launcher extends Activity
final String action = intent.getAction();
if (Intent.ACTION_SCREEN_OFF.equals(action)) {
mUserPresent = false;
- mDragLayer.clearAllResizeFrames();
+ mDragLayer.clearResizeFrame();
updateAutoAdvanceState();
// Reset AllApps to its initial state only if we are not in the middle of
@@ -2778,6 +2770,7 @@ public class Launcher extends Activity
}
}
+ @TargetApi(Build.VERSION_CODES.M)
private Bundle getActivityLaunchOptions(View v) {
if (Utilities.ATLEAST_MARSHMALLOW) {
int left = 0, top = 0;
@@ -3078,6 +3071,12 @@ public class Launcher extends Activity
}
@Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ mLastDispatchTouchEventX = ev.getX();
+ return super.dispatchTouchEvent(ev);
+ }
+
+ @Override
public boolean onLongClick(View v) {
if (!isDraggingEnabled()) return false;
if (isWorkspaceLocked()) return false;
@@ -3089,9 +3088,12 @@ public class Launcher extends Activity
return true;
}
+ boolean fromEdgeOfScreen = mLastDispatchTouchEventX < mEdgeOfScreenThresholdPx
+ || mLastDispatchTouchEventX > (mDeviceProfile.widthPx - mEdgeOfScreenThresholdPx);
+
if (v instanceof Workspace) {
if (!mWorkspace.isInOverviewMode()) {
- if (!mWorkspace.isTouchActive()) {
+ if (!mWorkspace.isTouchActive() && !fromEdgeOfScreen) {
showOverviewMode(true);
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
@@ -3118,13 +3120,16 @@ public class Launcher extends Activity
if (!mDragController.isDragging()) {
if (itemUnderLongClick == null) {
// User long pressed on empty space
- mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
- HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
if (mWorkspace.isInOverviewMode()) {
mWorkspace.startReordering(v);
} else {
+ if (fromEdgeOfScreen) {
+ return false;
+ }
showOverviewMode(true);
}
+ mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
+ HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
} else {
final boolean isAllAppsButton =
!FeatureFlags.NO_ALL_APPS_ICON && isHotseatLayout(v) &&
@@ -3981,14 +3986,6 @@ public class Launcher extends Activity
if (LauncherAppState.PROFILE_STARTUP) {
Trace.beginSection("Page bind completed");
}
- if (mSavedState != null) {
- if (!mWorkspace.hasFocus()) {
- mWorkspace.getChildAt(mWorkspace.getCurrentPage()).requestFocus();
- }
-
- mSavedState = null;
- }
-
mWorkspace.restoreInstanceStateForRemainingPages();
setWorkspaceLoading(false);
@@ -4410,7 +4407,6 @@ public class Launcher extends Activity
*/
public void dumpState() {
Log.d(TAG, "BEGIN launcher3 dump state for launcher " + this);
- Log.d(TAG, "mSavedState=" + mSavedState);
Log.d(TAG, "mWorkspaceLoading=" + mWorkspaceLoading);
Log.d(TAG, "mPendingRequestArgs=" + mPendingRequestArgs);
Log.d(TAG, "mPendingActivityResult=" + mPendingActivityResult);
@@ -4465,14 +4461,6 @@ public class Launcher extends Activity
return sCustomAppWidgets;
}
- public static List<View> getFolderContents(View icon) {
- if (icon instanceof FolderIcon) {
- return ((FolderIcon) icon).getFolder().getItemsInReadingOrder();
- } else {
- return Collections.EMPTY_LIST;
- }
- }
-
public static Launcher getLauncher(Context context) {
if (context instanceof Launcher) {
return (Launcher) context;
diff --git a/src/com/android/launcher3/LauncherClings.java b/src/com/android/launcher3/LauncherClings.java
deleted file mode 100644
index c1282b51c..000000000
--- a/src/com/android/launcher3/LauncherClings.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2008 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;
-
-import android.content.Context;
-
-@Deprecated
-public class LauncherClings {
- private static final String WORKSPACE_CLING_DISMISSED_KEY = "cling_gel.workspace.dismissed";
-
- public static void markFirstRunClingDismissed(Context ctx) {
- Utilities.getPrefs(ctx).edit()
- .putBoolean(WORKSPACE_CLING_DISMISSED_KEY, true)
- .apply();
- }
-}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index d66ce6b91..4afff1898 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -57,8 +57,11 @@ import com.android.launcher3.config.ProviderConfig;
import com.android.launcher3.dynamicui.ExtractionUtils;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.GridSizeMigrationTask;
+import com.android.launcher3.model.SdCardAvailableReceiver;
import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.provider.ImportDataTask;
import com.android.launcher3.provider.LauncherDbUtils;
@@ -69,12 +72,12 @@ import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.CursorIconInfo;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.GridOccupancy;
+import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LongArrayMap;
import com.android.launcher3.util.ManagedProfileHeuristic;
import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Preconditions;
-import com.android.launcher3.util.StringFilter;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.ViewOnDrawExecutor;
@@ -159,38 +162,11 @@ public class LauncherModel extends BroadcastReceiver
}
};
- // The lock that must be acquired before referencing any static bg data structures. Unlike
- // other locks, this one can generally be held long-term because we never expect any of these
- // static data structures to be referenced outside of the worker thread except on the first
- // load after configuration change.
- static final Object sBgLock = new Object();
-
- // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by
- // LauncherModel to their ids
- 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
- // shortcuts within folders).
- static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();
-
- // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()
- static final ArrayList<LauncherAppWidgetInfo> sBgAppWidgets =
- new ArrayList<LauncherAppWidgetInfo>();
-
- // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()
- static final LongArrayMap<FolderInfo> sBgFolders = new LongArrayMap<>();
-
- // sBgWorkspaceScreens is the ordered set of workspace screens.
- static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();
-
- // sBgPinnedShortcutCounts is the ComponentKey representing a pinned shortcut to the number of
- // times it is pinned.
- static final Map<ShortcutKey, MutableInt> sBgPinnedShortcutCounts = new HashMap<>();
-
- // sPendingPackages is a set of packages which could be on sdcard and are not available yet
- static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages =
- new HashMap<UserHandleCompat, HashSet<String>>();
+ /**
+ * All the static data should be accessed on the background thread, A lock should be acquired
+ * on this object when accessing any data from this model.
+ */
+ static final BgDataModel sBgDataModel = new BgDataModel();
// </ only access in worker thread >
@@ -232,10 +208,6 @@ public class LauncherModel extends BroadcastReceiver
public void bindDeepShortcutMap(MultiHashMap<ComponentKey, String> deepShortcutMap);
}
- public interface ItemInfoFilter {
- public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);
- }
-
LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter,
DeepShortcutManager deepShortcutManager) {
Context context = app.getContext();
@@ -276,7 +248,7 @@ public class LauncherModel extends BroadcastReceiver
@Override
public void run() {
- synchronized (sBgLock) {
+ synchronized (sBgDataModel) {
final HashSet<ItemInfo> updates = new HashSet<>();
if (installInfo.state == PackageInstallerCompat.STATUS_INSTALLED) {
@@ -284,7 +256,7 @@ public class LauncherModel extends BroadcastReceiver
return;
}
- for (ItemInfo info : sBgItemsIdMap) {
+ for (ItemInfo info : sBgDataModel.itemsIdMap) {
if (info instanceof ShortcutInfo) {
ShortcutInfo si = (ShortcutInfo) info;
ComponentName cn = si.getTargetComponent();
@@ -301,7 +273,7 @@ public class LauncherModel extends BroadcastReceiver
}
}
- for (LauncherAppWidgetInfo widget : sBgAppWidgets) {
+ for (LauncherAppWidgetInfo widget : sBgDataModel.appWidgets) {
if (widget.providerName.getPackageName().equals(installInfo.packageName)) {
widget.installProgress = installInfo.progress;
updates.add(widget);
@@ -334,11 +306,11 @@ public class LauncherModel extends BroadcastReceiver
@Override
public void run() {
- synchronized (sBgLock) {
+ synchronized (sBgDataModel) {
ArrayList<ShortcutInfo> updates = new ArrayList<>();
UserHandleCompat user = UserHandleCompat.myUserHandle();
- for (ItemInfo info : sBgItemsIdMap) {
+ for (ItemInfo info : sBgDataModel.itemsIdMap) {
if (info instanceof ShortcutInfo) {
ShortcutInfo si = (ShortcutInfo) info;
ComponentName cn = si.getTargetComponent();
@@ -418,8 +390,8 @@ public class LauncherModel extends BroadcastReceiver
// Use sBgItemsIdMap as all the items are already loaded.
assertWorkspaceLoaded();
- synchronized (sBgLock) {
- for (ItemInfo info : sBgItemsIdMap) {
+ synchronized (sBgDataModel) {
+ for (ItemInfo info : sBgDataModel.itemsIdMap) {
if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
ArrayList<ItemInfo> items = screenItems.get(info.screenId);
if (items == null) {
@@ -496,7 +468,7 @@ public class LauncherModel extends BroadcastReceiver
// can not use sBgWorkspaceScreens because loadWorkspace() may not have been
// called.
ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);
- synchronized(sBgLock) {
+ synchronized(sBgDataModel) {
for (ItemInfo item : workspaceApps) {
if (item instanceof ShortcutInfo) {
// Short-circuit this logic if the icon exists somewhere on the workspace
@@ -578,7 +550,7 @@ public class LauncherModel extends BroadcastReceiver
static void checkItemInfoLocked(
final long itemId, final ItemInfo item, StackTraceElement[] stackTrace) {
- ItemInfo modelItem = sBgItemsIdMap.get(itemId);
+ ItemInfo modelItem = sBgDataModel.itemsIdMap.get(itemId);
if (modelItem != null && item != modelItem) {
// check all the data is consistent
if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {
@@ -619,7 +591,7 @@ public class LauncherModel extends BroadcastReceiver
final long itemId = item.id;
Runnable r = new Runnable() {
public void run() {
- synchronized (sBgLock) {
+ synchronized (sBgDataModel) {
checkItemInfoLocked(itemId, item, stackTrace);
}
}
@@ -675,13 +647,13 @@ public class LauncherModel extends BroadcastReceiver
static void updateItemArrays(ItemInfo item, long itemId, StackTraceElement[] stackTrace) {
// Lock on mBgLock *after* the db operation
- synchronized (sBgLock) {
+ synchronized (sBgDataModel) {
checkItemInfoLocked(itemId, item, stackTrace);
if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&
item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
// Item is in a folder, make sure this folder exists
- if (!sBgFolders.containsKey(item.container)) {
+ if (!sBgDataModel.folders.containsKey(item.container)) {
// An items container is being set to a that of an item which is not in
// the list of Folders.
String msg = "item: " + item + " container being set to: " +
@@ -693,7 +665,7 @@ public class LauncherModel extends BroadcastReceiver
// Items are added/removed from the corresponding FolderInfo elsewhere, such
// as in Workspace.onDrop. Here, we just add/remove them from the list of items
// that are on the desktop, as appropriate
- ItemInfo modelItem = sBgItemsIdMap.get(itemId);
+ ItemInfo modelItem = sBgDataModel.itemsIdMap.get(itemId);
if (modelItem != null &&
(modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)) {
@@ -702,15 +674,15 @@ public class LauncherModel extends BroadcastReceiver
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- if (!sBgWorkspaceItems.contains(modelItem)) {
- sBgWorkspaceItems.add(modelItem);
+ if (!sBgDataModel.workspaceItems.contains(modelItem)) {
+ sBgDataModel.workspaceItems.add(modelItem);
}
break;
default:
break;
}
} else {
- sBgWorkspaceItems.remove(modelItem);
+ sBgDataModel.workspaceItems.remove(modelItem);
}
}
}
@@ -854,8 +826,8 @@ public class LauncherModel extends BroadcastReceiver
intentWithoutPkg = intent.toUri(0);
}
- synchronized (sBgLock) {
- for (ItemInfo item : sBgItemsIdMap) {
+ synchronized (sBgDataModel) {
+ for (ItemInfo item : sBgDataModel.itemsIdMap) {
if (item instanceof ShortcutInfo) {
ShortcutInfo info = (ShortcutInfo) item;
Intent targetIntent = info.promisedIntent == null
@@ -906,76 +878,35 @@ public class LauncherModel extends BroadcastReceiver
public void run() {
cr.insert(LauncherSettings.Favorites.CONTENT_URI, values);
- // Lock on mBgLock *after* the db operation
- synchronized (sBgLock) {
+ synchronized (sBgDataModel) {
checkItemInfoLocked(item.id, item, stackTrace);
- sBgItemsIdMap.put(item.id, item);
- switch (item.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- sBgFolders.put(item.id, (FolderInfo) item);
- // Fall through
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
- if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
- item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- sBgWorkspaceItems.add(item);
- } else {
- if (!sBgFolders.containsKey(item.container)) {
- // Adding an item to a folder that doesn't exist.
- String msg = "adding item: " + item + " to a folder that " +
- " doesn't exist";
- Log.e(TAG, msg);
- }
- }
- if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
- incrementPinnedShortcutCount(
- ShortcutKey.fromShortcutInfo((ShortcutInfo) item),
- true /* shouldPin */);
- }
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
- sBgAppWidgets.add((LauncherAppWidgetInfo) item);
- break;
- }
+ sBgDataModel.addItem(item, true);
}
}
};
runOnWorkerThread(r);
}
- private static ArrayList<ItemInfo> getItemsByPackageName(
- final String pn, final UserHandleCompat user) {
- ItemInfoFilter filter = new ItemInfoFilter() {
- @Override
- public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {
- return cn.getPackageName().equals(pn) && info.user.equals(user);
- }
- };
- return filterItemInfos(sBgItemsIdMap, filter);
- }
-
- /**
- * Removes all the items from the database corresponding to the specified package.
- */
- static void deletePackageFromDatabase(Context context, final String pn,
- final UserHandleCompat user) {
- deleteItemsFromDatabase(context, getItemsByPackageName(pn, user));
- }
-
/**
* Removes the specified item from the database
*/
public static void deleteItemFromDatabase(Context context, final ItemInfo item) {
- ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();
+ ArrayList<ItemInfo> items = new ArrayList<>();
items.add(item);
deleteItemsFromDatabase(context, items);
}
/**
+ * Removes all the items from the database matching {@param matcher}.
+ */
+ public static void deleteItemsFromDatabase(Context context, ItemInfoMatcher matcher) {
+ deleteItemsFromDatabase(context, matcher.filterItemInfos(sBgDataModel.itemsIdMap));
+ }
+
+ /**
* Removes the specified items from the database
*/
- static void deleteItemsFromDatabase(Context context, final ArrayList<? extends ItemInfo> items) {
+ static void deleteItemsFromDatabase(Context context, final Iterable<? extends ItemInfo> items) {
final ContentResolver cr = context.getContentResolver();
Runnable r = new Runnable() {
public void run() {
@@ -983,36 +914,7 @@ public class LauncherModel extends BroadcastReceiver
final Uri uri = LauncherSettings.Favorites.getContentUri(item.id);
cr.delete(uri, null, null);
- // Lock on mBgLock *after* the db operation
- synchronized (sBgLock) {
- switch (item.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- sBgFolders.remove(item.id);
- 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.
- String msg = "deleting a folder (" + item + ") which still " +
- "contains items (" + info + ")";
- Log.e(TAG, msg);
- }
- }
- sBgWorkspaceItems.remove(item);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
- decrementPinnedShortcutCount(ShortcutKey.fromShortcutInfo(
- (ShortcutInfo) item));
- // Fall through.
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- sBgWorkspaceItems.remove(item);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
- sBgAppWidgets.remove((LauncherAppWidgetInfo) item);
- break;
- }
- sBgItemsIdMap.remove(item.id);
- }
+ sBgDataModel.removeItem(item);
}
}
};
@@ -1020,39 +922,6 @@ public class LauncherModel extends BroadcastReceiver
}
/**
- * Decrement the count for the given pinned shortcut, unpinning it if the count becomes 0.
- */
- private static void decrementPinnedShortcutCount(final ShortcutKey pinnedShortcut) {
- synchronized (sBgLock) {
- MutableInt count = sBgPinnedShortcutCounts.get(pinnedShortcut);
- if (count == null || --count.value == 0) {
- LauncherAppState.getInstance().getShortcutManager().unpinShortcut(pinnedShortcut);
- }
- }
- }
-
- /**
- * Increment the count for the given shortcut, pinning it if the count becomes 1.
- *
- * As an optimization, the caller can pass shouldPin == false to avoid
- * unnecessary RPC's if the shortcut is already pinned.
- */
- private static void incrementPinnedShortcutCount(ShortcutKey pinnedShortcut, boolean shouldPin) {
- synchronized (sBgLock) {
- MutableInt count = sBgPinnedShortcutCounts.get(pinnedShortcut);
- if (count == null) {
- count = new MutableInt(1);
- sBgPinnedShortcutCounts.put(pinnedShortcut, count);
- } else {
- count.value++;
- }
- if (shouldPin && count.value == 1) {
- LauncherAppState.getInstance().getShortcutManager().pinShortcut(pinnedShortcut);
- }
- }
- }
-
- /**
* Update the order of the workspace screens in the database. The array list contains
* a list of screen ids in the order that they should appear.
*/
@@ -1091,9 +960,9 @@ public class LauncherModel extends BroadcastReceiver
throw new RuntimeException(ex);
}
- synchronized (sBgLock) {
- sBgWorkspaceScreens.clear();
- sBgWorkspaceScreens.addAll(screensCopy);
+ synchronized (sBgDataModel) {
+ sBgDataModel.workspaceScreens.clear();
+ sBgDataModel.workspaceScreens.addAll(screensCopy);
}
}
};
@@ -1108,22 +977,13 @@ public class LauncherModel extends BroadcastReceiver
Runnable r = new Runnable() {
public void run() {
- cr.delete(LauncherSettings.Favorites.getContentUri(info.id), null, null);
- // Lock on mBgLock *after* the db operation
- synchronized (sBgLock) {
- sBgItemsIdMap.remove(info.id);
- sBgFolders.remove(info.id);
- sBgWorkspaceItems.remove(info);
- }
-
cr.delete(LauncherSettings.Favorites.CONTENT_URI,
LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);
- // Lock on mBgLock *after* the db operation
- synchronized (sBgLock) {
- for (ItemInfo childInfo : info.contents) {
- sBgItemsIdMap.remove(childInfo.id);
- }
- }
+ sBgDataModel.removeItem(info.contents);
+ info.contents.clear();
+
+ cr.delete(LauncherSettings.Favorites.getContentUri(info.id), null, null);
+ sBgDataModel.removeItem(info);
}
};
runOnWorkerThread(r);
@@ -1150,9 +1010,12 @@ public class LauncherModel extends BroadcastReceiver
@Override
public void onPackageRemoved(String packageName, UserHandleCompat user) {
+ onPackagesRemoved(user, packageName);
+ }
+
+ public void onPackagesRemoved(UserHandleCompat user, String... packages) {
int op = PackageUpdatedTask.OP_REMOVE;
- enqueueItemUpdatedTask(new PackageUpdatedTask(op, new String[] { packageName },
- user));
+ enqueueItemUpdatedTask(new PackageUpdatedTask(op, packages, user));
}
@Override
@@ -1639,18 +1502,6 @@ public class LauncherModel extends BroadcastReceiver
}
}
- /** Clears all the sBg data structures */
- private void clearSBgDataStructures() {
- synchronized (sBgLock) {
- sBgWorkspaceItems.clear();
- sBgAppWidgets.clear();
- sBgFolders.clear();
- sBgItemsIdMap.clear();
- sBgWorkspaceScreens.clear();
- sBgPinnedShortcutCounts.clear();
- }
- }
-
private void loadWorkspace() {
if (LauncherAppState.PROFILE_STARTUP) {
Trace.beginSection("Loading Workspace");
@@ -1663,6 +1514,7 @@ public class LauncherModel extends BroadcastReceiver
final boolean isSafeMode = manager.isSafeMode();
final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
final boolean isSdCardReady = Utilities.isBootCompleted();
+ final MultiHashMap<UserHandleCompat, String> pendingPackages = new MultiHashMap<>();
LauncherAppState app = LauncherAppState.getInstance();
InvariantDeviceProfile profile = app.getInvariantDeviceProfile();
@@ -1693,11 +1545,12 @@ public class LauncherModel extends BroadcastReceiver
LauncherSettings.Settings.call(contentResolver,
LauncherSettings.Settings.METHOD_LOAD_DEFAULT_FAVORITES);
- synchronized (sBgLock) {
- clearSBgDataStructures();
+ synchronized (sBgDataModel) {
+ sBgDataModel.clear();
+
final HashMap<String, Integer> installingPkgs = PackageInstallerCompat
.getInstance(mContext).updateAndGetActiveSessionCache();
- sBgWorkspaceScreens.addAll(loadWorkspaceScreensDb(mContext));
+ sBgDataModel.workspaceScreens.addAll(loadWorkspaceScreensDb(mContext));
final ArrayList<Long> itemsToRemove = new ArrayList<>();
final ArrayList<Long> restoredRows = new ArrayList<>();
@@ -1901,12 +1754,7 @@ public class LauncherModel extends BroadcastReceiver
// SdCard is not ready yet. Package might get available,
// once it is ready.
Log.d(TAG, "Invalid package: " + cn + " (check again later)");
- HashSet<String> pkgs = sPendingPackages.get(user);
- if (pkgs == null) {
- pkgs = new HashSet<String>();
- sPendingPackages.put(user, pkgs);
- }
- pkgs.add(cn.getPackageName());
+ pendingPackages.addToList(user, cn.getPackageName());
allowMissingTarget = true;
// Add the icon on the workspace anyway.
@@ -1977,7 +1825,6 @@ public class LauncherModel extends BroadcastReceiver
info.isDisabled |= ShortcutInfo.FLAG_DISABLED_LOCKED_USER;
}
- incrementPinnedShortcutCount(key, false /* shouldPin */);
} else { // item type == ITEM_TYPE_SHORTCUT
info = getShortcutInfo(c, cursorIconInfo);
@@ -2019,7 +1866,7 @@ public class LauncherModel extends BroadcastReceiver
}
// check & update map of what's occupied
- if (!checkItemPlacement(occupied, info, sBgWorkspaceScreens)) {
+ if (!checkItemPlacement(occupied, info, sBgDataModel.workspaceScreens)) {
itemsToRemove.add(id);
break;
}
@@ -2036,19 +1883,7 @@ public class LauncherModel extends BroadcastReceiver
}
}
- switch (container) {
- case LauncherSettings.Favorites.CONTAINER_DESKTOP:
- case LauncherSettings.Favorites.CONTAINER_HOTSEAT:
- sBgWorkspaceItems.add(info);
- break;
- default:
- // Item is in a user folder
- FolderInfo folderInfo =
- findOrMakeFolder(sBgFolders, container);
- folderInfo.add(info, false);
- break;
- }
- sBgItemsIdMap.put(info.id, info);
+ sBgDataModel.addItem(info, false);
} else {
throw new RuntimeException("Unexpected null ShortcutInfo");
}
@@ -2056,7 +1891,7 @@ public class LauncherModel extends BroadcastReceiver
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
id = c.getLong(idIndex);
- FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);
+ FolderInfo folderInfo = sBgDataModel.findOrMakeFolder(id);
// Do not trim the folder label, as is was set by the user.
folderInfo.title = c.getString(cursorIconInfo.titleIndex);
@@ -2070,25 +1905,16 @@ public class LauncherModel extends BroadcastReceiver
folderInfo.options = c.getInt(optionsIndex);
// check & update map of what's occupied
- if (!checkItemPlacement(occupied, folderInfo, sBgWorkspaceScreens)) {
+ if (!checkItemPlacement(occupied, folderInfo, sBgDataModel.workspaceScreens)) {
itemsToRemove.add(id);
break;
}
-
- switch (container) {
- case LauncherSettings.Favorites.CONTAINER_DESKTOP:
- case LauncherSettings.Favorites.CONTAINER_HOTSEAT:
- sBgWorkspaceItems.add(folderInfo);
- break;
- }
-
if (restored) {
// no special handling required for restored folders
restoredRows.add(id);
}
- sBgItemsIdMap.put(folderInfo.id, folderInfo);
- sBgFolders.put(folderInfo.id, folderInfo);
+ sBgDataModel.addItem(folderInfo, false);
break;
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
@@ -2205,7 +2031,7 @@ public class LauncherModel extends BroadcastReceiver
appWidgetInfo.container = container;
// check & update map of what's occupied
- if (!checkItemPlacement(occupied, appWidgetInfo, sBgWorkspaceScreens)) {
+ if (!checkItemPlacement(occupied, appWidgetInfo, sBgDataModel.workspaceScreens)) {
itemsToRemove.add(id);
break;
}
@@ -2224,8 +2050,7 @@ public class LauncherModel extends BroadcastReceiver
updateItem(id, values);
}
}
- sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);
- sBgAppWidgets.add(appWidgetInfo);
+ sBgDataModel.addItem(appWidgetInfo, false);
}
break;
}
@@ -2239,7 +2064,7 @@ public class LauncherModel extends BroadcastReceiver
// Break early if we've stopped loading
if (mStopped) {
- clearSBgDataStructures();
+ sBgDataModel.clear();
return;
}
@@ -2259,15 +2084,15 @@ public class LauncherModel extends BroadcastReceiver
LauncherSettings.Settings.METHOD_DELETE_EMPTY_FOLDERS)
.getSerializable(LauncherSettings.Settings.EXTRA_VALUE);
for (long folderId : deletedFolderIds) {
- sBgWorkspaceItems.remove(sBgFolders.get(folderId));
- sBgFolders.remove(folderId);
- sBgItemsIdMap.remove(folderId);
+ sBgDataModel.workspaceItems.remove(sBgDataModel.folders.get(folderId));
+ sBgDataModel.folders.remove(folderId);
+ sBgDataModel.itemsIdMap.remove(folderId);
}
}
// Unpin shortcuts that don't exist on the workspace.
for (ShortcutKey key : shortcutKeyToPinnedShortcuts.keySet()) {
- MutableInt numTimesPinned = sBgPinnedShortcutCounts.get(key);
+ MutableInt numTimesPinned = sBgDataModel.pinnedShortcutCounts.get(key);
if (numTimesPinned == null || numTimesPinned.value == 0) {
// Shortcut is pinned but doesn't exist on the workspace; unpin it.
mDeepShortcutManager.unpinShortcut(key);
@@ -2275,7 +2100,7 @@ public class LauncherModel extends BroadcastReceiver
}
// Sort all the folder items and make sure the first 3 items are high resolution.
- for (FolderInfo folder : sBgFolders) {
+ for (FolderInfo folder : sBgDataModel.folders) {
Collections.sort(folder.contents, Folder.ITEM_POS_COMPARATOR);
int pos = 0;
for (ShortcutInfo info : folder.contents) {
@@ -2298,15 +2123,18 @@ public class LauncherModel extends BroadcastReceiver
LauncherSettings.Favorites._ID, restoredRows), null);
}
- if (!isSdCardReady && !sPendingPackages.isEmpty()) {
- context.registerReceiver(new AppsAvailabilityCheck(),
+ if (!isSdCardReady && !pendingPackages.isEmpty()) {
+ context.registerReceiver(
+ new SdCardAvailableReceiver(
+ LauncherModel.this, mContext, pendingPackages),
new IntentFilter(Intent.ACTION_BOOT_COMPLETED),
- null, sWorker);
+ null,
+ sWorker);
}
// Remove any empty screens
- ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);
- for (ItemInfo item: sBgItemsIdMap) {
+ ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgDataModel.workspaceScreens);
+ for (ItemInfo item: sBgDataModel.itemsIdMap) {
long screenId = item.screenId;
if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
unusedScreens.contains(screenId)) {
@@ -2316,8 +2144,8 @@ public class LauncherModel extends BroadcastReceiver
// If there are any empty screens remove them, and update.
if (unusedScreens.size() != 0) {
- sBgWorkspaceScreens.removeAll(unusedScreens);
- updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);
+ sBgDataModel.workspaceScreens.removeAll(unusedScreens);
+ updateWorkspaceScreenOrder(context, sBgDataModel.workspaceScreens);
}
if (DEBUG_LOADERS) {
@@ -2530,10 +2358,10 @@ public class LauncherModel extends BroadcastReceiver
ArrayList<LauncherAppWidgetInfo> appWidgets = new ArrayList<>();
ArrayList<Long> orderedScreenIds = new ArrayList<>();
- synchronized (sBgLock) {
- workspaceItems.addAll(sBgWorkspaceItems);
- appWidgets.addAll(sBgAppWidgets);
- orderedScreenIds.addAll(sBgWorkspaceScreens);
+ synchronized (sBgDataModel) {
+ workspaceItems.addAll(sBgDataModel.workspaceItems);
+ appWidgets.addAll(sBgDataModel.appWidgets);
+ orderedScreenIds.addAll(sBgDataModel.workspaceScreens);
}
final int currentScreen;
@@ -2677,8 +2505,8 @@ public class LauncherModel extends BroadcastReceiver
private void updateIconCache() {
// Ignore packages which have a promise icon.
HashSet<String> packagesToIgnore = new HashSet<>();
- synchronized (sBgLock) {
- for (ItemInfo info : sBgItemsIdMap) {
+ synchronized (sBgDataModel) {
+ for (ItemInfo info : sBgDataModel.itemsIdMap) {
if (info instanceof ShortcutInfo) {
ShortcutInfo si = (ShortcutInfo) info;
if (si.isPromise() && si.getTargetComponent() != null) {
@@ -2841,11 +2669,11 @@ public class LauncherModel extends BroadcastReceiver
}
public void dumpState() {
- synchronized (sBgLock) {
+ synchronized (sBgDataModel) {
Log.d(TAG, "mLoaderTask.mContext=" + mContext);
Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);
Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);
- Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());
+ Log.d(TAG, "mItems size=" + sBgDataModel.workspaceItems.size());
}
}
}
@@ -2914,8 +2742,8 @@ public class LauncherModel extends BroadcastReceiver
// If any package icon has changed (app was updated while launcher was dead),
// update the corresponding shortcuts.
- synchronized (sBgLock) {
- for (ItemInfo info : sBgItemsIdMap) {
+ synchronized (sBgDataModel) {
+ for (ItemInfo info : sBgDataModel.itemsIdMap) {
if (info instanceof ShortcutInfo && user.equals(info.user)
&& info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
ShortcutInfo si = (ShortcutInfo) info;
@@ -2971,47 +2799,10 @@ public class LauncherModel extends BroadcastReceiver
sWorker.post(task);
}
- @Thunk class AppsAvailabilityCheck extends BroadcastReceiver {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- synchronized (sBgLock) {
- final LauncherAppsCompat launcherApps = LauncherAppsCompat
- .getInstance(mApp.getContext());
- final PackageManager manager = context.getPackageManager();
- final ArrayList<String> packagesRemoved = new ArrayList<String>();
- final ArrayList<String> packagesUnavailable = new ArrayList<String>();
- for (Entry<UserHandleCompat, HashSet<String>> entry : sPendingPackages.entrySet()) {
- UserHandleCompat user = entry.getKey();
- packagesRemoved.clear();
- packagesUnavailable.clear();
- for (String pkg : entry.getValue()) {
- if (!launcherApps.isPackageEnabledForProfile(pkg, user)) {
- if (PackageManagerHelper.isAppOnSdcard(manager, pkg)) {
- packagesUnavailable.add(pkg);
- } else {
- packagesRemoved.add(pkg);
- }
- }
- }
- if (!packagesRemoved.isEmpty()) {
- enqueueItemUpdatedTask(new PackageUpdatedTask(PackageUpdatedTask.OP_REMOVE,
- packagesRemoved.toArray(new String[packagesRemoved.size()]), user));
- }
- if (!packagesUnavailable.isEmpty()) {
- enqueueItemUpdatedTask(new PackageUpdatedTask(PackageUpdatedTask.OP_UNAVAILABLE,
- packagesUnavailable.toArray(new String[packagesUnavailable.size()]), user));
- }
- }
- sPendingPackages.clear();
- }
- }
- }
-
private class PackageUpdatedTask implements Runnable {
- int mOp;
- String[] mPackages;
- UserHandleCompat mUser;
+ final int mOp;
+ final String[] mPackages;
+ final UserHandleCompat mUser;
public static final int OP_NONE = 0;
public static final int OP_ADD = 1;
@@ -3038,7 +2829,7 @@ public class LauncherModel extends BroadcastReceiver
final String[] packages = mPackages;
final int N = packages.length;
FlagOp flagOp = FlagOp.NO_OP;
- StringFilter pkgFilter = StringFilter.of(new HashSet<>(Arrays.asList(packages)));
+ final HashSet<String> packageSet = new HashSet<>(Arrays.asList(packages));
switch (mOp) {
case OP_ADD: {
for (int i=0; i<N; i++) {
@@ -3088,15 +2879,15 @@ public class LauncherModel extends BroadcastReceiver
FlagOp.addFlag(ShortcutInfo.FLAG_DISABLED_SUSPENDED) :
FlagOp.removeFlag(ShortcutInfo.FLAG_DISABLED_SUSPENDED);
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.(un)suspend " + N);
- mBgAllAppsList.updatePackageFlags(pkgFilter, mUser, flagOp);
+ mBgAllAppsList.updateDisabledFlags(
+ ItemInfoMatcher.ofPackages(packageSet, mUser), flagOp);
break;
case OP_USER_AVAILABILITY_CHANGE:
flagOp = UserManagerCompat.getInstance(context).isQuietModeEnabled(mUser)
? FlagOp.addFlag(ShortcutInfo.FLAG_DISABLED_QUIET_USER)
: FlagOp.removeFlag(ShortcutInfo.FLAG_DISABLED_QUIET_USER);
// We want to update all packages for this user.
- pkgFilter = StringFilter.matchesAll();
- mBgAllAppsList.updatePackageFlags(pkgFilter, mUser, flagOp);
+ mBgAllAppsList.updateDisabledFlags(ItemInfoMatcher.ofUser(mUser), flagOp);
break;
}
@@ -3145,12 +2936,12 @@ public class LauncherModel extends BroadcastReceiver
// Update shortcut infos
if (mOp == OP_ADD || flagOp != FlagOp.NO_OP) {
- final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<ShortcutInfo>();
- final ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<ShortcutInfo>();
- final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<LauncherAppWidgetInfo>();
+ final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<>();
+ final ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<>();
+ final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<>();
- synchronized (sBgLock) {
- for (ItemInfo info : sBgItemsIdMap) {
+ synchronized (sBgDataModel) {
+ for (ItemInfo info : sBgDataModel.itemsIdMap) {
if (info instanceof ShortcutInfo && mUser.equals(info.user)) {
ShortcutInfo si = (ShortcutInfo) info;
boolean infoUpdated = false;
@@ -3158,8 +2949,8 @@ public class LauncherModel extends BroadcastReceiver
// Update shortcuts which use iconResource.
if ((si.iconResource != null)
- && pkgFilter.matches(si.iconResource.packageName)) {
- Bitmap icon = Utilities.createIconBitmap(
+ && packageSet.contains(si.iconResource.packageName)) {
+ Bitmap icon = LauncherIcons.createIconBitmap(
si.iconResource.packageName,
si.iconResource.resourceName, context);
if (icon != null) {
@@ -3170,7 +2961,7 @@ public class LauncherModel extends BroadcastReceiver
}
ComponentName cn = si.getTargetComponent();
- if (cn != null && pkgFilter.matches(cn.getPackageName())) {
+ if (cn != null && packageSet.contains(cn.getPackageName())) {
AppInfo appInfo = addedOrUpdatedApps.get(cn);
if (si.isPromise()) {
@@ -3235,7 +3026,7 @@ public class LauncherModel extends BroadcastReceiver
LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;
if (mUser.equals(widgetInfo.user)
&& widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)
- && pkgFilter.matches(widgetInfo.providerName.getPackageName())) {
+ && packageSet.contains(widgetInfo.providerName.getPackageName())) {
widgetInfo.restoreStatus &=
~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY &
~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
@@ -3293,12 +3084,10 @@ public class LauncherModel extends BroadcastReceiver
}
if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
- for (String pn : removedPackages) {
- deletePackageFromDatabase(context, pn, mUser);
- }
- for (ComponentName cn : removedComponents) {
- deleteItemsFromDatabase(context, getItemInfoForComponentName(cn, mUser));
- }
+ deleteItemsFromDatabase(
+ context, ItemInfoMatcher.ofPackages(removedPackages, mUser));
+ deleteItemsFromDatabase(
+ context, ItemInfoMatcher.ofComponents(removedComponents, mUser));
// Remove any queued items from the install queue
InstallShortcutReceiver.removeFromInstallQueue(context, removedPackages, mUser);
@@ -3383,7 +3172,7 @@ public class LauncherModel extends BroadcastReceiver
// Find ShortcutInfo's that have changed on the workspace.
final ArrayList<ShortcutInfo> removedShortcutInfos = new ArrayList<>();
MultiHashMap<String, ShortcutInfo> idsToWorkspaceShortcutInfos = new MultiHashMap<>();
- for (ItemInfo itemInfo : sBgItemsIdMap) {
+ for (ItemInfo itemInfo : sBgDataModel.itemsIdMap) {
if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
ShortcutInfo si = (ShortcutInfo) itemInfo;
if (si.getPromisedIntent().getPackage().equals(mPackageName)
@@ -3473,7 +3262,7 @@ public class LauncherModel extends BroadcastReceiver
// Update the workspace to reflect the changes to updated shortcuts residing on it.
ArrayList<ShortcutInfo> updatedShortcutInfos = new ArrayList<>();
ArrayList<ShortcutInfo> deletedShortcutInfos = new ArrayList<>();
- for (ItemInfo itemInfo : sBgItemsIdMap) {
+ for (ItemInfo itemInfo : sBgDataModel.itemsIdMap) {
if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
&& mUser.equals(itemInfo.user)) {
ShortcutInfo si = (ShortcutInfo) itemInfo;
@@ -3549,18 +3338,6 @@ public class LauncherModel extends BroadcastReceiver
return !launcherApps.isPackageEnabledForProfile(packageName, user);
}
- public static boolean isValidPackageActivity(Context context, ComponentName cn,
- UserHandleCompat user) {
- if (cn == null) {
- return false;
- }
- final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
- if (!launcherApps.isPackageEnabledForProfile(cn.getPackageName(), user)) {
- return false;
- }
- return launcherApps.isActivityEnabledForProfile(cn, user);
- }
-
public static boolean isValidPackage(Context context, String packageName,
UserHandleCompat user) {
if (packageName == null) {
@@ -3683,50 +3460,6 @@ public class LauncherModel extends BroadcastReceiver
return info;
}
- static ArrayList<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos,
- ItemInfoFilter f) {
- HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();
- for (ItemInfo i : infos) {
- if (i instanceof ShortcutInfo) {
- ShortcutInfo info = (ShortcutInfo) i;
- ComponentName cn = info.getTargetComponent();
- if (cn != null && f.filterItem(null, info, cn)) {
- filtered.add(info);
- }
- } else if (i instanceof FolderInfo) {
- FolderInfo info = (FolderInfo) i;
- for (ShortcutInfo s : info.contents) {
- ComponentName cn = s.getTargetComponent();
- if (cn != null && f.filterItem(info, s, cn)) {
- filtered.add(s);
- }
- }
- } else if (i instanceof LauncherAppWidgetInfo) {
- LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;
- ComponentName cn = info.providerName;
- if (cn != null && f.filterItem(null, info, cn)) {
- filtered.add(info);
- }
- }
- }
- return new ArrayList<ItemInfo>(filtered);
- }
-
- @Thunk ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname,
- final UserHandleCompat user) {
- ItemInfoFilter filter = new ItemInfoFilter() {
- @Override
- public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {
- if (info.user == null) {
- return cn.equals(cname);
- } else {
- return cn.equals(cname) && info.user.equals(user);
- }
- }
- };
- return filterItemInfos(sBgItemsIdMap, filter);
- }
-
/**
* Make an ShortcutInfo object for a shortcut that isn't an application.
*/
@@ -3768,17 +3501,15 @@ public class LauncherModel extends BroadcastReceiver
}
Bitmap icon = null;
- boolean customIcon = false;
ShortcutIconResource iconResource = null;
if (bitmap instanceof Bitmap) {
- icon = Utilities.createIconBitmap((Bitmap) bitmap, context);
- customIcon = true;
+ icon = LauncherIcons.createIconBitmap((Bitmap) bitmap, context);
} else {
Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
if (extra instanceof ShortcutIconResource) {
iconResource = (ShortcutIconResource) extra;
- icon = Utilities.createIconBitmap(iconResource.packageName,
+ icon = LauncherIcons.createIconBitmap(iconResource.packageName,
iconResource.resourceName, context);
}
}
@@ -3802,22 +3533,6 @@ public class LauncherModel extends BroadcastReceiver
return info;
}
- /**
- * Return an existing FolderInfo object if we have encountered this ID previously,
- * or make a new one.
- */
- @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) {
- // No placeholder -- create a new instance
- folderInfo = new FolderInfo();
- folders.put(id, folderInfo);
- }
- return folderInfo;
- }
-
-
static boolean isValidProvider(AppWidgetProviderInfo provider) {
return (provider != null) && (provider.provider != null)
&& (provider.provider.getPackageName() != null);
@@ -3844,8 +3559,8 @@ public class LauncherModel extends BroadcastReceiver
* @return {@link FolderInfo} if its already loaded.
*/
public FolderInfo findFolderById(Long folderId) {
- synchronized (sBgLock) {
- return sBgFolders.get(folderId);
+ synchronized (sBgDataModel) {
+ return sBgDataModel.folders.get(folderId);
}
}
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index f3d949326..e1ff6dbc1 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -764,12 +764,7 @@ public class LauncherProvider extends ContentProvider {
}
}
case 16: {
- // We use the db version upgrade here to identify users who may not have seen
- // clings yet (because they weren't available), but for whom the clings are now
- // available (tablet users). Because one of the possible cling flows (migration)
- // is very destructive (wipes out workspaces), we want to prevent this from showing
- // until clear data. We do so by marking that the clings have been shown.
- LauncherClings.markFirstRunClingDismissed(mContext);
+ // No-op
}
case 17: {
// No-op
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index bea55d215..0b9bf09df 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -98,7 +98,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
@ViewDebug.ExportedProperty(category = "launcher")
protected int mCurrentPage;
- protected int mRestorePage = INVALID_RESTORE_PAGE;
private int mChildCountOnLastLayout;
@ViewDebug.ExportedProperty(category = "launcher")
@@ -418,17 +417,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
}
/**
- * The restore page will be set in place of the current page at the next (likely first)
- * layout.
- */
- void setRestorePage(int restorePage) {
- mRestorePage = restorePage;
- }
- int getRestorePage() {
- return mRestorePage;
- }
-
- /**
* Should be called whenever the page changes. In the case of a scroll, we wait until the page
* has settled.
*/
@@ -879,12 +867,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
}
if (mScroller.isFinished() && mChildCountOnLastLayout != childCount) {
- if (mRestorePage != INVALID_RESTORE_PAGE) {
- setCurrentPage(mRestorePage);
- mRestorePage = INVALID_RESTORE_PAGE;
- } else {
- setCurrentPage(getNextPage());
- }
+ setCurrentPage(getNextPage());
}
mChildCountOnLastLayout = childCount;
diff --git a/src/com/android/launcher3/PinchToOverviewListener.java b/src/com/android/launcher3/PinchToOverviewListener.java
index 48a75d111..bc5ac2456 100644
--- a/src/com/android/launcher3/PinchToOverviewListener.java
+++ b/src/com/android/launcher3/PinchToOverviewListener.java
@@ -61,12 +61,12 @@ public class PinchToOverviewListener extends ScaleGestureDetector.SimpleOnScaleG
mPinchDetector = new ScaleGestureDetector((Context) mLauncher, this);
}
- public boolean onInterceptTouchEvent(MotionEvent ev) {
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
mPinchDetector.onTouchEvent(ev);
return mPinchStarted;
}
- public boolean onTouchEvent(MotionEvent ev) {
+ public boolean onControllerTouchEvent(MotionEvent ev) {
if (mPinchStarted) {
if (ev.getPointerCount() > 2) {
// Using more than two fingers causes weird behavior, so just cancel the pinch.
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index fb9374314..ce0629136 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -31,6 +31,7 @@ import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
/**
@@ -323,13 +324,13 @@ public class ShortcutInfo extends ItemInfo {
IconCache cache = launcherAppState.getIconCache();
Bitmap unbadgedBitmap = unbadgedDrawable == null
? cache.getDefaultIcon(UserHandleCompat.myUserHandle())
- : Utilities.createScaledBitmapWithoutShadow(unbadgedDrawable, context);
+ : LauncherIcons.createScaledBitmapWithoutShadow(unbadgedDrawable, context);
setIcon(getBadgedIcon(unbadgedBitmap, shortcutInfo, cache, context));
}
protected Bitmap getBadgedIcon(Bitmap unbadgedBitmap, ShortcutInfoCompat shortcutInfo,
IconCache cache, Context context) {
- unbadgedBitmap = Utilities.addShadowToIcon(unbadgedBitmap);
+ unbadgedBitmap = LauncherIcons.addShadowToIcon(unbadgedBitmap);
// Get the app info for the source activity.
AppInfo appInfo = new AppInfo();
appInfo.user = user;
@@ -338,9 +339,9 @@ public class ShortcutInfo extends ItemInfo {
cache.getTitleAndIcon(appInfo, shortcutInfo.getActivityInfo(context), false);
} catch (NullPointerException e) {
// This may happen when we fail to load the activity info. Worst case ignore badging.
- return Utilities.badgeIconForUser(unbadgedBitmap, user, context);
+ return LauncherIcons.badgeIconForUser(unbadgedBitmap, user, context);
}
- return Utilities.badgeWithBitmap(unbadgedBitmap, appInfo.iconBitmap, context);
+ return LauncherIcons.badgeWithBitmap(unbadgedBitmap, appInfo.iconBitmap, context);
}
/** Returns the ShortcutInfo id associated with the deep shortcut. */
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index b0e096a2e..b4f0a498c 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -31,19 +31,11 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.database.Cursor;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
-import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.PaintDrawable;
import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
@@ -62,11 +54,7 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
-import com.android.launcher3.compat.UserHandleCompat;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.config.ProviderConfig;
-import com.android.launcher3.graphics.ShadowGenerator;
-import com.android.launcher3.util.IconNormalizer;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
@@ -90,19 +78,9 @@ public final class Utilities {
private static final String TAG = "Launcher.Utilities";
- private static final Rect sOldBounds = new Rect();
- private static final Canvas sCanvas = new Canvas();
-
private static final Pattern sTrimPattern =
Pattern.compile("^[\\s|\\p{javaSpaceChar}]*(.*)[\\s|\\p{javaSpaceChar}]*$");
- static {
- sCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
- Paint.FILTER_BITMAP_FLAG));
- }
- static int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff };
- static int sColorIndex = 0;
-
private static final int[] sLoc0 = new int[2];
private static final int[] sLoc1 = new int[2];
@@ -170,198 +148,6 @@ public final class Utilities {
return false;
}
- public static Bitmap createIconBitmap(Cursor c, int iconIndex, Context context) {
- byte[] data = c.getBlob(iconIndex);
- try {
- return createIconBitmap(BitmapFactory.decodeByteArray(data, 0, data.length), context);
- } catch (Exception e) {
- return null;
- }
- }
-
- /**
- * Returns a bitmap suitable for the all apps view. If the package or the resource do not
- * exist, it returns null.
- */
- public static Bitmap createIconBitmap(String packageName, String resourceName,
- Context context) {
- PackageManager packageManager = context.getPackageManager();
- // the resource
- try {
- Resources resources = packageManager.getResourcesForApplication(packageName);
- if (resources != null) {
- final int id = resources.getIdentifier(resourceName, null, null);
- return createIconBitmap(
- resources.getDrawableForDensity(id, LauncherAppState.getInstance()
- .getInvariantDeviceProfile().fillResIconDpi), context);
- }
- } catch (Exception e) {
- // Icon not found.
- }
- return null;
- }
-
- private static int getIconBitmapSize() {
- return LauncherAppState.getInstance().getInvariantDeviceProfile().iconBitmapSize;
- }
-
- /**
- * Returns a bitmap which is of the appropriate size to be displayed as an icon
- */
- public static Bitmap createIconBitmap(Bitmap icon, Context context) {
- final int iconBitmapSize = getIconBitmapSize();
- if (iconBitmapSize == icon.getWidth() && iconBitmapSize == icon.getHeight()) {
- return icon;
- }
- return createIconBitmap(new BitmapDrawable(context.getResources(), icon), context);
- }
-
- /**
- * Returns a bitmap suitable for the all apps view. The icon is badged for {@param user}.
- * The bitmap is also visually normalized with other icons.
- */
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- public static Bitmap createBadgedIconBitmap(
- Drawable icon, UserHandleCompat user, Context context) {
- float scale = FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ?
- 1 : IconNormalizer.getInstance().getScale(icon, null);
- Bitmap bitmap = createIconBitmap(icon, context, scale);
- return badgeIconForUser(bitmap, user, context);
- }
-
- /**
- * Badges the provided icon with the user badge if required.
- */
- public static Bitmap badgeIconForUser(Bitmap icon, UserHandleCompat user, Context context) {
- if (Utilities.ATLEAST_LOLLIPOP && user != null
- && !UserHandleCompat.myUserHandle().equals(user)) {
- BitmapDrawable drawable = new FixedSizeBitmapDrawable(icon);
- Drawable badged = context.getPackageManager().getUserBadgedIcon(
- drawable, user.getUser());
- if (badged instanceof BitmapDrawable) {
- return ((BitmapDrawable) badged).getBitmap();
- } else {
- return createIconBitmap(badged, context);
- }
- } else {
- return icon;
- }
- }
-
- /**
- * Creates a normalized bitmap suitable for the all apps view. The bitmap is also visually
- * normalized with other icons and has enough spacing to add shadow.
- */
- public static Bitmap createScaledBitmapWithoutShadow(Drawable icon, Context context) {
- RectF iconBounds = new RectF();
- float scale = FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ?
- 1 : IconNormalizer.getInstance().getScale(icon, iconBounds);
- scale = Math.min(scale, ShadowGenerator.getScaleForBounds(iconBounds));
- return createIconBitmap(icon, context, scale);
- }
-
- /**
- * Adds a shadow to the provided icon. It assumes that the icon has already been scaled using
- * {@link #createScaledBitmapWithoutShadow(Drawable, Context)}
- */
- public static Bitmap addShadowToIcon(Bitmap icon) {
- return ShadowGenerator.getInstance().recreateIcon(icon);
- }
-
- /**
- * Adds the {@param badge} on top of {@param srcTgt} using the badge dimensions.
- */
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- public static Bitmap badgeWithBitmap(Bitmap srcTgt, Bitmap badge, Context context) {
- int badgeSize = context.getResources().getDimensionPixelSize(R.dimen.profile_badge_size);
- synchronized (sCanvas) {
- sCanvas.setBitmap(srcTgt);
- sCanvas.drawBitmap(badge, new Rect(0, 0, badge.getWidth(), badge.getHeight()),
- new Rect(srcTgt.getWidth() - badgeSize,
- srcTgt.getHeight() - badgeSize, srcTgt.getWidth(), srcTgt.getHeight()),
- new Paint(Paint.FILTER_BITMAP_FLAG));
- sCanvas.setBitmap(null);
- }
- return srcTgt;
- }
-
- /**
- * Returns a bitmap suitable for the all apps view.
- */
- public static Bitmap createIconBitmap(Drawable icon, Context context) {
- return createIconBitmap(icon, context, 1.0f /* scale */);
- }
-
- /**
- * @param scale the scale to apply before drawing {@param icon} on the canvas
- */
- public static Bitmap createIconBitmap(Drawable icon, Context context, float scale) {
- synchronized (sCanvas) {
- final int iconBitmapSize = getIconBitmapSize();
-
- int width = iconBitmapSize;
- int height = iconBitmapSize;
-
- if (icon instanceof PaintDrawable) {
- PaintDrawable painter = (PaintDrawable) icon;
- painter.setIntrinsicWidth(width);
- painter.setIntrinsicHeight(height);
- } else if (icon instanceof BitmapDrawable) {
- // Ensure the bitmap has a density.
- BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
- Bitmap bitmap = bitmapDrawable.getBitmap();
- if (bitmap != null && bitmap.getDensity() == Bitmap.DENSITY_NONE) {
- bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
- }
- }
- int sourceWidth = icon.getIntrinsicWidth();
- int sourceHeight = icon.getIntrinsicHeight();
- if (sourceWidth > 0 && sourceHeight > 0) {
- // Scale the icon proportionally to the icon dimensions
- final float ratio = (float) sourceWidth / sourceHeight;
- if (sourceWidth > sourceHeight) {
- height = (int) (width / ratio);
- } else if (sourceHeight > sourceWidth) {
- width = (int) (height * ratio);
- }
- }
-
- // no intrinsic size --> use default size
- int textureWidth = iconBitmapSize;
- int textureHeight = iconBitmapSize;
-
- final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
- Bitmap.Config.ARGB_8888);
- final Canvas canvas = sCanvas;
- canvas.setBitmap(bitmap);
-
- final int left = (textureWidth-width) / 2;
- final int top = (textureHeight-height) / 2;
-
- @SuppressWarnings("all") // suppress dead code warning
- final boolean debug = false;
- if (debug) {
- // draw a big box for the icon for debugging
- canvas.drawColor(sColors[sColorIndex]);
- if (++sColorIndex >= sColors.length) sColorIndex = 0;
- Paint debugPaint = new Paint();
- debugPaint.setColor(0xffcccc00);
- canvas.drawRect(left, top, left+width, top+height, debugPaint);
- }
-
- sOldBounds.set(icon.getBounds());
- icon.setBounds(left, top, left+width, top+height);
- canvas.save(Canvas.MATRIX_SAVE_FLAG);
- canvas.scale(scale, scale, textureWidth / 2, textureHeight / 2);
- icon.draw(canvas);
- canvas.restore();
- icon.setBounds(sOldBounds);
- canvas.setBitmap(null);
-
- return bitmap;
- }
- }
-
/**
* Given a coordinate relative to the descendant, find the coordinate in a parent view's
* coordinates.
@@ -880,28 +666,6 @@ public final class Utilities {
return c == null || c.isEmpty();
}
- /**
- * An extension of {@link BitmapDrawable} which returns the bitmap pixel size as intrinsic size.
- * This allows the badging to be done based on the action bitmap size rather than
- * the scaled bitmap size.
- */
- private static class FixedSizeBitmapDrawable extends BitmapDrawable {
-
- public FixedSizeBitmapDrawable(Bitmap bitmap) {
- super(null, bitmap);
- }
-
- @Override
- public int getIntrinsicHeight() {
- return getBitmap().getWidth();
- }
-
- @Override
- public int getIntrinsicWidth() {
- return getBitmap().getWidth();
- }
- }
-
public static int getColorAccent(Context context) {
TypedArray ta = context.obtainStyledAttributes(new int[]{android.R.attr.colorAccent});
int colorAccent = ta.getColor(0, 0);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index ea5401eb3..af4dc07e6 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -28,7 +28,6 @@ import android.annotation.SuppressLint;
import android.app.WallpaperManager;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -735,11 +734,7 @@ public class Workspace extends PagedView
addFullScreenPage(customScreen);
// Update the custom content hint
- if (mRestorePage != INVALID_RESTORE_PAGE) {
- mRestorePage = mRestorePage + 1;
- } else {
- setCurrentPage(getCurrentPage() + 1);
- }
+ setCurrentPage(getCurrentPage() + 1);
}
public void removeCustomContentPage() {
@@ -760,11 +755,7 @@ public class Workspace extends PagedView
mCustomContentCallbacks = null;
// Update the custom content hint
- if (mRestorePage != INVALID_RESTORE_PAGE) {
- mRestorePage = mRestorePage - 1;
- } else {
- setCurrentPage(getCurrentPage() - 1);
- }
+ setCurrentPage(getCurrentPage() - 1);
}
public void addToCustomContentPage(View customContent, CustomContentCallbacks callbacks,
@@ -1754,7 +1745,7 @@ public class Workspace extends PagedView
}
public boolean isOnOrMovingToCustomContent() {
- return hasCustomContent() && getNextPage() == 0 && mRestorePage == INVALID_RESTORE_PAGE;
+ return hasCustomContent() && getNextPage() == 0;
}
private void updateStateForCustomContent(int screenCenter) {
@@ -2007,7 +1998,7 @@ public class Workspace extends PagedView
public void exitWidgetResizeMode() {
DragLayer dragLayer = mLauncher.getDragLayer();
- dragLayer.clearAllResizeFrames();
+ dragLayer.clearResizeFrame();
}
@Override
@@ -2708,7 +2699,7 @@ public class Workspace extends PagedView
public void run() {
if (!isPageMoving() && !mIsSwitchingState) {
DragLayer dragLayer = mLauncher.getDragLayer();
- dragLayer.addResizeFrame(info, hostView, cellLayout);
+ dragLayer.addResizeFrame(hostView, cellLayout);
}
}
};
@@ -3998,63 +3989,34 @@ public class Workspace extends PagedView
for (final CellLayout layoutParent: cellLayouts) {
final ViewGroup layout = layoutParent.getShortcutsAndWidgets();
- final HashMap<ItemInfo, View> children = new HashMap<>();
+ LongArrayMap<View> idToViewMap = new LongArrayMap<>();
+ ArrayList<ItemInfo> items = new ArrayList<>();
for (int j = 0; j < layout.getChildCount(); j++) {
final View view = layout.getChildAt(j);
- children.put((ItemInfo) view.getTag(), view);
- }
-
- final ArrayList<View> childrenToRemove = new ArrayList<>();
- final HashMap<FolderInfo, ArrayList<ShortcutInfo>> folderAppsToRemove = new HashMap<>();
- LauncherModel.ItemInfoFilter filter = new LauncherModel.ItemInfoFilter() {
- @Override
- public boolean filterItem(ItemInfo parent, ItemInfo info,
- ComponentName cn) {
- if (parent instanceof FolderInfo) {
- if (matcher.matches(info, cn)) {
- FolderInfo folder = (FolderInfo) parent;
- ArrayList<ShortcutInfo> appsToRemove;
- if (folderAppsToRemove.containsKey(folder)) {
- appsToRemove = folderAppsToRemove.get(folder);
- } else {
- appsToRemove = new ArrayList<ShortcutInfo>();
- folderAppsToRemove.put(folder, appsToRemove);
- }
- appsToRemove.add((ShortcutInfo) info);
- return true;
- }
- } else {
- if (matcher.matches(info, cn)) {
- childrenToRemove.add(children.get(info));
- return true;
- }
- }
- return false;
- }
- };
- LauncherModel.filterItemInfos(children.keySet(), filter);
-
- // Remove all the apps from their folders
- for (FolderInfo folder : folderAppsToRemove.keySet()) {
- ArrayList<ShortcutInfo> appsToRemove = folderAppsToRemove.get(folder);
- for (ShortcutInfo info : appsToRemove) {
- folder.remove(info, false);
+ if (view.getTag() instanceof ItemInfo) {
+ ItemInfo item = (ItemInfo) view.getTag();
+ items.add(item);
+ idToViewMap.put(item.id, view);
}
}
- // Remove all the other children
- for (View child : childrenToRemove) {
- // Note: We can not remove the view directly from CellLayoutChildren as this
- // does not re-mark the spaces as unoccupied.
- layoutParent.removeViewInLayout(child);
- if (child instanceof DropTarget) {
- mDragController.removeDropTarget((DropTarget) child);
- }
- }
+ for (ItemInfo itemToRemove : matcher.filterItemInfos(items)) {
+ View child = idToViewMap.get(itemToRemove.id);
- if (childrenToRemove.size() > 0) {
- layout.requestLayout();
- layout.invalidate();
+ if (child != null) {
+ // Note: We can not remove the view directly from CellLayoutChildren as this
+ // does not re-mark the spaces as unoccupied.
+ layoutParent.removeViewInLayout(child);
+ if (child instanceof DropTarget) {
+ mDragController.removeDropTarget((DropTarget) child);
+ }
+ } else if (itemToRemove.container >= 0) {
+ // The item may belong to a folder.
+ View parent = idToViewMap.get(itemToRemove.container);
+ if (parent != null) {
+ ((FolderInfo) parent.getTag()).remove((ShortcutInfo) itemToRemove, false);
+ }
+ }
}
}
@@ -4155,8 +4117,9 @@ public class Workspace extends PagedView
public void removeAbandonedPromise(String packageName, UserHandleCompat user) {
HashSet<String> packages = new HashSet<>(1);
packages.add(packageName);
- LauncherModel.deletePackageFromDatabase(mLauncher, packageName, user);
- removeItemsByMatcher(ItemInfoMatcher.ofPackages(packages, user));
+ ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(packages, user);
+ LauncherModel.deleteItemsFromDatabase(mLauncher, matcher);
+ removeItemsByMatcher(matcher);
}
public void updateRestoreItems(final HashSet<ItemInfo> updates) {
@@ -4333,7 +4296,6 @@ public class Workspace extends PagedView
@Override
public boolean evaluate(ItemInfo info, View view) {
if (view instanceof PendingAppWidgetHostView && mInfos.contains(info)) {
- PendingAppWidgetHostView hostView = (PendingAppWidgetHostView) view;
mLauncher.removeItem(view, info, false /* deleteFromDb */);
mLauncher.bindAppWidget((LauncherAppWidgetInfo) info);
}
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 5892787f3..8fedc96c2 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -15,10 +15,8 @@
*/
package com.android.launcher3.allapps;
-import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Point;
import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.text.Selection;
@@ -31,7 +29,6 @@ import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.ViewGroup;
import com.android.launcher3.AppInfo;
@@ -43,6 +40,7 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget;
import com.android.launcher3.ExtendedEditText;
+import com.android.launcher3.Insettable;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherTransitionable;
@@ -134,7 +132,8 @@ final class SimpleSectionMergeAlgorithm implements AlphabeticalAppsList.MergeAlg
* The all apps view container.
*/
public class AllAppsContainerView extends BaseContainerView implements DragSource,
- LauncherTransitionable, View.OnLongClickListener, AllAppsSearchBarController.Callbacks {
+ LauncherTransitionable, View.OnLongClickListener, AllAppsSearchBarController.Callbacks,
+ Insettable {
private static final int MIN_ROWS_IN_MERGED_SECTION_PHONE = 3;
private static final int MAX_NUM_MERGES_PHONE = 2;
@@ -145,25 +144,18 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
private final RecyclerView.LayoutManager mLayoutManager;
private final RecyclerView.ItemDecoration mItemDecoration;
- // The computed bounds of the container
- private final Rect mContentBounds = new Rect();
-
private AllAppsRecyclerView mAppsRecyclerView;
private AllAppsSearchBarController mSearchBarController;
private View mSearchContainer;
private ExtendedEditText mSearchInput;
private HeaderElevationController mElevationController;
- private int mSearchContainerOffsetTop;
private SpannableStringBuilder mSearchQueryBuilder = null;
private int mSectionNamesMargin;
private int mNumAppsPerRow;
private int mNumPredictedAppsPerRow;
- private int mRecyclerViewBottomPadding;
- // This coordinate is relative to this container view
- private final Point mBoundsCheckLastTouchDownPos = new Point(-1, -1);
public AllAppsContainerView(Context context) {
this(context, null);
@@ -184,14 +176,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
mApps.setAdapter(mAdapter);
mLayoutManager = mAdapter.getLayoutManager();
mItemDecoration = mAdapter.getItemDecoration();
- DeviceProfile grid = mLauncher.getDeviceProfile();
- if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && !grid.isVerticalBarLayout()) {
- mRecyclerViewBottomPadding = 0;
- setPadding(0, 0, 0, 0);
- } else {
- mRecyclerViewBottomPadding =
- res.getDimensionPixelSize(R.dimen.all_apps_list_bottom_padding);
- }
mSearchQueryBuilder = new SpannableStringBuilder();
Selection.setSelection(mSearchQueryBuilder, 0);
}
@@ -340,9 +324,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
0, 1, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
mSearchInput.setHint(spanned);
- mSearchContainerOffsetTop = getResources().getDimensionPixelSize(
- R.dimen.all_apps_search_bar_margin_top);
-
mElevationController = Utilities.ATLEAST_LOLLIPOP
? new HeaderElevationController.ControllerVL(mSearchContainer)
: new HeaderElevationController.ControllerV16(mSearchContainer);
@@ -370,6 +351,19 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
getContentView().setVisibility(View.VISIBLE);
getContentView().setBackground(null);
}
+
+ int maxScrollBarWidth = mAppsRecyclerView.getMaxScrollbarWidth();
+ int startInset = Math.max(mSectionNamesMargin, maxScrollBarWidth);
+ if (Utilities.isRtl(getResources())) {
+ mAppsRecyclerView.setPadding(maxScrollBarWidth, 0, startInset, 0);
+ } else {
+ mAppsRecyclerView.setPadding(startInset, 0, maxScrollBarWidth, 0);
+ }
+ }
+
+ @Override
+ public View getTouchDelegateTargetView() {
+ return mAppsRecyclerView;
}
@Override
@@ -377,11 +371,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int widthPx = MeasureSpec.getSize(widthMeasureSpec);
- int heightPx = MeasureSpec.getSize(heightMeasureSpec);
- updatePaddingsAndMargins(widthPx, heightPx);
- mContentBounds.set(mContainerPaddingLeft, 0, widthPx - mContainerPaddingRight, heightPx);
-
DeviceProfile grid = mLauncher.getDeviceProfile();
grid.updateAppsViewNumCols();
if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
@@ -393,17 +382,12 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
mAppsRecyclerView.setNumAppsPerRow(grid, mNumAppsPerRow);
mAdapter.setNumAppsPerRow(mNumAppsPerRow);
mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow, new FullMergeAlgorithm());
- if (mNumAppsPerRow > 0) {
- int rvPadding = mAppsRecyclerView.getPaddingStart(); // Assumes symmetry
- final int thumbMaxWidth =
- getResources().getDimensionPixelSize(
- R.dimen.container_fastscroll_thumb_max_width);
- mSearchContainer.setPadding(
- rvPadding - mContainerPaddingLeft + thumbMaxWidth,
- mSearchContainer.getPaddingTop(),
- rvPadding - mContainerPaddingRight + thumbMaxWidth,
- mSearchContainer.getPaddingBottom());
- }
+ }
+ if (!grid.isVerticalBarLayout()) {
+ MarginLayoutParams searchContainerLp =
+ (MarginLayoutParams) mSearchContainer.getLayoutParams();
+ searchContainerLp.height = grid.hotseatBarHeightPx;
+ mSearchContainer.setLayoutParams(searchContainerLp);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
@@ -437,73 +421,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
- /**
- * Update the background and padding of the Apps view and children. Instead of insetting the
- * container view, we inset the background and padding of the recycler view to allow for the
- * recycler view to handle touch events (for fast scrolling) all the way to the edge.
- */
- private void updatePaddingsAndMargins(int widthPx, int heightPx) {
- Rect bgPadding = new Rect();
- getRevealView().getBackground().getPadding(bgPadding);
-
- mAppsRecyclerView.updateBackgroundPadding(bgPadding);
- mAdapter.updateBackgroundPadding(bgPadding);
- mElevationController.updateBackgroundPadding(bgPadding);
-
- // Pad the recycler view by the background padding plus the start margin (for the section
- // names)
- int maxScrollBarWidth = mAppsRecyclerView.getMaxScrollbarWidth();
- int startInset = Math.max(mSectionNamesMargin, maxScrollBarWidth);
- if (Utilities.isRtl(getResources())) {
- mAppsRecyclerView.setPadding(bgPadding.left + maxScrollBarWidth, 0, bgPadding.right
- + startInset, mRecyclerViewBottomPadding);
- } else {
- mAppsRecyclerView.setPadding(bgPadding.left + startInset, 0, bgPadding.right +
- maxScrollBarWidth, mRecyclerViewBottomPadding);
- }
-
- MarginLayoutParams lp = (MarginLayoutParams) mSearchContainer.getLayoutParams();
- lp.leftMargin = bgPadding.left;
- lp.rightMargin = bgPadding.right;
-
- // Clip the view to the left and right edge of the background to
- // to prevent shadows from rendering beyond the edges
- final Rect newClipBounds = new Rect(
- bgPadding.left, 0, widthPx - bgPadding.right, heightPx);
- setClipBounds(newClipBounds);
-
- // Allow the overscroll effect to reach the edges of the view
- mAppsRecyclerView.setClipToPadding(false);
-
- DeviceProfile grid = mLauncher.getDeviceProfile();
- if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
- if (!grid.isVerticalBarLayout()) {
- MarginLayoutParams mlp = (MarginLayoutParams) mAppsRecyclerView.getLayoutParams();
-
- Rect insets = mLauncher.getDragLayer().getInsets();
- getContentView().setPadding(0, 0, 0, 0);
- int height = insets.top + grid.hotseatCellHeightPx;
-
- mlp.topMargin = height;
- mAppsRecyclerView.setLayoutParams(mlp);
-
- mSearchContainer.setPadding(
- mSearchContainer.getPaddingLeft(),
- insets.top + mSearchContainerOffsetTop,
- mSearchContainer.getPaddingRight(),
- mSearchContainer.getPaddingBottom());
- lp.height = height;
-
- View navBarBg = findViewById(R.id.nav_bar_bg);
- ViewGroup.LayoutParams params = navBarBg.getLayoutParams();
- params.height = insets.bottom;
- navBarBg.setLayoutParams(params);
- navBarBg.setVisibility(View.VISIBLE);
- }
- }
- mSearchContainer.setLayoutParams(lp);
- }
-
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
// Determine if the key event was actual text, if so, focus the search bar and then dispatch
@@ -526,17 +443,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
}
@Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- return handleTouchEvent(ev);
- }
-
- @SuppressLint("ClickableViewAccessibility")
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- return handleTouchEvent(ev);
- }
-
- @Override
public boolean onLongClick(View v) {
// Return early if this is not initiated from a touch
if (!v.isInTouchMode()) return false;
@@ -660,55 +566,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
}
}
- /**
- * Handles the touch events to dismiss all apps when clicking outside the bounds of the
- * recycler view.
- */
- private boolean handleTouchEvent(MotionEvent ev) {
- DeviceProfile grid = mLauncher.getDeviceProfile();
- int x = (int) ev.getX();
- int y = (int) ev.getY();
-
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN:
- if (!mContentBounds.isEmpty()) {
- // Outset the fixed bounds and check if the touch is outside all apps
- Rect tmpRect = new Rect(mContentBounds);
- tmpRect.inset(-grid.allAppsIconSizePx / 2, 0);
- if (ev.getX() < tmpRect.left || ev.getX() > tmpRect.right) {
- mBoundsCheckLastTouchDownPos.set(x, y);
- return true;
- }
- } else {
- // Check if the touch is outside all apps
- if (ev.getX() < getPaddingLeft() ||
- ev.getX() > (getWidth() - getPaddingRight())) {
- mBoundsCheckLastTouchDownPos.set(x, y);
- return true;
- }
- }
- break;
- case MotionEvent.ACTION_UP:
- if (mBoundsCheckLastTouchDownPos.x > -1) {
- ViewConfiguration viewConfig = ViewConfiguration.get(getContext());
- float dx = ev.getX() - mBoundsCheckLastTouchDownPos.x;
- float dy = ev.getY() - mBoundsCheckLastTouchDownPos.y;
- float distance = (float) Math.hypot(dx, dy);
- if (distance < viewConfig.getScaledTouchSlop()) {
- // The background was clicked, so just go home
- Launcher launcher = (Launcher) getContext();
- launcher.showWorkspace(true);
- return true;
- }
- }
- // Fall through
- case MotionEvent.ACTION_CANCEL:
- mBoundsCheckLastTouchDownPos.set(-1, -1);
- break;
- }
- return false;
- }
-
@Override
public void onSearchResult(String query, ArrayList<ComponentKey> apps) {
if (apps != null) {
@@ -739,4 +596,22 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
public boolean shouldRestoreImeState() {
return !TextUtils.isEmpty(mSearchInput.getText());
}
+
+ @Override
+ public void setInsets(Rect insets) {
+ DeviceProfile grid = mLauncher.getDeviceProfile();
+ if (grid.isVerticalBarLayout()) {
+ ViewGroup.MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
+ mlp.leftMargin = insets.left;
+ mlp.topMargin = insets.top;
+ mlp.rightMargin = insets.right;
+ setLayoutParams(mlp);
+ } else {
+ View navBarBg = findViewById(R.id.nav_bar_bg);
+ ViewGroup.LayoutParams navBarBgLp = navBarBg.getLayoutParams();
+ navBarBgLp.height = insets.bottom;
+ navBarBg.setLayoutParams(navBarBgLp);
+ navBarBg.setVisibility(View.VISIBLE);
+ }
+ }
}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerViewContainerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerViewContainerView.java
index 1d5b209c2..cac388c2b 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerViewContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerViewContainerView.java
@@ -21,6 +21,7 @@ import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
+import android.widget.RelativeLayout;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.BubbleTextView.BubbleTextShadowHandler;
@@ -33,7 +34,7 @@ import com.android.launcher3.R;
* A container for RecyclerView to allow for the click shadow view to be shown behind an icon that
* is launching.
*/
-public class AllAppsRecyclerViewContainerView extends FrameLayout
+public class AllAppsRecyclerViewContainerView extends RelativeLayout
implements BubbleTextShadowHandler {
private final ClickShadowView mTouchFeedbackView;
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index fb15afecd..2b1a9da64 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -104,7 +104,7 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
}
@Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mNoIntercept = false;
if (!mLauncher.isAllAppsVisible() && mLauncher.getWorkspace().workspaceInModalState()) {
@@ -170,7 +170,7 @@ public class AllAppsTransitionController implements TouchController, VerticalPul
}
@Override
- public boolean onTouchEvent(MotionEvent ev) {
+ public boolean onControllerTouchEvent(MotionEvent ev) {
return mDetector.onTouchEvent(ev);
}
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index 6eb7dcc20..c7b66e7bd 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -456,7 +456,7 @@ public class DragController implements DragDriver.EventListener, TouchController
/**
* Call this from a drag source view.
*/
- public boolean onInterceptTouchEvent(MotionEvent ev) {
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
if (mOptions != null && mOptions.isAccessibleDrag) {
return false;
}
@@ -604,7 +604,7 @@ public class DragController implements DragDriver.EventListener, TouchController
/**
* Call this from a drag source view.
*/
- public boolean onTouchEvent(MotionEvent ev) {
+ public boolean onControllerTouchEvent(MotionEvent ev) {
if (mDragDriver == null || mOptions == null || mOptions.isAccessibleDrag) {
return false;
}
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 016347b17..e1c74bf6d 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -36,7 +36,6 @@ import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.DragEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -53,8 +52,6 @@ import com.android.launcher3.AppWidgetResizeFrame;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DropTargetBar;
import com.android.launcher3.InsettableFrameLayout;
-import com.android.launcher3.InstallShortcutReceiver;
-import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppWidgetHostView;
import com.android.launcher3.PinchToOverviewListener;
@@ -72,7 +69,6 @@ import com.android.launcher3.shortcuts.DeepShortcutsContainer;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.TouchController;
-import java.net.URISyntaxException;
import java.util.ArrayList;
/**
@@ -90,11 +86,9 @@ public class DragLayer extends InsettableFrameLayout {
@Thunk DragController mDragController;
- private int mXDown, mYDown;
private Launcher mLauncher;
// Variables relating to resizing widgets
- private final ArrayList<AppWidgetResizeFrame> mResizeFrames = new ArrayList<>();
private final boolean mIsRtl;
private AppWidgetResizeFrame mCurrentResizeFrame;
@@ -209,23 +203,6 @@ public class DragLayer extends InsettableFrameLayout {
}
private boolean handleTouchDown(MotionEvent ev, boolean intercept) {
- Rect hitRect = new Rect();
- int x = (int) ev.getX();
- int y = (int) ev.getY();
-
- for (AppWidgetResizeFrame child: mResizeFrames) {
- child.getHitRect(hitRect);
- if (hitRect.contains(x, y)) {
- if (child.beginResizeIfPointInRegion(x - child.getLeft(), y - child.getTop())) {
- mCurrentResizeFrame = child;
- mXDown = x;
- mYDown = y;
- requestDisallowInterceptTouchEvent(true);
- return true;
- }
- }
- }
-
// Remove the shortcuts container when touching outside of it.
DeepShortcutsContainer deepShortcutsContainer = mLauncher.getOpenShortcutsContainer();
if (deepShortcutsContainer != null) {
@@ -289,21 +266,27 @@ public class DragLayer extends InsettableFrameLayout {
}
mTouchCompleteListener = null;
}
- clearAllResizeFrames();
-
mActiveController = null;
- if (mDragController.onInterceptTouchEvent(ev)) {
+ if (mCurrentResizeFrame != null
+ && mCurrentResizeFrame.onControllerInterceptTouchEvent(ev)) {
+ mActiveController = mCurrentResizeFrame;
+ return true;
+ } else {
+ clearResizeFrame();
+ }
+
+ if (mDragController.onControllerInterceptTouchEvent(ev)) {
mActiveController = mDragController;
return true;
}
- if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && mAllAppsController.onInterceptTouchEvent(ev)) {
+ if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && mAllAppsController.onControllerInterceptTouchEvent(ev)) {
mActiveController = mAllAppsController;
return true;
}
- if (mPinchListener != null && mPinchListener.onInterceptTouchEvent(ev)) {
+ if (mPinchListener != null && mPinchListener.onControllerInterceptTouchEvent(ev)) {
// Stop listening for scrolling etc. (onTouchEvent() handles the rest of the pinch.)
mActiveController = mPinchListener;
return true;
@@ -405,12 +388,8 @@ public class DragLayer extends InsettableFrameLayout {
@Override
public boolean onTouchEvent(MotionEvent ev) {
- boolean handled = false;
int action = ev.getAction();
- int x = (int) ev.getX();
- int y = (int) ev.getY();
-
if (action == MotionEvent.ACTION_DOWN) {
if (handleTouchDown(ev, false)) {
return true;
@@ -422,22 +401,8 @@ public class DragLayer extends InsettableFrameLayout {
mTouchCompleteListener = null;
}
- if (mCurrentResizeFrame != null) {
- handled = true;
- switch (action) {
- case MotionEvent.ACTION_MOVE:
- mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
- break;
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
- mCurrentResizeFrame.onTouchUp();
- mCurrentResizeFrame = null;
- }
- }
- if (handled) return true;
if (mActiveController != null) {
- return mActiveController.onTouchEvent(ev);
+ return mActiveController.onControllerTouchEvent(ev);
}
return false;
}
@@ -645,36 +610,24 @@ public class DragLayer extends InsettableFrameLayout {
}
}
- public void clearAllResizeFrames() {
- if (mResizeFrames.size() > 0) {
- for (AppWidgetResizeFrame frame: mResizeFrames) {
- frame.commitResize();
- removeView(frame);
- }
- mResizeFrames.clear();
+ public void clearResizeFrame() {
+ if (mCurrentResizeFrame != null) {
+ mCurrentResizeFrame.commitResize();
+ removeView(mCurrentResizeFrame);
+ mCurrentResizeFrame = null;
}
}
- public boolean hasResizeFrames() {
- return mResizeFrames.size() > 0;
- }
+ public void addResizeFrame(LauncherAppWidgetHostView widget, CellLayout cellLayout) {
+ clearResizeFrame();
- public boolean isWidgetBeingResized() {
- return mCurrentResizeFrame != null;
- }
-
- public void addResizeFrame(ItemInfo itemInfo, LauncherAppWidgetHostView widget,
- CellLayout cellLayout) {
- AppWidgetResizeFrame resizeFrame = new AppWidgetResizeFrame(getContext(),
- widget, cellLayout, this);
+ mCurrentResizeFrame = new AppWidgetResizeFrame(getContext(), widget, cellLayout, this);
LayoutParams lp = new LayoutParams(-1, -1);
lp.customPosition = true;
- addView(resizeFrame, lp);
- mResizeFrames.add(resizeFrame);
-
- resizeFrame.snapToWidget(false);
+ addView(mCurrentResizeFrame, lp);
+ mCurrentResizeFrame.snapToWidget(false);
}
public void animateViewIntoPosition(DragView dragView, final int[] pos, float alpha,
diff --git a/src/com/android/launcher3/dragndrop/ExternalDragPreviewProvider.java b/src/com/android/launcher3/dragndrop/ExternalDragPreviewProvider.java
index 6b14be714..ac50332bf 100644
--- a/src/com/android/launcher3/dragndrop/ExternalDragPreviewProvider.java
+++ b/src/com/android/launcher3/dragndrop/ExternalDragPreviewProvider.java
@@ -23,10 +23,10 @@ import android.graphics.Paint;
import android.graphics.Rect;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.HolographicOutlineHelper;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.graphics.DragPreviewProvider;
+import com.android.launcher3.graphics.HolographicOutlineHelper;
/**
* Extension of {@link DragPreviewProvider} which provides a dummy outline when drag starts from
@@ -72,7 +72,7 @@ public class ExternalDragPreviewProvider extends DragPreviewProvider {
canvas.drawCircle(DRAG_BITMAP_PADDING / 2 + radius,
DRAG_BITMAP_PADDING / 2 + radius, radius * 0.9f, paint);
- HolographicOutlineHelper.obtain(mLauncher).applyExpensiveOutlineWithBlur(b, canvas);
+ HolographicOutlineHelper.getInstance(mLauncher).applyExpensiveOutlineWithBlur(b, canvas);
canvas.setBitmap(null);
return b;
}
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index bc91c15be..7ad1e3a43 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -24,7 +24,6 @@ import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.TextView;
-import com.android.launcher3.HolographicOutlineHelper;
import com.android.launcher3.Launcher;
import com.android.launcher3.PreloadIconDrawable;
import com.android.launcher3.Workspace;
@@ -137,7 +136,7 @@ public class DragPreviewProvider {
mView.getHeight() + DRAG_BITMAP_PADDING, Bitmap.Config.ALPHA_8);
canvas.setBitmap(b);
drawDragView(canvas);
- HolographicOutlineHelper.obtain(mView.getContext())
+ HolographicOutlineHelper.getInstance(mView.getContext())
.applyExpensiveOutlineWithBlur(b, canvas);
canvas.setBitmap(null);
return b;
diff --git a/src/com/android/launcher3/HolographicOutlineHelper.java b/src/com/android/launcher3/graphics/HolographicOutlineHelper.java
index 9dec7d9e4..0d70bdee1 100644
--- a/src/com/android/launcher3/HolographicOutlineHelper.java
+++ b/src/com/android/launcher3/graphics/HolographicOutlineHelper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.launcher3;
+package com.android.launcher3.graphics;
import android.content.Context;
import android.content.res.Resources;
@@ -29,6 +29,8 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.SparseArray;
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.R;
import com.android.launcher3.config.ProviderConfig;
import java.nio.ByteBuffer;
@@ -72,9 +74,9 @@ public class HolographicOutlineHelper {
mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
}
- public static HolographicOutlineHelper obtain(Context context) {
+ public static HolographicOutlineHelper getInstance(Context context) {
if (sInstance == null) {
- sInstance = new HolographicOutlineHelper(context);
+ sInstance = new HolographicOutlineHelper(context.getApplicationContext());
}
return sInstance;
}
@@ -155,11 +157,11 @@ public class HolographicOutlineHelper {
thickInnerBlur.recycle();
}
- Bitmap createMediumDropShadow(BubbleTextView view) {
+ public Bitmap createMediumDropShadow(BubbleTextView view) {
return createMediumDropShadow(view.getIcon(), view.getScaleX(), view.getScaleY(), true);
}
- Bitmap createMediumDropShadow(Drawable drawable, boolean shouldCache) {
+ public Bitmap createMediumDropShadow(Drawable drawable, boolean shouldCache) {
return createMediumDropShadow(drawable, 1f, 1f, shouldCache);
}
diff --git a/src/com/android/launcher3/util/IconNormalizer.java b/src/com/android/launcher3/graphics/IconNormalizer.java
index 040a1b51a..f90b2d72e 100644
--- a/src/com/android/launcher3/util/IconNormalizer.java
+++ b/src/com/android/launcher3/graphics/IconNormalizer.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.launcher3.util;
+package com.android.launcher3.graphics;
import android.graphics.Bitmap;
import android.graphics.Canvas;
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
new file mode 100644
index 000000000..9f3f3571d
--- /dev/null
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.graphics;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.PaintDrawable;
+import android.os.Build;
+
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.config.FeatureFlags;
+
+/**
+ * Helper methods for generating various launcher icons
+ */
+public class LauncherIcons {
+
+ private static final Rect sOldBounds = new Rect();
+ private static final Canvas sCanvas = new Canvas();
+
+ static {
+ sCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
+ Paint.FILTER_BITMAP_FLAG));
+ }
+
+
+ public static Bitmap createIconBitmap(Cursor c, int iconIndex, Context context) {
+ byte[] data = c.getBlob(iconIndex);
+ try {
+ return createIconBitmap(BitmapFactory.decodeByteArray(data, 0, data.length), context);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns a bitmap suitable for the all apps view. If the package or the resource do not
+ * exist, it returns null.
+ */
+ public static Bitmap createIconBitmap(String packageName, String resourceName,
+ Context context) {
+ PackageManager packageManager = context.getPackageManager();
+ // the resource
+ try {
+ Resources resources = packageManager.getResourcesForApplication(packageName);
+ if (resources != null) {
+ final int id = resources.getIdentifier(resourceName, null, null);
+ return createIconBitmap(
+ resources.getDrawableForDensity(id, LauncherAppState.getInstance()
+ .getInvariantDeviceProfile().fillResIconDpi), context);
+ }
+ } catch (Exception e) {
+ // Icon not found.
+ }
+ return null;
+ }
+
+ private static int getIconBitmapSize() {
+ return LauncherAppState.getInstance().getInvariantDeviceProfile().iconBitmapSize;
+ }
+
+ /**
+ * Returns a bitmap which is of the appropriate size to be displayed as an icon
+ */
+ public static Bitmap createIconBitmap(Bitmap icon, Context context) {
+ final int iconBitmapSize = getIconBitmapSize();
+ if (iconBitmapSize == icon.getWidth() && iconBitmapSize == icon.getHeight()) {
+ return icon;
+ }
+ return createIconBitmap(new BitmapDrawable(context.getResources(), icon), context);
+ }
+
+ /**
+ * Returns a bitmap suitable for the all apps view. The icon is badged for {@param user}.
+ * The bitmap is also visually normalized with other icons.
+ */
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public static Bitmap createBadgedIconBitmap(
+ Drawable icon, UserHandleCompat user, Context context) {
+ float scale = FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ?
+ 1 : IconNormalizer.getInstance().getScale(icon, null);
+ Bitmap bitmap = createIconBitmap(icon, context, scale);
+ return badgeIconForUser(bitmap, user, context);
+ }
+
+ /**
+ * Badges the provided icon with the user badge if required.
+ */
+ public static Bitmap badgeIconForUser(Bitmap icon, UserHandleCompat user, Context context) {
+ if (Utilities.ATLEAST_LOLLIPOP && user != null
+ && !UserHandleCompat.myUserHandle().equals(user)) {
+ BitmapDrawable drawable = new FixedSizeBitmapDrawable(icon);
+ Drawable badged = context.getPackageManager().getUserBadgedIcon(
+ drawable, user.getUser());
+ if (badged instanceof BitmapDrawable) {
+ return ((BitmapDrawable) badged).getBitmap();
+ } else {
+ return createIconBitmap(badged, context);
+ }
+ } else {
+ return icon;
+ }
+ }
+
+ /**
+ * Creates a normalized bitmap suitable for the all apps view. The bitmap is also visually
+ * normalized with other icons and has enough spacing to add shadow.
+ */
+ public static Bitmap createScaledBitmapWithoutShadow(Drawable icon, Context context) {
+ RectF iconBounds = new RectF();
+ float scale = FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ?
+ 1 : IconNormalizer.getInstance().getScale(icon, iconBounds);
+ scale = Math.min(scale, ShadowGenerator.getScaleForBounds(iconBounds));
+ return createIconBitmap(icon, context, scale);
+ }
+
+ /**
+ * Adds a shadow to the provided icon. It assumes that the icon has already been scaled using
+ * {@link #createScaledBitmapWithoutShadow(Drawable, Context)}
+ */
+ public static Bitmap addShadowToIcon(Bitmap icon) {
+ return ShadowGenerator.getInstance().recreateIcon(icon);
+ }
+
+ /**
+ * Adds the {@param badge} on top of {@param srcTgt} using the badge dimensions.
+ */
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public static Bitmap badgeWithBitmap(Bitmap srcTgt, Bitmap badge, Context context) {
+ int badgeSize = context.getResources().getDimensionPixelSize(R.dimen.profile_badge_size);
+ synchronized (sCanvas) {
+ sCanvas.setBitmap(srcTgt);
+ sCanvas.drawBitmap(badge, new Rect(0, 0, badge.getWidth(), badge.getHeight()),
+ new Rect(srcTgt.getWidth() - badgeSize,
+ srcTgt.getHeight() - badgeSize, srcTgt.getWidth(), srcTgt.getHeight()),
+ new Paint(Paint.FILTER_BITMAP_FLAG));
+ sCanvas.setBitmap(null);
+ }
+ return srcTgt;
+ }
+
+ /**
+ * Returns a bitmap suitable for the all apps view.
+ */
+ public static Bitmap createIconBitmap(Drawable icon, Context context) {
+ return createIconBitmap(icon, context, 1.0f /* scale */);
+ }
+
+ /**
+ * @param scale the scale to apply before drawing {@param icon} on the canvas
+ */
+ public static Bitmap createIconBitmap(Drawable icon, Context context, float scale) {
+ synchronized (sCanvas) {
+ final int iconBitmapSize = getIconBitmapSize();
+
+ int width = iconBitmapSize;
+ int height = iconBitmapSize;
+
+ if (icon instanceof PaintDrawable) {
+ PaintDrawable painter = (PaintDrawable) icon;
+ painter.setIntrinsicWidth(width);
+ painter.setIntrinsicHeight(height);
+ } else if (icon instanceof BitmapDrawable) {
+ // Ensure the bitmap has a density.
+ BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
+ Bitmap bitmap = bitmapDrawable.getBitmap();
+ if (bitmap != null && bitmap.getDensity() == Bitmap.DENSITY_NONE) {
+ bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
+ }
+ }
+ int sourceWidth = icon.getIntrinsicWidth();
+ int sourceHeight = icon.getIntrinsicHeight();
+ if (sourceWidth > 0 && sourceHeight > 0) {
+ // Scale the icon proportionally to the icon dimensions
+ final float ratio = (float) sourceWidth / sourceHeight;
+ if (sourceWidth > sourceHeight) {
+ height = (int) (width / ratio);
+ } else if (sourceHeight > sourceWidth) {
+ width = (int) (height * ratio);
+ }
+ }
+
+ // no intrinsic size --> use default size
+ int textureWidth = iconBitmapSize;
+ int textureHeight = iconBitmapSize;
+
+ final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
+ Bitmap.Config.ARGB_8888);
+ final Canvas canvas = sCanvas;
+ canvas.setBitmap(bitmap);
+
+ final int left = (textureWidth-width) / 2;
+ final int top = (textureHeight-height) / 2;
+
+ sOldBounds.set(icon.getBounds());
+ icon.setBounds(left, top, left+width, top+height);
+ canvas.save(Canvas.MATRIX_SAVE_FLAG);
+ canvas.scale(scale, scale, textureWidth / 2, textureHeight / 2);
+ icon.draw(canvas);
+ canvas.restore();
+ icon.setBounds(sOldBounds);
+ canvas.setBitmap(null);
+
+ return bitmap;
+ }
+ }
+
+ /**
+ * An extension of {@link BitmapDrawable} which returns the bitmap pixel size as intrinsic size.
+ * This allows the badging to be done based on the action bitmap size rather than
+ * the scaled bitmap size.
+ */
+ private static class FixedSizeBitmapDrawable extends BitmapDrawable {
+
+ public FixedSizeBitmapDrawable(Bitmap bitmap) {
+ super(null, bitmap);
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return getBitmap().getWidth();
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return getBitmap().getWidth();
+ }
+ }
+}
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
new file mode 100644
index 000000000..2b7039928
--- /dev/null
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.model;
+
+import android.util.Log;
+import android.util.MutableInt;
+
+import com.android.launcher3.FolderInfo;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.config.ProviderConfig;
+import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.util.LongArrayMap;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * All the data stored in-memory and managed by the LauncherModel
+ */
+public class BgDataModel {
+
+ private static final String TAG = "BgDataModel";
+
+ /**
+ * Map of all the ItemInfos (shortcuts, folders, and widgets) created by
+ * LauncherModel to their ids
+ */
+ public final LongArrayMap<ItemInfo> itemsIdMap = new LongArrayMap<>();
+
+ /**
+ * List of all the folders and shortcuts directly on the home screen (no widgets
+ * or shortcuts within folders).
+ */
+ public final ArrayList<ItemInfo> workspaceItems = new ArrayList<>();
+
+ /**
+ * All LauncherAppWidgetInfo created by LauncherModel.
+ */
+ public final ArrayList<LauncherAppWidgetInfo> appWidgets = new ArrayList<>();
+
+ /**
+ * Map of id to FolderInfos of all the folders created by LauncherModel
+ */
+ public final LongArrayMap<FolderInfo> folders = new LongArrayMap<>();
+
+ /**
+ * Ordered list of workspace screens ids.
+ */
+ public final ArrayList<Long> workspaceScreens = new ArrayList<>();
+
+ /**
+ * Map of ShortcutKey to the number of times it is pinned.
+ */
+ public final Map<ShortcutKey, MutableInt> pinnedShortcutCounts = new HashMap<>();
+
+ /**
+ * Clears all the data
+ */
+ public synchronized void clear() {
+ workspaceItems.clear();
+ appWidgets.clear();
+ folders.clear();
+ itemsIdMap.clear();
+ workspaceScreens.clear();
+ pinnedShortcutCounts.clear();
+ }
+
+ public synchronized void removeItem(ItemInfo... items) {
+ removeItem(Arrays.asList(items));
+ }
+
+ public synchronized void removeItem(Iterable<? extends ItemInfo> items) {
+ for (ItemInfo item : items) {
+ switch (item.itemType) {
+ case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
+ folders.remove(item.id);
+ if (ProviderConfig.IS_DOGFOOD_BUILD) {
+ for (ItemInfo info : itemsIdMap) {
+ if (info.container == item.id) {
+ // We are deleting a folder which still contains items that
+ // think they are contained by that folder.
+ String msg = "deleting a folder (" + item + ") which still " +
+ "contains items (" + info + ")";
+ Log.e(TAG, msg);
+ }
+ }
+ }
+ workspaceItems.remove(item);
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: {
+ // Decrement pinned shortcut count
+ ShortcutKey pinnedShortcut = ShortcutKey.fromShortcutInfo((ShortcutInfo) item);
+ MutableInt count = pinnedShortcutCounts.get(pinnedShortcut);
+ if (count == null || --count.value == 0) {
+ LauncherAppState.getInstance()
+ .getShortcutManager().unpinShortcut(pinnedShortcut);
+ }
+ // Fall through.
+ }
+ case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+ case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+ workspaceItems.remove(item);
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+ case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
+ appWidgets.remove(item);
+ break;
+ }
+ itemsIdMap.remove(item.id);
+ }
+ }
+
+ public synchronized void addItem(ItemInfo item, boolean newItem) {
+ itemsIdMap.put(item.id, item);
+ switch (item.itemType) {
+ case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
+ folders.put(item.id, (FolderInfo) item);
+ workspaceItems.add(item);
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: {
+ // Increment the count for the given shortcut
+ ShortcutKey pinnedShortcut = ShortcutKey.fromShortcutInfo((ShortcutInfo) item);
+ MutableInt count = pinnedShortcutCounts.get(pinnedShortcut);
+ if (count == null) {
+ count = new MutableInt(1);
+ pinnedShortcutCounts.put(pinnedShortcut, count);
+ } else {
+ count.value++;
+ }
+
+ // Since this is a new item, pin the shortcut in the system server.
+ if (newItem && count.value == 1) {
+ LauncherAppState.getInstance().getShortcutManager()
+ .pinShortcut(pinnedShortcut);
+ }
+ // Fall through
+ }
+ case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+ case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+ if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
+ item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+ workspaceItems.add(item);
+ } else {
+ if (newItem) {
+ if (!folders.containsKey(item.container)) {
+ // Adding an item to a folder that doesn't exist.
+ String msg = "adding item: " + item + " to a folder that " +
+ " doesn't exist";
+ Log.e(TAG, msg);
+ }
+ } else {
+ findOrMakeFolder(item.container).add((ShortcutInfo) item, false);
+ }
+
+ }
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+ case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
+ appWidgets.add((LauncherAppWidgetInfo) item);
+ break;
+ }
+ }
+
+ /**
+ * Return an existing FolderInfo object if we have encountered this ID previously,
+ * or make a new one.
+ */
+ public synchronized FolderInfo findOrMakeFolder(long id) {
+ // See if a placeholder was created for us already
+ FolderInfo folderInfo = folders.get(id);
+ if (folderInfo == null) {
+ // No placeholder -- create a new instance
+ folderInfo = new FolderInfo();
+ folders.put(id, folderInfo);
+ }
+ return folderInfo;
+ }
+}
diff --git a/src/com/android/launcher3/model/SdCardAvailableReceiver.java b/src/com/android/launcher3/model/SdCardAvailableReceiver.java
new file mode 100644
index 000000000..54260c915
--- /dev/null
+++ b/src/com/android/launcher3/model/SdCardAvailableReceiver.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel;
+import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.util.MultiHashMap;
+import com.android.launcher3.util.PackageManagerHelper;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Map.Entry;
+
+/**
+ * Helper class to re-query app status when SD-card becomes available.
+ *
+ * During first load, just after reboot, some apps on sdcard might not be available immediately due
+ * to some race conditions in the system. We wait for ACTION_BOOT_COMPLETED and process such
+ * apps again.
+ */
+public class SdCardAvailableReceiver extends BroadcastReceiver {
+
+ private final LauncherModel mModel;
+ private final Context mContext;
+ private final MultiHashMap<UserHandleCompat, String> mPackages;
+
+ public SdCardAvailableReceiver(LauncherModel model, Context context,
+ MultiHashMap<UserHandleCompat, String> packages) {
+ mModel = model;
+ mContext = context;
+ mPackages = packages;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
+ final PackageManager manager = context.getPackageManager();
+ for (Entry<UserHandleCompat, ArrayList<String>> entry : mPackages.entrySet()) {
+ UserHandleCompat user = entry.getKey();
+
+ final ArrayList<String> packagesRemoved = new ArrayList<>();
+ final ArrayList<String> packagesUnavailable = new ArrayList<>();
+
+ for (String pkg : new HashSet<>(entry.getValue())) {
+ if (!launcherApps.isPackageEnabledForProfile(pkg, user)) {
+ if (PackageManagerHelper.isAppOnSdcard(manager, pkg)) {
+ packagesUnavailable.add(pkg);
+ } else {
+ packagesRemoved.add(pkg);
+ }
+ }
+ }
+ if (!packagesRemoved.isEmpty()) {
+ mModel.onPackagesRemoved(user,
+ packagesRemoved.toArray(new String[packagesRemoved.size()]));
+ }
+ if (!packagesUnavailable.isEmpty()) {
+ mModel.onPackagesUnavailable(
+ packagesUnavailable.toArray(new String[packagesUnavailable.size()]),
+ user, false);
+ }
+ }
+
+ // Unregister the broadcast receiver, just in case
+ mContext.unregisterReceiver(this);
+ }
+}
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
index 2702d4e8e..1aa1b9e9e 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
@@ -62,6 +62,7 @@ import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.graphics.TriangleShape;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
diff --git a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
index 2adb82e2d..fc474f527 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
@@ -23,7 +23,7 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.View;
-import com.android.launcher3.HolographicOutlineHelper;
+import com.android.launcher3.graphics.HolographicOutlineHelper;
import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
import com.android.launcher3.graphics.DragPreviewProvider;
@@ -44,7 +44,7 @@ public class ShortcutDragPreviewProvider extends DragPreviewProvider {
public Bitmap createDragOutline(Canvas canvas) {
Bitmap b = drawScaledPreview(canvas, Bitmap.Config.ALPHA_8);
- HolographicOutlineHelper.obtain(mView.getContext())
+ HolographicOutlineHelper.getInstance(mView.getContext())
.applyExpensiveOutlineWithBlur(b, canvas);
canvas.setBitmap(null);
return b;
diff --git a/src/com/android/launcher3/util/CursorIconInfo.java b/src/com/android/launcher3/util/CursorIconInfo.java
index 4fefa986e..6603ee765 100644
--- a/src/com/android/launcher3/util/CursorIconInfo.java
+++ b/src/com/android/launcher3/util/CursorIconInfo.java
@@ -25,6 +25,7 @@ import android.text.TextUtils;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.Utilities;
+import com.android.launcher3.graphics.LauncherIcons;
/**
* Utility class to load icon from a cursor.
@@ -59,7 +60,7 @@ public class CursorIconInfo {
info.iconResource = new ShortcutIconResource();
info.iconResource.packageName = packageName;
info.iconResource.resourceName = resourceName;
- icon = Utilities.createIconBitmap(packageName, resourceName, mContext);
+ icon = LauncherIcons.createIconBitmap(packageName, resourceName, mContext);
}
if (icon == null) {
// Failed to load from resource, try loading from DB.
@@ -72,7 +73,7 @@ public class CursorIconInfo {
* Loads the fixed bitmap from the icon if available.
*/
public Bitmap loadIcon(Cursor c) {
- return Utilities.createIconBitmap(c, iconIndex, mContext);
+ return LauncherIcons.createIconBitmap(c, iconIndex, mContext);
}
/**
diff --git a/src/com/android/launcher3/util/ItemInfoMatcher.java b/src/com/android/launcher3/util/ItemInfoMatcher.java
index 46e9184b4..8f985c344 100644
--- a/src/com/android/launcher3/util/ItemInfoMatcher.java
+++ b/src/com/android/launcher3/util/ItemInfoMatcher.java
@@ -18,7 +18,9 @@ package com.android.launcher3.util;
import android.content.ComponentName;
+import com.android.launcher3.FolderInfo;
import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.compat.UserHandleCompat;
@@ -33,6 +35,46 @@ public abstract class ItemInfoMatcher {
public abstract boolean matches(ItemInfo info, ComponentName cn);
+ /**
+ * Filters {@param infos} to those satisfying the {@link #matches(ItemInfo, ComponentName)}.
+ */
+ public final HashSet<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos) {
+ HashSet<ItemInfo> filtered = new HashSet<>();
+ for (ItemInfo i : infos) {
+ if (i instanceof ShortcutInfo) {
+ ShortcutInfo info = (ShortcutInfo) i;
+ ComponentName cn = info.getTargetComponent();
+ if (cn != null && matches(info, cn)) {
+ filtered.add(info);
+ }
+ } else if (i instanceof FolderInfo) {
+ FolderInfo info = (FolderInfo) i;
+ for (ShortcutInfo s : info.contents) {
+ ComponentName cn = s.getTargetComponent();
+ if (cn != null && matches(s, cn)) {
+ filtered.add(s);
+ }
+ }
+ } else if (i instanceof LauncherAppWidgetInfo) {
+ LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;
+ ComponentName cn = info.providerName;
+ if (cn != null && matches(info, cn)) {
+ filtered.add(info);
+ }
+ }
+ }
+ return filtered;
+ }
+
+ public static ItemInfoMatcher ofUser(final UserHandleCompat user) {
+ return new ItemInfoMatcher() {
+ @Override
+ public boolean matches(ItemInfo info, ComponentName cn) {
+ return info.user.equals(user);
+ }
+ };
+ }
+
public static ItemInfoMatcher ofComponents(
final HashSet<ComponentName> components, final UserHandleCompat user) {
return new ItemInfoMatcher() {
diff --git a/src/com/android/launcher3/util/StringFilter.java b/src/com/android/launcher3/util/StringFilter.java
deleted file mode 100644
index f539ad11e..000000000
--- a/src/com/android/launcher3/util/StringFilter.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.android.launcher3.util;
-
-import java.util.Set;
-
-/**
- * Abstract class to filter a set of strings.
- */
-public abstract class StringFilter {
-
- private StringFilter() { }
-
- public abstract boolean matches(String str);
-
- public static StringFilter matchesAll() {
- return new StringFilter() {
- @Override
- public boolean matches(String str) {
- return true;
- }
- };
- }
-
- public static StringFilter of(final Set<String> validEntries) {
- return new StringFilter() {
- @Override
- public boolean matches(String str) {
- return validEntries.contains(str);
- }
- };
- }
-}
diff --git a/src/com/android/launcher3/util/TouchController.java b/src/com/android/launcher3/util/TouchController.java
index d1409c8b9..3cca21500 100644
--- a/src/com/android/launcher3/util/TouchController.java
+++ b/src/com/android/launcher3/util/TouchController.java
@@ -1,8 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.launcher3.util;
import android.view.MotionEvent;
public interface TouchController {
- boolean onTouchEvent(MotionEvent ev);
- boolean onInterceptTouchEvent(MotionEvent ev);
+
+ /**
+ * Called when the draglayer receives touch event.
+ */
+ boolean onControllerTouchEvent(MotionEvent ev);
+
+ /**
+ * Called when the draglayer receives a intercept touch event.
+ */
+ boolean onControllerInterceptTouchEvent(MotionEvent ev);
}
diff --git a/src/com/android/launcher3/widget/PendingItemPreviewProvider.java b/src/com/android/launcher3/widget/PendingItemPreviewProvider.java
index eaa0bb3d5..7c06701e8 100644
--- a/src/com/android/launcher3/widget/PendingItemPreviewProvider.java
+++ b/src/com/android/launcher3/widget/PendingItemPreviewProvider.java
@@ -21,7 +21,7 @@ import android.graphics.Canvas;
import android.graphics.Rect;
import android.view.View;
-import com.android.launcher3.HolographicOutlineHelper;
+import com.android.launcher3.graphics.HolographicOutlineHelper;
import com.android.launcher3.Launcher;
import com.android.launcher3.PendingAddItemInfo;
import com.android.launcher3.Workspace;
@@ -67,7 +67,7 @@ public class PendingItemPreviewProvider extends DragPreviewProvider {
// Don't clip alpha values for the drag outline if we're using the default widget preview
boolean clipAlpha = !(mAddInfo instanceof PendingAddWidgetInfo &&
(((PendingAddWidgetInfo) mAddInfo).previewImage == 0));
- HolographicOutlineHelper.obtain(mView.getContext())
+ HolographicOutlineHelper.getInstance(mView.getContext())
.applyExpensiveOutlineWithBlur(b, canvas, clipAlpha);
canvas.setBitmap(null);
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 89c44c859..8b7225821 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -21,7 +21,6 @@ import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView.State;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
@@ -45,11 +44,11 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.WidgetPreviewLoader;
import com.android.launcher3.Workspace;
import com.android.launcher3.dragndrop.DragController;
+import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.Thunk;
-import com.android.launcher3.util.TransformingTouchDelegate;
/**
* The widgets list view container.
@@ -64,12 +63,9 @@ public class WidgetsContainerView extends BaseContainerView
private DragController mDragController;
private IconCache mIconCache;
- private final Rect mTmpBgPaddingRect = new Rect();
-
/* Recycler view related member variables */
private WidgetsRecyclerView mRecyclerView;
private WidgetsListAdapter mAdapter;
- private TransformingTouchDelegate mRecyclerViewTouchDelegate;
/* Touch handling related member variables. */
private Toast mWidgetInstructionToast;
@@ -97,14 +93,8 @@ public class WidgetsContainerView extends BaseContainerView
}
@Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- getRevealView().getBackground().getPadding(mTmpBgPaddingRect);
- mRecyclerViewTouchDelegate.setBounds(
- mRecyclerView.getLeft() - mTmpBgPaddingRect.left,
- mRecyclerView.getTop() - mTmpBgPaddingRect.top,
- mRecyclerView.getRight() + mTmpBgPaddingRect.right,
- mRecyclerView.getBottom() + mTmpBgPaddingRect.bottom);
+ public View getTouchDelegateTargetView() {
+ return mRecyclerView;
}
@Override
@@ -113,13 +103,6 @@ public class WidgetsContainerView extends BaseContainerView
mRecyclerView = (WidgetsRecyclerView) getContentView().findViewById(R.id.widgets_list_view);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
- mRecyclerViewTouchDelegate = new TransformingTouchDelegate(mRecyclerView);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- ((View) mRecyclerView.getParent()).setTouchDelegate(mRecyclerViewTouchDelegate);
}
//
@@ -241,7 +224,7 @@ public class WidgetsContainerView extends BaseContainerView
} else {
PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) v.getTag();
Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.activityInfo);
- preview = Utilities.createIconBitmap(icon, mLauncher);
+ preview = LauncherIcons.createIconBitmap(icon, mLauncher);
createItemInfo.spanX = createItemInfo.spanY = 1;
scale = ((float) mLauncher.getDeviceProfile().iconSizePx) / preview.getWidth();
}
diff --git a/tests/src/com/android/launcher3/BindWidgetTest.java b/tests/src/com/android/launcher3/BindWidgetTest.java
index 5c5069fea..c133bf6c8 100644
--- a/tests/src/com/android/launcher3/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/BindWidgetTest.java
@@ -232,7 +232,6 @@ public class BindWidgetTest extends LauncherInstrumentationTestCase {
runTestOnUiThread(new Runnable() {
@Override
public void run() {
- LauncherClings.markFirstRunClingDismissed(mTargetContext);
ManagedProfileHeuristic.markExistingUsersForNoFolderCreation(mTargetContext);
LauncherAppState.getInstance().getModel().resetLoadedState(true, true);
}
diff --git a/tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java b/tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java
index e858d17f3..e94fca6ff 100644
--- a/tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java
+++ b/tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java
@@ -23,7 +23,6 @@ import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.LauncherClings;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -189,7 +188,6 @@ public class LauncherInstrumentationTestCase extends InstrumentationTestCase {
LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
LauncherSettings.Settings.call(mTargetContext.getContentResolver(),
LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG);
- LauncherClings.markFirstRunClingDismissed(mTargetContext);
ManagedProfileHeuristic.markExistingUsersForNoFolderCreation(mTargetContext);
runTestOnUiThread(new Runnable() {