Adding single/multi selection mode to AllAppsPagedView (action bar disabled).
Also adding check to prevent scrolling mode from continuing on touch down. Change-Id: I744f2c1f6bc659219145b52b15a7ea176853ec7c
This commit is contained in:
@@ -22,10 +22,15 @@ import java.util.Collections;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ActionMode;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.Checkable;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.launcher.R;
|
||||
@@ -35,7 +40,8 @@ import com.android.launcher.R;
|
||||
* with all of the user's applications.
|
||||
*/
|
||||
public class AllAppsPagedView extends PagedView
|
||||
implements AllAppsView, View.OnClickListener, View.OnLongClickListener, DragSource {
|
||||
implements AllAppsView, View.OnClickListener, View.OnLongClickListener, DragSource,
|
||||
DropTarget, ActionMode.Callback {
|
||||
|
||||
private static final String TAG = "AllAppsPagedView";
|
||||
private static final boolean DEBUG = false;
|
||||
@@ -127,6 +133,8 @@ public class AllAppsPagedView extends PagedView
|
||||
if (!isVisible()) {
|
||||
setVisibility(View.GONE);
|
||||
mZoom = 0.0f;
|
||||
|
||||
endChoiceMode();
|
||||
} else {
|
||||
mZoom = 1.0f;
|
||||
}
|
||||
@@ -138,7 +146,7 @@ public class AllAppsPagedView extends PagedView
|
||||
private int getChildIndexForGrandChild(View v) {
|
||||
final int childCount = getChildCount();
|
||||
for (int i = 0; i < childCount; ++i) {
|
||||
PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i);
|
||||
final PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i);
|
||||
if (layout.indexOfChild(v) > -1) {
|
||||
return i;
|
||||
}
|
||||
@@ -148,6 +156,22 @@ public class AllAppsPagedView extends PagedView
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// if we are already in a choice mode, then just change the selection
|
||||
if (v instanceof Checkable) {
|
||||
if (!isChoiceMode(CHOICE_MODE_NONE)) {
|
||||
if (isChoiceMode(CHOICE_MODE_SINGLE)) {
|
||||
// reset all the previously checked items if in single selection mode
|
||||
resetCheckedGrandchildren();
|
||||
}
|
||||
|
||||
// then toggle this one
|
||||
Checkable c = (Checkable) v;
|
||||
c.toggle();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise continue and launch the application
|
||||
int childIndex = getChildIndexForGrandChild(v);
|
||||
if (childIndex == getCurrentPage()) {
|
||||
final ApplicationInfo app = (ApplicationInfo) v.getTag();
|
||||
@@ -159,6 +183,8 @@ public class AllAppsPagedView extends PagedView
|
||||
mLauncher.startActivitySafely(app.intent, app);
|
||||
}
|
||||
});
|
||||
|
||||
endChoiceMode();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,6 +194,24 @@ public class AllAppsPagedView extends PagedView
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Uncomment this to enable selection mode with the action bar
|
||||
|
||||
// start the choice mode, and select the item that was long-pressed
|
||||
if (isChoiceMode(CHOICE_MODE_NONE)) {
|
||||
startChoiceMode(CHOICE_MODE_SINGLE, this);
|
||||
}
|
||||
|
||||
if (v instanceof Checkable) {
|
||||
// In preparation for drag, we always reset the checked grand children regardless of
|
||||
// what choice mode we are in
|
||||
resetCheckedGrandchildren();
|
||||
|
||||
// Toggle the selection on the dragged app
|
||||
Checkable c = (Checkable) v;
|
||||
c.toggle();
|
||||
}
|
||||
*/
|
||||
|
||||
ApplicationInfo app = (ApplicationInfo) v.getTag();
|
||||
app = new ApplicationInfo(app);
|
||||
|
||||
@@ -177,7 +221,10 @@ public class AllAppsPagedView extends PagedView
|
||||
|
||||
@Override
|
||||
public void onDropCompleted(View target, boolean success) {
|
||||
// do nothing
|
||||
// close the choice action mode if we have a proper drop
|
||||
if (target != this) {
|
||||
endChoiceMode();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -341,4 +388,63 @@ public class AllAppsPagedView extends PagedView
|
||||
params.cellY = index / mCellCountX;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
||||
mDragController.addDropTarget(this);
|
||||
|
||||
// REST TO BE IMPLEMENTED BY PAT
|
||||
mode.setTitle("Customization title goes here");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
mDragController.removeDropTarget(this);
|
||||
endChoiceMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
// TO BE IMPLEMENTED BY PAT
|
||||
// get the checked grandchild, and handle the action here
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't actually use AllAppsPagedView as a drop target... it's only used to intercept a drop
|
||||
* to the workspace.
|
||||
*/
|
||||
@Override
|
||||
public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
|
||||
DragView dragView, Object dragInfo) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset,
|
||||
DragView dragView, Object dragInfo, Rect recycle) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset,
|
||||
int yOffset, DragView dragView, Object dragInfo) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
|
||||
DragView dragView, Object dragInfo) {}
|
||||
@Override
|
||||
public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
|
||||
DragView dragView, Object dragInfo) {}
|
||||
@Override
|
||||
public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
|
||||
DragView dragView, Object dragInfo) {}
|
||||
@Override
|
||||
public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
|
||||
DragView dragView, Object dragInfo) {}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ package com.android.launcher2;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
@@ -27,6 +26,8 @@ import android.graphics.Rect;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.ActionMode;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.View;
|
||||
@@ -36,6 +37,7 @@ import android.view.ViewParent;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.Animation.AnimationListener;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.Checkable;
|
||||
import android.widget.Scroller;
|
||||
|
||||
import com.android.launcher.R;
|
||||
@@ -51,6 +53,7 @@ public abstract class PagedView extends ViewGroup {
|
||||
// the min drag distance for a fling to register, to prevent random page shifts
|
||||
private static final int MIN_LENGTH_FOR_FLING = 50;
|
||||
|
||||
private static final int PAGE_SNAP_ANIMATION_DURATION = 1000;
|
||||
protected static final float NANOTIME_DIV = 1000000000.0f;
|
||||
|
||||
// the velocity at which a fling gesture will cause us to snap to the next page
|
||||
@@ -96,6 +99,14 @@ public abstract class PagedView extends ViewGroup {
|
||||
private ArrayList<Boolean> mDirtyPageContent;
|
||||
private boolean mDirtyPageAlpha;
|
||||
|
||||
// choice modes
|
||||
protected static final int CHOICE_MODE_NONE = 0;
|
||||
protected static final int CHOICE_MODE_SINGLE = 1;
|
||||
// Multiple selection mode is not supported by all Launcher actions atm
|
||||
protected static final int CHOICE_MODE_MULTIPLE = 2;
|
||||
private int mChoiceMode;
|
||||
private ActionMode mActionMode;
|
||||
|
||||
protected PagedViewIconCache mPageViewIconCache;
|
||||
|
||||
// If true, syncPages and syncPageItems will be called to refresh pages
|
||||
@@ -153,6 +164,7 @@ public abstract class PagedView extends ViewGroup {
|
||||
|
||||
public PagedView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
mChoiceMode = CHOICE_MODE_NONE;
|
||||
|
||||
setHapticFeedbackEnabled(false);
|
||||
init();
|
||||
@@ -530,7 +542,14 @@ public abstract class PagedView extends ViewGroup {
|
||||
* otherwise don't. mScroller.isFinished should be false when
|
||||
* being flinged.
|
||||
*/
|
||||
mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;
|
||||
final int xDist = (mScroller.getFinalX() - mScroller.getCurrX());
|
||||
final boolean finishedScrolling = (mScroller.isFinished() || xDist < mTouchSlop);
|
||||
if (finishedScrolling) {
|
||||
mTouchState = TOUCH_STATE_REST;
|
||||
mScroller.abortAnimation();
|
||||
} else {
|
||||
mTouchState = TOUCH_STATE_SCROLLING;
|
||||
}
|
||||
|
||||
// check if this can be the beginning of a tap on the side of the pages
|
||||
// to scroll the current page
|
||||
@@ -819,7 +838,7 @@ public abstract class PagedView extends ViewGroup {
|
||||
minDistanceFromScreenCenterIndex = i;
|
||||
}
|
||||
}
|
||||
snapToPage(minDistanceFromScreenCenterIndex, 1000);
|
||||
snapToPage(minDistanceFromScreenCenterIndex, PAGE_SNAP_ANIMATION_DURATION);
|
||||
}
|
||||
|
||||
protected void snapToPageWithVelocity(int whichPage, int velocity) {
|
||||
@@ -829,7 +848,7 @@ public abstract class PagedView extends ViewGroup {
|
||||
}
|
||||
|
||||
protected void snapToPage(int whichPage) {
|
||||
snapToPage(whichPage, 1000);
|
||||
snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
|
||||
}
|
||||
|
||||
protected void snapToPage(int whichPage, int duration) {
|
||||
@@ -982,6 +1001,50 @@ public abstract class PagedView extends ViewGroup {
|
||||
}
|
||||
}
|
||||
|
||||
protected void startChoiceMode(int mode, ActionMode.Callback callback) {
|
||||
// StartActionMode may call through toendChoiceMode, so we should do this first
|
||||
mActionMode = startActionMode(callback);
|
||||
mChoiceMode = mode;
|
||||
}
|
||||
|
||||
protected void endChoiceMode() {
|
||||
if (!isChoiceMode(CHOICE_MODE_NONE)) {
|
||||
mActionMode.finish();
|
||||
mActionMode = null;
|
||||
mChoiceMode = CHOICE_MODE_NONE;
|
||||
resetCheckedGrandchildren();
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isChoiceMode(int mode) {
|
||||
return mChoiceMode == mode;
|
||||
}
|
||||
|
||||
protected ArrayList<Checkable> getCheckedGrandchildren() {
|
||||
ArrayList<Checkable> checked = new ArrayList<Checkable>();
|
||||
final int childCount = getChildCount();
|
||||
for (int i = 0; i < childCount; ++i) {
|
||||
final PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i);
|
||||
final int grandChildCount = layout.getChildCount();
|
||||
for (int j = 0; j < grandChildCount; ++j) {
|
||||
final View v = layout.getChildAt(j);
|
||||
if (v instanceof Checkable) {
|
||||
checked.add((Checkable) v);
|
||||
}
|
||||
}
|
||||
}
|
||||
return checked;
|
||||
}
|
||||
|
||||
protected void resetCheckedGrandchildren() {
|
||||
// loop through children, and set all of their children to _not_ be checked
|
||||
final ArrayList<Checkable> checked = getCheckedGrandchildren();
|
||||
for (int i = 0; i < checked.size(); ++i) {
|
||||
final Checkable c = checked.get(i);
|
||||
c.setChecked(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called ONLY to synchronize the number of pages that the paged view has.
|
||||
* To actually fill the pages with information, implement syncPageItems() below. It is
|
||||
|
||||
@@ -40,17 +40,19 @@ import android.widget.TextView;
|
||||
import com.android.launcher2.PagedView.PagedViewIconCache;
|
||||
|
||||
class HolographicOutlineHelper {
|
||||
private float mDensity;
|
||||
private final Paint mHolographicPaint = new Paint();
|
||||
private final Paint mBlurPaint = new Paint();
|
||||
private final Paint mErasePaint = new Paint();
|
||||
private static final Matrix mIdentity = new Matrix();
|
||||
private static final float STROKE_WIDTH = 6.0f;
|
||||
private static final Matrix mIdentity = new Matrix();;
|
||||
private static final float BLUR_FACTOR = 3.5f;
|
||||
|
||||
public static final float DEFAULT_STROKE_WIDTH = 6.0f;
|
||||
public static final int HOLOGRAPHIC_BLUE = 0xFF6699FF;
|
||||
public static final int HOLOGRAPHIC_GREEN = 0xFF66FF66;
|
||||
public static final int HOLOGRAPHIC_GREEN = 0xFF51E633;
|
||||
|
||||
HolographicOutlineHelper(float density) {
|
||||
mDensity = density;
|
||||
mHolographicPaint.setColor(HOLOGRAPHIC_BLUE);
|
||||
mHolographicPaint.setFilterBitmap(true);
|
||||
mHolographicPaint.setAntiAlias(true);
|
||||
@@ -101,13 +103,14 @@ class HolographicOutlineHelper {
|
||||
/**
|
||||
* Applies an outline to whatever is currently drawn in the specified bitmap.
|
||||
*/
|
||||
void applyOutline(Bitmap srcDst, Canvas srcDstCanvas, PointF offset) {
|
||||
void applyOutline(Bitmap srcDst, Canvas srcDstCanvas, float strokeWidth, PointF offset) {
|
||||
strokeWidth *= mDensity;
|
||||
Bitmap mask = srcDst.extractAlpha();
|
||||
Matrix m = new Matrix();
|
||||
final int width = srcDst.getWidth();
|
||||
final int height = srcDst.getHeight();
|
||||
float xScale = STROKE_WIDTH*2.0f/width;
|
||||
float yScale = STROKE_WIDTH*2.0f/height;
|
||||
float xScale = strokeWidth*2.0f/width;
|
||||
float yScale = strokeWidth*2.0f/height;
|
||||
m.preScale(1+xScale, 1+yScale, (width / 2.0f) + offset.x,
|
||||
(height / 2.0f) + offset.y);
|
||||
|
||||
@@ -138,6 +141,7 @@ public class PagedViewIcon extends TextView implements Checkable {
|
||||
// holographic outline
|
||||
private final Paint mPaint = new Paint();
|
||||
private static HolographicOutlineHelper sHolographicOutlineHelper;
|
||||
private Bitmap mCheckedOutline;
|
||||
private Bitmap mHolographicOutline;
|
||||
private Canvas mHolographicOutlineCanvas;
|
||||
private boolean mIsHolographicUpdatePass;
|
||||
@@ -207,6 +211,13 @@ public class PagedViewIcon extends TextView implements Checkable {
|
||||
super.setAlpha(viewAlpha);
|
||||
}
|
||||
|
||||
public void invalidateCheckedImage() {
|
||||
if (mCheckedOutline != null) {
|
||||
mCheckedOutline.recycle();
|
||||
mCheckedOutline = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
@@ -229,10 +240,11 @@ public class PagedViewIcon extends TextView implements Checkable {
|
||||
draw(mHolographicOutlineCanvas);
|
||||
sHolographicOutlineHelper.setColor(HolographicOutlineHelper.HOLOGRAPHIC_BLUE);
|
||||
sHolographicOutlineHelper.applyOutline(mHolographicOutline, mHolographicOutlineCanvas,
|
||||
offset);
|
||||
HolographicOutlineHelper.DEFAULT_STROKE_WIDTH, offset);
|
||||
sHolographicOutlineHelper.applyBlur(mHolographicOutline, mHolographicOutlineCanvas);
|
||||
mIsHolographicUpdatePass = false;
|
||||
mIconCache.addOutline(mIconCacheKey, mHolographicOutline);
|
||||
mHolographicOutlineCanvas = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,9 +266,17 @@ public class PagedViewIcon extends TextView implements Checkable {
|
||||
}
|
||||
}
|
||||
|
||||
if (!mIsHolographicUpdatePass && mHolographicOutline != null && mHolographicAlpha > 0) {
|
||||
mPaint.setAlpha(mHolographicAlpha);
|
||||
canvas.drawBitmap(mHolographicOutline, 0, 0, mPaint);
|
||||
// draw any blended overlays
|
||||
if (!mIsHolographicUpdatePass) {
|
||||
if (mCheckedOutline == null) {
|
||||
if (mHolographicOutline != null && mHolographicAlpha > 0) {
|
||||
mPaint.setAlpha(mHolographicAlpha);
|
||||
canvas.drawBitmap(mHolographicOutline, 0, 0, mPaint);
|
||||
}
|
||||
} else {
|
||||
mPaint.setAlpha(255);
|
||||
canvas.drawBitmap(mCheckedOutline, 0, 0, mPaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,8 +287,32 @@ public class PagedViewIcon extends TextView implements Checkable {
|
||||
|
||||
@Override
|
||||
public void setChecked(boolean checked) {
|
||||
mIsChecked = checked;
|
||||
invalidate();
|
||||
if (mIsChecked != checked) {
|
||||
mIsChecked = checked;
|
||||
|
||||
if (mIsChecked) {
|
||||
final PointF offset = new PointF(0,
|
||||
-(getCompoundPaddingBottom() + getCompoundPaddingTop())/2.0f);
|
||||
|
||||
// set a flag to indicate that we are going to draw the view at full alpha with the text
|
||||
// clipped for the generation of the holographic icon
|
||||
mIsHolographicUpdatePass = true;
|
||||
mCheckedOutline = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
|
||||
Bitmap.Config.ARGB_8888);
|
||||
mHolographicOutlineCanvas = new Canvas(mCheckedOutline);
|
||||
mHolographicOutlineCanvas.concat(getMatrix());
|
||||
draw(mHolographicOutlineCanvas);
|
||||
sHolographicOutlineHelper.setColor(HolographicOutlineHelper.HOLOGRAPHIC_GREEN);
|
||||
sHolographicOutlineHelper.applyOutline(mCheckedOutline, mHolographicOutlineCanvas,
|
||||
HolographicOutlineHelper.DEFAULT_STROKE_WIDTH + 1.0f, offset);
|
||||
mIsHolographicUpdatePass = false;
|
||||
mHolographicOutlineCanvas = null;
|
||||
} else {
|
||||
invalidateCheckedImage();
|
||||
}
|
||||
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user