summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/widget
diff options
context:
space:
mode:
authorSunny Goyal <sunnygoyal@google.com>2017-10-10 15:21:15 -0700
committerSunny Goyal <sunnygoyal@google.com>2017-10-13 18:47:54 -0700
commitf1fbc3fbe78997f141e2770221fe5ab1b1e68014 (patch)
tree466510cf18141f0a7a841c349096f6dfc23d5e8f /src/com/android/launcher3/widget
parent10a1bd0e652ec7ea3e3ee861fc0d72261a33a3fd (diff)
downloadandroid_packages_apps_Trebuchet-f1fbc3fbe78997f141e2770221fe5ab1b1e68014.tar.gz
android_packages_apps_Trebuchet-f1fbc3fbe78997f141e2770221fe5ab1b1e68014.tar.bz2
android_packages_apps_Trebuchet-f1fbc3fbe78997f141e2770221fe5ab1b1e68014.zip
Converting widget panel into a floating view
> The widget panel is only inflated when needed > Using the swipe up/down interaction for widgets tray > Removing additional view wrappers from all-apps > Widget tray is preserved across activity recreation > Launcher no longer has WIDGET state, the actual code around the states will be removed in a follow-up cl Bug: 67678570 Bug: 67585158 Change-Id: Ia29a7c33ec81e6c53cc24e2906b7022b6f41755b
Diffstat (limited to 'src/com/android/launcher3/widget')
-rw-r--r--src/com/android/launcher3/widget/BaseWidgetSheet.java288
-rw-r--r--src/com/android/launcher3/widget/WidgetCell.java33
-rw-r--r--src/com/android/launcher3/widget/WidgetsBottomSheet.java199
-rw-r--r--src/com/android/launcher3/widget/WidgetsContainerView.java243
-rw-r--r--src/com/android/launcher3/widget/WidgetsDiffReporter.java37
-rw-r--r--src/com/android/launcher3/widget/WidgetsFullSheet.java222
-rw-r--r--src/com/android/launcher3/widget/WidgetsListAdapter.java87
-rw-r--r--src/com/android/launcher3/widget/WidgetsRecyclerView.java16
8 files changed, 615 insertions, 510 deletions
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
new file mode 100644
index 000000000..ee5dd66bd
--- /dev/null
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.widget;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.content.Context;
+import android.graphics.Point;
+import android.util.AttributeSet;
+import android.util.Property;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.Toast;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.DeleteDropTarget;
+import com.android.launcher3.DragSource;
+import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.folder.Folder;
+import com.android.launcher3.graphics.GradientView;
+import com.android.launcher3.touch.SwipeDetector;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+import com.android.launcher3.util.SystemUiController;
+import com.android.launcher3.util.Themes;
+
+/**
+ * Base class for various widgets popup
+ */
+abstract class BaseWidgetSheet extends AbstractFloatingView
+ implements OnClickListener, OnLongClickListener, DragSource, SwipeDetector.Listener {
+
+
+ protected static Property<BaseWidgetSheet, Float> TRANSLATION_SHIFT =
+ new Property<BaseWidgetSheet, Float>(Float.class, "translationShift") {
+
+ @Override
+ public Float get(BaseWidgetSheet view) {
+ return view.mTranslationShift;
+ }
+
+ @Override
+ public void set(BaseWidgetSheet view, Float value) {
+ view.setTranslationShift(value);
+ }
+ };
+ protected static final float TRANSLATION_SHIFT_CLOSED = 1f;
+ protected static final float TRANSLATION_SHIFT_OPENED = 0f;
+
+ /* Touch handling related member variables. */
+ private Toast mWidgetInstructionToast;
+
+ protected final Launcher mLauncher;
+ protected final SwipeDetector.ScrollInterpolator mScrollInterpolator;
+ protected final SwipeDetector mSwipeDetector;
+ protected final ObjectAnimator mOpenCloseAnimator;
+
+ protected View mContent;
+ protected GradientView mGradientView;
+
+ // range [0, 1], 0=> completely open, 1=> completely closed
+ protected float mTranslationShift = TRANSLATION_SHIFT_CLOSED;
+
+ protected boolean mNoIntercept;
+
+ public BaseWidgetSheet(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mLauncher = Launcher.getLauncher(context);
+
+ mScrollInterpolator = new SwipeDetector.ScrollInterpolator();
+ mSwipeDetector = new SwipeDetector(context, this, SwipeDetector.VERTICAL);
+
+ mOpenCloseAnimator = LauncherAnimUtils.ofPropertyValuesHolder(this);
+ mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mSwipeDetector.finishedScrolling();
+ }
+ });
+ }
+
+ @Override
+ public final void onClick(View v) {
+ // Let the user know that they have to long press to add a widget
+ if (mWidgetInstructionToast != null) {
+ mWidgetInstructionToast.cancel();
+ }
+
+ CharSequence msg = Utilities.wrapForTts(
+ getContext().getText(R.string.long_press_widget_to_add),
+ getContext().getString(R.string.long_accessible_way_to_add));
+ mWidgetInstructionToast = Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT);
+ mWidgetInstructionToast.show();
+ }
+
+ @Override
+ public final boolean onLongClick(View v) {
+ if (!mLauncher.isDraggingEnabled()) return false;
+
+ if (v instanceof WidgetCell) {
+ return beginDraggingWidget((WidgetCell) v);
+ }
+ return true;
+ }
+
+ protected void setTranslationShift(float translationShift) {
+ mTranslationShift = translationShift;
+ mGradientView.setAlpha(1 - mTranslationShift);
+ mContent.setTranslationY(mTranslationShift * mContent.getHeight());
+ }
+
+ private boolean beginDraggingWidget(WidgetCell v) {
+ // Get the widget preview as the drag representation
+ WidgetImageView image = v.getWidgetView();
+
+ // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
+ // we abort the drag.
+ if (image.getBitmap() == null) {
+ return false;
+ }
+
+ int[] loc = new int[2];
+ mLauncher.getDragLayer().getLocationInDragLayer(image, loc);
+
+ new PendingItemDragHelper(v).startDrag(
+ image.getBitmapBounds(), image.getBitmap().getWidth(), image.getWidth(),
+ new Point(loc[0], loc[1]), this, new DragOptions());
+ close(true);
+ return true;
+ }
+
+ //
+ // Drag related handling methods that implement {@link DragSource} interface.
+ //
+
+ @Override
+ public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
+ boolean success) {
+ if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
+ !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
+ // Exit spring loaded mode if we have not successfully dropped or have not handled the
+ // drop in Workspace
+ mLauncher.exitSpringLoadedDragModeDelayed(true,
+ Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
+ }
+ mLauncher.unlockScreenOrientation(false);
+
+ if (!success) {
+ d.deferDragViewCleanupPostAnimation = false;
+ }
+ }
+
+
+ @Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_UP && !mNoIntercept) {
+ // If we got ACTION_UP without ever returning true on intercept,
+ // the user never started dragging the bottom sheet.
+ if (!mLauncher.getDragLayer().isEventOverView(mContent, ev)) {
+ close(true);
+ return false;
+ }
+ }
+
+ if (mNoIntercept) {
+ return false;
+ }
+
+ int directionsToDetectScroll = mSwipeDetector.isIdleState() ?
+ SwipeDetector.DIRECTION_NEGATIVE : 0;
+ mSwipeDetector.setDetectableScrollConditions(
+ directionsToDetectScroll, false);
+ mSwipeDetector.onTouchEvent(ev);
+ return mSwipeDetector.isDraggingOrSettling();
+ }
+
+ @Override
+ public boolean onControllerTouchEvent(MotionEvent ev) {
+ return mSwipeDetector.onTouchEvent(ev);
+ }
+
+ /* SwipeDetector.Listener */
+
+ @Override
+ public void onDragStart(boolean start) { }
+
+ @Override
+ public boolean onDrag(float displacement, float velocity) {
+ float range = mContent.getHeight();
+ displacement = Utilities.boundToRange(displacement, 0, range);
+ setTranslationShift(displacement / range);
+ return true;
+ }
+
+ @Override
+ public void onDragEnd(float velocity, boolean fling) {
+ if ((fling && velocity > 0) || mTranslationShift > 0.5f) {
+ mScrollInterpolator.setVelocityAtZero(velocity);
+ mOpenCloseAnimator.setDuration(SwipeDetector.calculateDuration(
+ velocity, TRANSLATION_SHIFT_CLOSED - mTranslationShift));
+ close(true);
+ } else {
+ mOpenCloseAnimator.setValues(PropertyValuesHolder.ofFloat(
+ TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
+ mOpenCloseAnimator.setDuration(
+ SwipeDetector.calculateDuration(velocity, mTranslationShift))
+ .setInterpolator(new DecelerateInterpolator());
+ mOpenCloseAnimator.start();
+ }
+ }
+
+ protected void handleClose(boolean animate, long defaultDuration) {
+ if (!mIsOpen || mOpenCloseAnimator.isRunning()) {
+ return;
+ }
+ if (animate) {
+ mOpenCloseAnimator.setValues(
+ PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_CLOSED));
+ mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ onCloseComplete();
+ }
+ });
+ if (mSwipeDetector.isIdleState()) {
+ mOpenCloseAnimator
+ .setDuration(defaultDuration)
+ .setInterpolator(new AccelerateInterpolator());
+ } else {
+ mOpenCloseAnimator.setInterpolator(mScrollInterpolator);
+ }
+ mOpenCloseAnimator.start();
+ } else {
+ setTranslationShift(TRANSLATION_SHIFT_CLOSED);
+ onCloseComplete();
+ }
+ }
+
+ protected void onCloseComplete() {
+ mIsOpen = false;
+ mLauncher.getDragLayer().removeView(this);
+ mLauncher.getSystemUiController().updateUiState(
+ SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0);
+ }
+
+ protected void setupNavBarColor() {
+ boolean isSheetDark = Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark);
+ mLauncher.getSystemUiController().updateUiState(
+ SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET,
+ isSheetDark ? SystemUiController.FLAG_DARK_NAV : SystemUiController.FLAG_LIGHT_NAV);
+ }
+
+ @Override
+ public void fillInLogContainerData(View v, ItemInfo info, Target target, Target targetParent) {
+ targetParent.containerType = ContainerType.WIDGETS;
+ }
+
+ @Override
+ public final void logActionCommand(int command) {
+ // TODO: be more specific
+ mLauncher.getUserEventDispatcher().logActionCommand(command, ContainerType.WIDGETS);
+ }
+}
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 40dbd523c..2ba55ab97 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -75,6 +75,9 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
protected CancellationSignal mActiveRequest;
private boolean mAnimatePreview = true;
+ private boolean mApplyBitmapDeferred = false;
+ private Bitmap mDeferredBitmap;
+
protected final BaseActivity mActivity;
public WidgetCell(Context context) {
@@ -150,15 +153,31 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
return mWidgetImage;
}
+ /**
+ * Sets if applying bitmap preview should be deferred. The UI will still load the bitmap, but
+ * will not cause invalidate, so that when deferring is disabled later, all the bitmaps are
+ * ready.
+ * This prevents invalidates while the animation is running.
+ */
+ public void setApplyBitmapDeferred(boolean isDeferred) {
+ if (mApplyBitmapDeferred != isDeferred) {
+ mApplyBitmapDeferred = isDeferred;
+ if (!mApplyBitmapDeferred && mDeferredBitmap != null) {
+ applyPreview(mDeferredBitmap);
+ mDeferredBitmap = null;
+ }
+ }
+ }
+
public void setAnimatePreview(boolean shouldAnimate) {
mAnimatePreview = shouldAnimate;
}
public void applyPreview(Bitmap bitmap) {
- applyPreview(bitmap, true);
- }
-
- public void applyPreview(Bitmap bitmap, boolean animate) {
+ if (mApplyBitmapDeferred) {
+ mDeferredBitmap = bitmap;
+ return;
+ }
if (bitmap != null) {
mWidgetImage.setBitmap(bitmap,
DrawableFactory.get(getContext()).getBadgeForUser(mItem.user, getContext()));
@@ -173,15 +192,11 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
}
public void ensurePreview() {
- ensurePreview(true);
- }
-
- public void ensurePreview(boolean animate) {
if (mActiveRequest != null) {
return;
}
mActiveRequest = mWidgetPreviewLoader.getPreview(
- mItem, mPresetPreviewSize, mPresetPreviewSize, this, animate);
+ mItem, mPresetPreviewSize, mPresetPreviewSize, this);
}
@Override
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 7aa50a445..201bd1c9c 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -16,62 +16,38 @@
package com.android.launcher3.widget;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
-import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.TextView;
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.DropTarget;
import com.android.launcher3.Insettable;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.PropertyListBuilder;
-import com.android.launcher3.dragndrop.DragController;
-import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.graphics.GradientView;
import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.touch.SwipeDetector;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.util.SystemUiController;
-import com.android.launcher3.util.Themes;
import java.util.List;
/**
* Bottom sheet for the "Widgets" system shortcut in the long-press popup.
*/
-public class WidgetsBottomSheet extends AbstractFloatingView implements Insettable,
- SwipeDetector.Listener, View.OnClickListener, View.OnLongClickListener,
- DragController.DragListener {
+public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable {
- private int mTranslationYOpen;
- private int mTranslationYClosed;
- private float mTranslationYRange;
-
- private Launcher mLauncher;
+ private static final int DEFAULT_CLOSE_DURATION = 200;
private ItemInfo mOriginalItemInfo;
- private ObjectAnimator mOpenCloseAnimator;
private Interpolator mFastOutSlowInInterpolator;
- private SwipeDetector.ScrollInterpolator mScrollInterpolator;
private Rect mInsets;
- private SwipeDetector mSwipeDetector;
- private GradientView mGradientBackground;
public WidgetsBottomSheet(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -80,23 +56,20 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab
public WidgetsBottomSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setWillNotDraw(false);
- mLauncher = Launcher.getLauncher(context);
- mOpenCloseAnimator = LauncherAnimUtils.ofPropertyValuesHolder(this);
mFastOutSlowInInterpolator =
AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
- mScrollInterpolator = new SwipeDetector.ScrollInterpolator();
mInsets = new Rect();
- mSwipeDetector = new SwipeDetector(context, this, SwipeDetector.VERTICAL);
- mGradientBackground = (GradientView) mLauncher.getLayoutInflater().inflate(
+
+ mGradientView = (GradientView) mLauncher.getLayoutInflater().inflate(
R.layout.gradient_bg, mLauncher.getDragLayer(), false);
+ mGradientView.setProgress(1, false);
+ mContent = this;
}
@Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- mTranslationYOpen = 0;
- mTranslationYClosed = getMeasuredHeight();
- mTranslationYRange = mTranslationYClosed - mTranslationYOpen;
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ setTranslationShift(mTranslationShift);
}
public void populateAndShow(ItemInfo itemInfo) {
@@ -106,21 +79,21 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab
onWidgetsBound();
- mLauncher.getDragLayer().addView(mGradientBackground);
+ mLauncher.getDragLayer().addView(mGradientView);
mLauncher.getDragLayer().addView(this);
- measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- setTranslationY(mTranslationYClosed);
mIsOpen = false;
open(true);
}
@Override
protected void onWidgetsBound() {
- List<WidgetItem> widgets = mLauncher.getWidgetsForPackageUser(new PackageUserKey(
- mOriginalItemInfo.getTargetComponent().getPackageName(), mOriginalItemInfo.user));
+ List<WidgetItem> widgets = mLauncher.getPopupDataProvider().getWidgetsForPackageUser(
+ new PackageUserKey(
+ mOriginalItemInfo.getTargetComponent().getPackageName(),
+ mOriginalItemInfo.user));
- ViewGroup widgetRow = (ViewGroup) findViewById(R.id.widgets);
- ViewGroup widgetCells = (ViewGroup) widgetRow.findViewById(R.id.widgets_cell_list);
+ ViewGroup widgetRow = findViewById(R.id.widgets);
+ ViewGroup widgetCells = widgetRow.findViewById(R.id.widgets_cell_list);
widgetCells.removeAllViews();
@@ -166,72 +139,31 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab
return widget;
}
- @Override
- public void onClick(View view) {
- mLauncher.getWidgetsView().handleClick();
- }
-
- @Override
- public boolean onLongClick(View view) {
- mLauncher.getDragController().addDragListener(this);
- return mLauncher.getWidgetsView().handleLongClick(view);
- }
-
private void open(boolean animate) {
if (mIsOpen || mOpenCloseAnimator.isRunning()) {
return;
}
mIsOpen = true;
- boolean isSheetDark = Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark);
- mLauncher.getSystemUiController().updateUiState(
- SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET,
- isSheetDark ? SystemUiController.FLAG_DARK_NAV : SystemUiController.FLAG_LIGHT_NAV);
+ setupNavBarColor();
if (animate) {
- mOpenCloseAnimator.setValues(new PropertyListBuilder()
- .translationY(mTranslationYOpen).build());
- mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mSwipeDetector.finishedScrolling();
- }
- });
+ mOpenCloseAnimator.setValues(
+ PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
mOpenCloseAnimator.setInterpolator(mFastOutSlowInInterpolator);
mOpenCloseAnimator.start();
} else {
- setTranslationY(mTranslationYOpen);
+ setTranslationShift(TRANSLATION_SHIFT_OPENED);
}
}
@Override
protected void handleClose(boolean animate) {
- if (!mIsOpen || mOpenCloseAnimator.isRunning()) {
- return;
- }
- if (animate) {
- mOpenCloseAnimator.setValues(new PropertyListBuilder()
- .translationY(mTranslationYClosed).build());
- mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mSwipeDetector.finishedScrolling();
- onCloseComplete();
- }
- });
- mOpenCloseAnimator.setInterpolator(mSwipeDetector.isIdleState()
- ? mFastOutSlowInInterpolator : mScrollInterpolator);
- mOpenCloseAnimator.start();
- } else {
- setTranslationY(mTranslationYClosed);
- onCloseComplete();
- }
+ handleClose(animate, DEFAULT_CLOSE_DURATION);
}
- private void onCloseComplete() {
- mIsOpen = false;
- mLauncher.getDragLayer().removeView(mGradientBackground);
- mLauncher.getDragLayer().removeView(WidgetsBottomSheet.this);
- mLauncher.getSystemUiController().updateUiState(
- SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0);
+ @Override
+ protected void onCloseComplete() {
+ super.onCloseComplete();
+ mLauncher.getDragLayer().removeView(mGradientView);
}
@Override
@@ -249,83 +181,4 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab
setPadding(getPaddingLeft() + leftInset, getPaddingTop(),
getPaddingRight() + rightInset, getPaddingBottom() + bottomInset);
}
-
- /* SwipeDetector.Listener */
-
- @Override
- public void onDragStart(boolean start) {
- }
-
- @Override
- public boolean onDrag(float displacement, float velocity) {
- setTranslationY(Utilities.boundToRange(displacement, mTranslationYOpen,
- mTranslationYClosed));
- return true;
- }
-
- @Override
- public void setTranslationY(float translationY) {
- super.setTranslationY(translationY);
- if (mGradientBackground == null) return;
- float p = (mTranslationYClosed - translationY) / mTranslationYRange;
- boolean showScrim = p <= 0;
- mGradientBackground.setProgress(p, showScrim);
- }
-
- @Override
- public void onDragEnd(float velocity, boolean fling) {
- if ((fling && velocity > 0) || getTranslationY() > (mTranslationYRange) / 2) {
- mScrollInterpolator.setVelocityAtZero(velocity);
- mOpenCloseAnimator.setDuration(SwipeDetector.calculateDuration(velocity,
- (mTranslationYClosed - getTranslationY()) / mTranslationYRange));
- close(true);
- } else {
- mIsOpen = false;
- mOpenCloseAnimator.setDuration(SwipeDetector.calculateDuration(velocity,
- (getTranslationY() - mTranslationYOpen) / mTranslationYRange));
- open(true);
- }
- }
-
- @Override
- public void logActionCommand(int command) {
- // TODO: be more specific
- mLauncher.getUserEventDispatcher().logActionCommand(command, ContainerType.WIDGETS);
- }
-
- @Override
- public boolean onControllerTouchEvent(MotionEvent ev) {
- return mSwipeDetector.onTouchEvent(ev);
- }
-
- @Override
- public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_UP) {
- // If we got ACTION_UP without ever returning true on intercept,
- // the user never started dragging the bottom sheet.
- if (!mLauncher.getDragLayer().isEventOverView(this, ev)) {
- close(true);
- return false;
- }
- }
-
- int directionsToDetectScroll = mSwipeDetector.isIdleState() ?
- SwipeDetector.DIRECTION_NEGATIVE : 0;
- mSwipeDetector.setDetectableScrollConditions(
- directionsToDetectScroll, false);
- mSwipeDetector.onTouchEvent(ev);
- return mSwipeDetector.isDraggingOrSettling();
- }
-
- /* DragListener */
-
- @Override
- public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
- // A widget or custom shortcut was dragged.
- close(true);
- }
-
- @Override
- public void onDragEnd() {
- }
}
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
deleted file mode 100644
index 39dd0d498..000000000
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.widget;
-
-import android.content.Context;
-import android.content.pm.LauncherApps;
-import android.graphics.Point;
-import android.support.v7.widget.LinearLayoutManager;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Toast;
-
-import com.android.launcher3.BaseContainerView;
-import com.android.launcher3.DeleteDropTarget;
-import com.android.launcher3.DragSource;
-import com.android.launcher3.DropTarget.DragObject;
-import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.compat.AlphabeticIndexCompat;
-import com.android.launcher3.dragndrop.DragOptions;
-import com.android.launcher3.folder.Folder;
-import com.android.launcher3.model.PackageItemInfo;
-import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
-import com.android.launcher3.util.MultiHashMap;
-import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.util.Thunk;
-
-import java.util.List;
-
-/**
- * The widgets list view container.
- */
-public class WidgetsContainerView extends BaseContainerView
- implements View.OnLongClickListener, View.OnClickListener, DragSource {
- private static final String TAG = "WidgetsContainerView";
- private static final boolean LOGD = false;
-
- /* Global instances that are used inside this container. */
- @Thunk Launcher mLauncher;
-
- /* Recycler view related member variables */
- private WidgetsRecyclerView mRecyclerView;
- private WidgetsListAdapter mAdapter;
-
- /* Touch handling related member variables. */
- private Toast mWidgetInstructionToast;
-
- public WidgetsContainerView(Context context) {
- this(context, null);
- }
-
- public WidgetsContainerView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- mLauncher = Launcher.getLauncher(context);
- LauncherAppState apps = LauncherAppState.getInstance(context);
- mAdapter = new WidgetsListAdapter(context, LayoutInflater.from(context),
- apps.getWidgetCache(), new AlphabeticIndexCompat(context), this, this,
- new WidgetsDiffReporter(apps.getIconCache()));
- mAdapter.setNotifyListener();
- if (LOGD) {
- Log.d(TAG, "WidgetsContainerView constructor");
- }
- }
-
- @Override
- public View getTouchDelegateTargetView() {
- return mRecyclerView;
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mRecyclerView = (WidgetsRecyclerView) getContentView().findViewById(R.id.widgets_list_view);
- mRecyclerView.setAdapter(mAdapter);
- mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
- }
-
- //
- // Returns views used for launcher transitions.
- //
-
- public void scrollToTop() {
- mRecyclerView.scrollToPosition(0);
- }
-
- //
- // Touch related handling.
- //
-
- @Override
- public void onClick(View v) {
- // When we have exited widget tray or are in transition, disregard clicks
- if (!mLauncher.isWidgetsViewVisible()
- || mLauncher.getWorkspace().isSwitchingState()
- || !(v instanceof WidgetCell)) return;
-
- handleClick();
- }
-
- public void handleClick() {
- // Let the user know that they have to long press to add a widget
- if (mWidgetInstructionToast != null) {
- mWidgetInstructionToast.cancel();
- }
-
- CharSequence msg = Utilities.wrapForTts(
- getContext().getText(R.string.long_press_widget_to_add),
- getContext().getString(R.string.long_accessible_way_to_add));
- mWidgetInstructionToast = Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT);
- mWidgetInstructionToast.show();
- }
-
- @Override
- public boolean onLongClick(View v) {
- // When we have exited the widget tray, disregard long clicks
- if (!mLauncher.isWidgetsViewVisible()) return false;
- return handleLongClick(v);
- }
-
- public boolean handleLongClick(View v) {
- if (LOGD) {
- Log.d(TAG, String.format("onLongClick [v=%s]", v));
- }
- // When we are in transition, disregard long clicks
- if (mLauncher.getWorkspace().isSwitchingState()) return false;
- // Return if global dragging is not enabled
- if (!mLauncher.isDraggingEnabled()) return false;
-
- return beginDragging(v);
- }
-
- private boolean beginDragging(View v) {
- if (v instanceof WidgetCell) {
- if (!beginDraggingWidget((WidgetCell) v)) {
- return false;
- }
- } else {
- Log.e(TAG, "Unexpected dragging view: " + v);
- }
-
- // We don't enter spring-loaded mode if the drag has been cancelled
- if (mLauncher.getDragController().isDragging()) {
- // Go into spring loaded mode (must happen before we startDrag())
- mLauncher.enterSpringLoadedDragMode();
- }
-
- return true;
- }
-
- private boolean beginDraggingWidget(WidgetCell v) {
- // Get the widget preview as the drag representation
- WidgetImageView image = (WidgetImageView) v.findViewById(R.id.widget_preview);
-
- // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
- // we abort the drag.
- if (image.getBitmap() == null) {
- return false;
- }
-
- int[] loc = new int[2];
- mLauncher.getDragLayer().getLocationInDragLayer(image, loc);
-
- new PendingItemDragHelper(v).startDrag(
- image.getBitmapBounds(), image.getBitmap().getWidth(), image.getWidth(),
- new Point(loc[0], loc[1]), this, new DragOptions());
- return true;
- }
-
- //
- // Drag related handling methods that implement {@link DragSource} interface.
- //
-
- @Override
- public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
- boolean success) {
- if (LOGD) {
- Log.d(TAG, "onDropCompleted");
- }
- if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
- !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
- // Exit spring loaded mode if we have not successfully dropped or have not handled the
- // drop in Workspace
- mLauncher.exitSpringLoadedDragModeDelayed(true,
- Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
- }
- mLauncher.unlockScreenOrientation(false);
-
- if (!success) {
- d.deferDragViewCleanupPostAnimation = false;
- }
- }
-
- /**
- * Initialize the widget data model.
- */
- public void setWidgets(MultiHashMap<PackageItemInfo, WidgetItem> model) {
- mAdapter.setWidgets(model);
-
- View loader = getContentView().findViewById(R.id.loader);
- if (loader != null) {
- ((ViewGroup) getContentView()).removeView(loader);
- }
- }
-
- public boolean isEmpty() {
- return mAdapter.getItemCount() == 0;
- }
-
- public List<WidgetItem> getWidgetsForPackageUser(PackageUserKey packageUserKey) {
- return mAdapter.copyWidgetsForPackageUser(packageUserKey);
- }
-
- @Override
- public void fillInLogContainerData(View v, ItemInfo info, Target target, Target targetParent) {
- targetParent.containerType = ContainerType.WIDGETS;
- }
-} \ No newline at end of file
diff --git a/src/com/android/launcher3/widget/WidgetsDiffReporter.java b/src/com/android/launcher3/widget/WidgetsDiffReporter.java
index 52deec32b..d67f40365 100644
--- a/src/com/android/launcher3/widget/WidgetsDiffReporter.java
+++ b/src/com/android/launcher3/widget/WidgetsDiffReporter.java
@@ -16,6 +16,7 @@
package com.android.launcher3.widget;
+import android.support.v7.widget.RecyclerView;
import android.util.Log;
import com.android.launcher3.IconCache;
@@ -26,26 +27,18 @@ import java.util.ArrayList;
import java.util.Iterator;
/**
- * Do diff on widget's tray list items and call the {@link NotifyListener} methods accordingly.
+ * Do diff on widget's tray list items and call the {@link RecyclerView.Adapter}
+ * methods accordingly.
*/
public class WidgetsDiffReporter {
- private final boolean DEBUG = false;
- private final String TAG = "WidgetsDiffReporter";
- private final IconCache mIconCache;
- private NotifyListener mListener;
+ private static final boolean DEBUG = false;
+ private static final String TAG = "WidgetsDiffReporter";
- public interface NotifyListener {
- void notifyDataSetChanged();
- void notifyItemChanged(int index);
- void notifyItemInserted(int index);
- void notifyItemRemoved(int index);
- }
+ private final IconCache mIconCache;
+ private final RecyclerView.Adapter mListener;
- public WidgetsDiffReporter(IconCache iconCache) {
+ public WidgetsDiffReporter(IconCache iconCache, RecyclerView.Adapter listener) {
mIconCache = iconCache;
- }
-
- public void setListener(NotifyListener listener) {
mListener = listener;
}
@@ -55,9 +48,17 @@ public class WidgetsDiffReporter {
Log.d(TAG, "process oldEntries#=" + currentEntries.size()
+ " newEntries#=" + newEntries.size());
}
- if (currentEntries.size() == 0 && newEntries.size() > 0) {
- currentEntries.addAll(newEntries);
- mListener.notifyDataSetChanged();
+ // Early exit if either of the list is empty
+ if (currentEntries.isEmpty() || newEntries.isEmpty()) {
+ // Skip if both list are empty.
+ // On rotation, we open the widget tray with empty. Then try to fetch the list again
+ // when the animation completes (which still gives empty). And we get the final result
+ // when the bind actually completes.
+ if (currentEntries.size() != newEntries.size()) {
+ currentEntries.clear();
+ currentEntries.addAll(newEntries);
+ mListener.notifyDataSetChanged();
+ }
return;
}
ArrayList<WidgetListRowEntry> orgEntries =
diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java
new file mode 100644
index 000000000..72277a253
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.widget;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.PropertyValuesHolder;
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+
+import com.android.launcher3.Insettable;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
+import com.android.launcher3.R;
+
+/**
+ * Popup for showing the full list of available widgets
+ */
+public class WidgetsFullSheet extends BaseWidgetSheet
+ implements Insettable, ProviderChangedListener {
+
+ private static final long DEFAULT_OPEN_DURATION = 267;
+ private static final long FADE_IN_DURATION = 150;
+ private static final float VERTICAL_START_POSITION = 0.3f;
+
+ private static final Rect sTempRect = new Rect();
+
+ private final Rect mInsets = new Rect();
+
+ private final WidgetsListAdapter mAdapter;
+
+ private View mNavBarScrim;
+ private WidgetsRecyclerView mRecyclerView;
+
+ public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ LauncherAppState apps = LauncherAppState.getInstance(context);
+ mAdapter = new WidgetsListAdapter(context,
+ LayoutInflater.from(context), apps.getWidgetCache(), apps.getIconCache(),
+ this, this);
+ }
+
+ public WidgetsFullSheet(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mContent = findViewById(R.id.container);
+ mNavBarScrim = findViewById(R.id.nav_bar_bg);
+
+ mRecyclerView = findViewById(R.id.widgets_list_view);
+ mRecyclerView.setAdapter(mAdapter);
+ mAdapter.setApplyBitmapDeferred(true, mRecyclerView);
+
+ mGradientView = findViewById(R.id.gradient_bg);
+ mGradientView.setProgress(1, false);
+
+ onWidgetsBound();
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mLauncher.getAppWidgetHost().addProviderChangeListener(this);
+ notifyWidgetProvidersChanged();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mLauncher.getAppWidgetHost().removeProviderChangeListener(this);
+ }
+
+ @Override
+ public void setInsets(Rect insets) {
+ mInsets.set(insets);
+
+ mNavBarScrim.getLayoutParams().height = insets.bottom;
+ mRecyclerView.setPadding(
+ mRecyclerView.getPaddingLeft(), mRecyclerView.getPaddingTop(),
+ mRecyclerView.getPaddingRight(), insets.bottom);
+ if (insets.bottom > 0) {
+ setupNavBarColor();
+ }
+ requestLayout();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int widthUsed;
+ if (mInsets.bottom > 0) {
+ // If we have bottom insets, we do not show the scrim as it would overlap
+ // with the navbar scrim
+ mGradientView.setVisibility(View.INVISIBLE);
+ widthUsed = 0;
+ } else {
+ mLauncher.getDeviceProfile().getWorkspacePadding(sTempRect);
+ widthUsed = Math.max(sTempRect.left + sTempRect.right,
+ 2 * (mInsets.left + mInsets.right));
+ }
+
+ int heightUsed = mInsets.top + mLauncher.getDeviceProfile().edgeMarginPx;
+ measureChildWithMargins(mContent, widthMeasureSpec,
+ widthUsed, heightMeasureSpec, heightUsed);
+ measureChild(mGradientView, widthMeasureSpec, heightMeasureSpec);
+ setMeasuredDimension(mGradientView.getMeasuredWidth(), mGradientView.getMeasuredHeight());
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ int width = r - l;
+ int height = b - t;
+ mGradientView.layout(0, 0, width, height);
+
+ // Content is laid out as center bottom aligned
+ int contentWidth = mContent.getMeasuredWidth();
+ int contentLeft = (width - contentWidth) / 2;
+ mContent.layout(contentLeft, height - mContent.getMeasuredHeight(),
+ contentLeft + contentWidth, height);
+
+ setTranslationShift(mTranslationShift);
+ }
+
+ @Override
+ public void notifyWidgetProvidersChanged() {
+ mLauncher.refreshAndBindWidgetsForPackageUser(null);
+ }
+
+ @Override
+ protected void onWidgetsBound() {
+ mAdapter.setWidgets(mLauncher.getPopupDataProvider().getAllWidgets());
+ }
+
+ private void open(boolean animate) {
+ if (mIsOpen) {
+ return;
+ }
+ mIsOpen = true;
+ if (animate) {
+ if (mLauncher.getDragLayer().getInsets().bottom > 0) {
+ mContent.setAlpha(0);
+ setTranslationShift(VERTICAL_START_POSITION);
+ }
+ mOpenCloseAnimator.setValues(
+ PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
+ mOpenCloseAnimator
+ .setDuration(DEFAULT_OPEN_DURATION)
+ .setInterpolator(AnimationUtils.loadInterpolator(
+ getContext(), android.R.interpolator.linear_out_slow_in));
+ mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mRecyclerView.setLayoutFrozen(false);
+ mAdapter.setApplyBitmapDeferred(false, mRecyclerView);
+ mOpenCloseAnimator.removeListener(this);
+ }
+ });
+ post(new Runnable() {
+ @Override
+ public void run() {
+ mRecyclerView.setLayoutFrozen(true);
+ mOpenCloseAnimator.start();
+ mContent.animate().alpha(1).setDuration(FADE_IN_DURATION);
+ }
+ });
+ } else {
+ setTranslationShift(TRANSLATION_SHIFT_OPENED);
+ mAdapter.setApplyBitmapDeferred(false, mRecyclerView);
+ }
+ }
+
+ @Override
+ protected void handleClose(boolean animate) {
+ handleClose(animate, DEFAULT_OPEN_DURATION);
+ }
+
+ @Override
+ protected boolean isOfType(int type) {
+ return (type & TYPE_WIDGETS_FULL_SHEET) != 0;
+ }
+
+ @Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ // Disable swipe down when recycler view is scrolling
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ mNoIntercept = false;
+ if (mLauncher.getDragLayer().isEventOverView(mContent, ev)) {
+ mNoIntercept = !mRecyclerView.shouldContainerScroll(ev, mLauncher.getDragLayer());
+ }
+ }
+ return super.onControllerInterceptTouchEvent(ev);
+ }
+
+ public static WidgetsFullSheet show(Launcher launcher, boolean animate) {
+ WidgetsFullSheet sheet = (WidgetsFullSheet) launcher.getLayoutInflater()
+ .inflate(R.layout.widgets_full_sheet, launcher.getDragLayer(), false);
+ launcher.getDragLayer().addView(sheet);
+ sheet.open(animate);
+ return sheet;
+ }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java
index 6b1800c67..0147ea427 100644
--- a/src/com/android/launcher3/widget/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java
@@ -25,13 +25,11 @@ import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
+import com.android.launcher3.IconCache;
import com.android.launcher3.R;
import com.android.launcher3.WidgetPreviewLoader;
-import com.android.launcher3.compat.AlphabeticIndexCompat;
-import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.util.LabelComparator;
-import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageUserKey;
import java.util.ArrayList;
@@ -39,7 +37,6 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
/**
* List view adapter for the widget tray.
@@ -56,7 +53,6 @@ public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> {
private final WidgetPreviewLoader mWidgetPreviewLoader;
private final LayoutInflater mLayoutInflater;
- private final AlphabeticIndexCompat mIndexer;
private final OnClickListener mIconClickListener;
private final OnLongClickListener mIconLongClickListener;
@@ -64,56 +60,43 @@ public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> {
private ArrayList<WidgetListRowEntry> mEntries = new ArrayList<>();
private final WidgetsDiffReporter mDiffReporter;
+ private boolean mApplyBitmapDeferred;
+
public WidgetsListAdapter(Context context, LayoutInflater layoutInflater,
- WidgetPreviewLoader widgetPreviewLoader, AlphabeticIndexCompat indexCompat,
- OnClickListener iconClickListener, OnLongClickListener iconLongClickListener,
- WidgetsDiffReporter diffReporter) {
+ WidgetPreviewLoader widgetPreviewLoader, IconCache iconCache,
+ OnClickListener iconClickListener, OnLongClickListener iconLongClickListener) {
mLayoutInflater = layoutInflater;
mWidgetPreviewLoader = widgetPreviewLoader;
- mIndexer = indexCompat;
mIconClickListener = iconClickListener;
mIconLongClickListener = iconLongClickListener;
mIndent = context.getResources().getDimensionPixelSize(R.dimen.widget_section_indent);
- mDiffReporter = diffReporter;
+ mDiffReporter = new WidgetsDiffReporter(iconCache, this);
}
- public void setNotifyListener() {
- mDiffReporter.setListener(new WidgetsDiffReporter.NotifyListener() {
- @Override
- public void notifyDataSetChanged() {
- WidgetsListAdapter.this.notifyDataSetChanged();
- }
-
- @Override
- public void notifyItemChanged(int index) {
- WidgetsListAdapter.this.notifyItemChanged(index);
- }
-
- @Override
- public void notifyItemInserted(int index) {
- WidgetsListAdapter.this.notifyItemInserted(index);
- }
-
- @Override
- public void notifyItemRemoved(int index) {
- WidgetsListAdapter.this.notifyItemRemoved(index);
+ /**
+ * Defers applying bitmap on all the {@link WidgetCell} in the {@param rv}
+ *
+ * @see WidgetCell#setApplyBitmapDeferred(boolean)
+ */
+ public void setApplyBitmapDeferred(boolean isDeferred, RecyclerView rv) {
+ mApplyBitmapDeferred = isDeferred;
+
+ for (int i = rv.getChildCount() - 1; i >= 0; i--) {
+ WidgetsRowViewHolder holder = (WidgetsRowViewHolder)
+ rv.getChildViewHolder(rv.getChildAt(i));
+ for (int j = holder.cellContainer.getChildCount() - 1; j >= 0; j--) {
+ View v = holder.cellContainer.getChildAt(j);
+ if (v instanceof WidgetCell) {
+ ((WidgetCell) v).setApplyBitmapDeferred(mApplyBitmapDeferred);
+ }
}
- });
+ }
}
/**
* Update the widget list.
*/
- public void setWidgets(MultiHashMap<PackageItemInfo, WidgetItem> widgets) {
- ArrayList<WidgetListRowEntry> tempEntries = new ArrayList<>();
-
- WidgetItemComparator widgetComparator = new WidgetItemComparator();
- for (Map.Entry<PackageItemInfo, ArrayList<WidgetItem>> entry : widgets.entrySet()) {
- WidgetListRowEntry row = new WidgetListRowEntry(entry.getKey(), entry.getValue());
- row.titleSectionName = mIndexer.computeSectionName(row.pkgItem.title);
- Collections.sort(row.widgets, widgetComparator);
- tempEntries.add(row);
- }
+ public void setWidgets(ArrayList<WidgetListRowEntry> tempEntries) {
WidgetListRowEntryComparator rowComparator = new WidgetListRowEntryComparator();
Collections.sort(tempEntries, rowComparator);
mDiffReporter.process(mEntries, tempEntries, rowComparator);
@@ -128,26 +111,6 @@ public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> {
return mEntries.get(pos).titleSectionName;
}
- /**
- * Copies and returns the widgets associated with the package and user of the ComponentKey.
- */
- public List<WidgetItem> copyWidgetsForPackageUser(PackageUserKey packageUserKey) {
- for (WidgetListRowEntry entry : mEntries) {
- if (entry.pkgItem.packageName.equals(packageUserKey.mPackageName)) {
- ArrayList<WidgetItem> widgets = new ArrayList<>(entry.widgets);
- // Remove widgets not associated with the correct user.
- Iterator<WidgetItem> iterator = widgets.iterator();
- while (iterator.hasNext()) {
- if (!iterator.next().user.equals(packageUserKey.mUser)) {
- iterator.remove();
- }
- }
- return widgets.isEmpty() ? null : widgets;
- }
- }
- return null;
- }
-
@Override
public void onBindViewHolder(WidgetsRowViewHolder holder, int pos) {
WidgetListRowEntry entry = mEntries.get(pos);
@@ -194,6 +157,7 @@ public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> {
for (int i=0; i < infoList.size(); i++) {
WidgetCell widget = (WidgetCell) row.getChildAt(2*i);
widget.applyFromCellItem(infoList.get(i), mWidgetPreviewLoader);
+ widget.setApplyBitmapDeferred(mApplyBitmapDeferred);
widget.ensurePreview();
widget.setVisibility(View.VISIBLE);
@@ -253,5 +217,4 @@ public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> {
return mComparator.compare(a.pkgItem.title.toString(), b.pkgItem.title.toString());
}
}
-
}
diff --git a/src/com/android/launcher3/widget/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
index 9730a82aa..89c88a4e7 100644
--- a/src/com/android/launcher3/widget/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
@@ -17,12 +17,12 @@
package com.android.launcher3.widget;
import android.content.Context;
-import android.graphics.Color;
import android.support.v7.widget.LinearLayoutManager;
import android.util.AttributeSet;
import android.view.View;
import com.android.launcher3.BaseRecyclerView;
+import com.android.launcher3.R;
/**
* The widgets recycler view.
@@ -32,6 +32,8 @@ public class WidgetsRecyclerView extends BaseRecyclerView {
private static final String TAG = "WidgetsRecyclerView";
private WidgetsListAdapter mAdapter;
+ private final int mScrollbarTop;
+
public WidgetsRecyclerView(Context context) {
this(context, null);
}
@@ -43,6 +45,7 @@ public class WidgetsRecyclerView extends BaseRecyclerView {
public WidgetsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
// API 21 and below only support 3 parameter ctor.
super(context, attrs, defStyleAttr);
+ mScrollbarTop = getResources().getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
}
public WidgetsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr,
@@ -130,13 +133,16 @@ public class WidgetsRecyclerView extends BaseRecyclerView {
@Override
protected int getAvailableScrollHeight() {
View child = getChildAt(0);
- int height = child.getMeasuredHeight() * mAdapter.getItemCount();
- int totalHeight = getPaddingTop() + height + getPaddingBottom();
- int availableScrollHeight = totalHeight - getScrollbarTrackHeight();
- return availableScrollHeight;
+ return child.getMeasuredHeight() * mAdapter.getItemCount() - getScrollbarTrackHeight()
+ - mScrollbarTop;
}
private boolean isModelNotReady() {
return mAdapter.getItemCount() == 0;
}
+
+ @Override
+ public int getScrollBarTop() {
+ return mScrollbarTop;
+ }
} \ No newline at end of file