Updating the icon click feedback
> Using BubbleTextView everywhere, removed PagedIconView > There is a brightness feedback on touch and shadow feedback on click, until app launches issue: 16878374 Change-Id: I3dc1149a123c8a75feca6210948398bf2187f1f2
This commit is contained in:
@@ -14,10 +14,8 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<com.android.launcher3.PagedViewIcon
|
||||
<com.android.launcher3.BubbleTextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3"
|
||||
|
||||
style="@style/WorkspaceIcon.AppsCustomize"
|
||||
android:id="@+id/application_icon"
|
||||
android:focusable="true" />
|
||||
|
||||
@@ -106,7 +106,6 @@
|
||||
<declare-styleable name="BubbleTextView">
|
||||
<!-- A spacing override for the icons within a page -->
|
||||
<attr name="customShadows" format="boolean" />
|
||||
<attr name="glowColor" format="color" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- AppsCustomizePagedView specific attributes. These attributes are used to
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
|
||||
<color name="quantum_panel_text_color">#FF666666</color>
|
||||
<color name="quantum_panel_text_shadow_color">#FFC4C4C4</color>
|
||||
<color name="folder_items_glow_color">#FFCCCCCC</color>
|
||||
<color name="outline_color">#FFFFFFFF</color>
|
||||
<color name="widget_text_panel">#FF374248</color>
|
||||
|
||||
|
||||
@@ -91,7 +91,8 @@
|
||||
<item name="android:shadowRadius">2.0</item>
|
||||
<item name="android:shadowDx">0</item>
|
||||
<item name="android:shadowDy">2</item>
|
||||
<item name="android:shadowColor">#FFC4C4C4</item>
|
||||
<item name="android:shadowColor">@color/quantum_panel_text_shadow_color</item>
|
||||
<item name="customShadows">false</item>
|
||||
</style>
|
||||
|
||||
<style name="WorkspaceIcon.Folder">
|
||||
@@ -103,7 +104,6 @@
|
||||
<item name="android:shadowDy">2</item>
|
||||
|
||||
<item name="customShadows">false</item>
|
||||
<item name="glowColor">@color/folder_items_glow_color</item>
|
||||
</style>
|
||||
|
||||
<style name="SearchDropTargetBar">
|
||||
|
||||
@@ -44,7 +44,6 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.GridLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
@@ -144,8 +143,7 @@ class AppsCustomizeAsyncTask extends AsyncTask<AsyncTaskPageData, Void, AsyncTas
|
||||
*/
|
||||
public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements
|
||||
View.OnClickListener, View.OnKeyListener, DragSource,
|
||||
PagedViewIcon.PressedCallback, PagedViewWidget.ShortPressListener,
|
||||
LauncherTransitionable {
|
||||
PagedViewWidget.ShortPressListener, LauncherTransitionable {
|
||||
static final String TAG = "AppsCustomizePagedView";
|
||||
|
||||
private static Rect sTmpRect = new Rect();
|
||||
@@ -167,7 +165,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
|
||||
// Save and Restore
|
||||
private int mSaveInstanceStateItemIndex = -1;
|
||||
private PagedViewIcon mPressedIcon;
|
||||
|
||||
// Content
|
||||
private ArrayList<AppInfo> mApps;
|
||||
@@ -444,39 +441,29 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// When we have exited all apps or are in transition, disregard clicks
|
||||
if (!mLauncher.isAllAppsVisible() ||
|
||||
mLauncher.getWorkspace().isSwitchingState()) return;
|
||||
if (!mLauncher.isAllAppsVisible()
|
||||
|| mLauncher.getWorkspace().isSwitchingState()
|
||||
|| !(v instanceof PagedViewWidget)) return;
|
||||
|
||||
if (v instanceof PagedViewIcon) {
|
||||
// Animate some feedback to the click
|
||||
final AppInfo appInfo = (AppInfo) v.getTag();
|
||||
|
||||
// Lock the drawable state to pressed until we return to Launcher
|
||||
if (mPressedIcon != null) {
|
||||
mPressedIcon.lockDrawableState();
|
||||
}
|
||||
mLauncher.onClickPagedViewIcon(v, appInfo);
|
||||
} else if (v instanceof PagedViewWidget) {
|
||||
// Let the user know that they have to long press to add a widget
|
||||
if (mWidgetInstructionToast != null) {
|
||||
mWidgetInstructionToast.cancel();
|
||||
}
|
||||
mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add,
|
||||
Toast.LENGTH_SHORT);
|
||||
mWidgetInstructionToast.show();
|
||||
|
||||
// Create a little animation to show that the widget can move
|
||||
float offsetY = getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);
|
||||
final ImageView p = (ImageView) v.findViewById(R.id.widget_preview);
|
||||
AnimatorSet bounce = LauncherAnimUtils.createAnimatorSet();
|
||||
ValueAnimator tyuAnim = LauncherAnimUtils.ofFloat(p, "translationY", offsetY);
|
||||
tyuAnim.setDuration(125);
|
||||
ValueAnimator tydAnim = LauncherAnimUtils.ofFloat(p, "translationY", 0f);
|
||||
tydAnim.setDuration(100);
|
||||
bounce.play(tyuAnim).before(tydAnim);
|
||||
bounce.setInterpolator(new AccelerateInterpolator());
|
||||
bounce.start();
|
||||
// Let the user know that they have to long press to add a widget
|
||||
if (mWidgetInstructionToast != null) {
|
||||
mWidgetInstructionToast.cancel();
|
||||
}
|
||||
mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add,
|
||||
Toast.LENGTH_SHORT);
|
||||
mWidgetInstructionToast.show();
|
||||
|
||||
// Create a little animation to show that the widget can move
|
||||
float offsetY = getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);
|
||||
final ImageView p = (ImageView) v.findViewById(R.id.widget_preview);
|
||||
AnimatorSet bounce = LauncherAnimUtils.createAnimatorSet();
|
||||
ValueAnimator tyuAnim = LauncherAnimUtils.ofFloat(p, "translationY", offsetY);
|
||||
tyuAnim.setDuration(125);
|
||||
ValueAnimator tydAnim = LauncherAnimUtils.ofFloat(p, "translationY", 0f);
|
||||
tydAnim.setDuration(100);
|
||||
bounce.play(tyuAnim).before(tydAnim);
|
||||
bounce.setInterpolator(new AccelerateInterpolator());
|
||||
bounce.start();
|
||||
}
|
||||
|
||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||
@@ -492,7 +479,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
}
|
||||
|
||||
private void beginDraggingApplication(View v) {
|
||||
mLauncher.getWorkspace().onDragStartedWithItem(v);
|
||||
mLauncher.getWorkspace().beginDragShared(v, this);
|
||||
}
|
||||
|
||||
@@ -726,7 +712,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
protected boolean beginDragging(final View v) {
|
||||
if (!super.beginDragging(v)) return false;
|
||||
|
||||
if (v instanceof PagedViewIcon) {
|
||||
if (v instanceof BubbleTextView) {
|
||||
beginDraggingApplication(v);
|
||||
} else if (v instanceof PagedViewWidget) {
|
||||
if (!beginDraggingWidget(v)) {
|
||||
@@ -741,9 +727,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
public void run() {
|
||||
// We don't enter spring-loaded mode if the drag has been cancelled
|
||||
if (mLauncher.getDragController().isDragging()) {
|
||||
// Reset the alpha on the dragged icon before we drag
|
||||
resetDrawableState();
|
||||
|
||||
// Go into spring loaded mode (must happen before we startDrag())
|
||||
mLauncher.enterSpringLoadedDragMode();
|
||||
}
|
||||
@@ -992,10 +975,10 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
ArrayList<Bitmap> images = new ArrayList<Bitmap>();
|
||||
for (int i = startIndex; i < endIndex; ++i) {
|
||||
AppInfo info = mApps.get(i);
|
||||
PagedViewIcon icon = (PagedViewIcon) mLayoutInflater.inflate(
|
||||
BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
|
||||
R.layout.apps_customize_application, layout, false);
|
||||
icon.applyFromApplicationInfo(info, true, this);
|
||||
icon.setOnClickListener(this);
|
||||
icon.applyFromApplicationInfo(info);
|
||||
icon.setOnClickListener(mLauncher);
|
||||
icon.setOnLongClickListener(this);
|
||||
icon.setOnTouchListener(this);
|
||||
icon.setOnKeyListener(this);
|
||||
@@ -1559,23 +1542,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
cancelAllTasks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void iconPressed(PagedViewIcon icon) {
|
||||
// Reset the previously pressed icon and store a reference to the pressed icon so that
|
||||
// we can reset it on return to Launcher (in Launcher.onResume())
|
||||
if (mPressedIcon != null) {
|
||||
mPressedIcon.resetDrawableState();
|
||||
}
|
||||
mPressedIcon = icon;
|
||||
}
|
||||
|
||||
public void resetDrawableState() {
|
||||
if (mPressedIcon != null) {
|
||||
mPressedIcon.resetDrawableState();
|
||||
mPressedIcon = null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We load an extra page on each side to prevent flashes from scrolling and loading of the
|
||||
* widget previews in the background with the AsyncTasks.
|
||||
|
||||
@@ -23,14 +23,13 @@ import android.content.res.Resources.Theme;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.graphics.Region.Op;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TypedValue;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.widget.TextView;
|
||||
@@ -44,12 +43,11 @@ public class BubbleTextView extends TextView {
|
||||
|
||||
private static SparseArray<Theme> sPreloaderThemes = new SparseArray<>(2);
|
||||
|
||||
static final float SHADOW_LARGE_RADIUS = 4.0f;
|
||||
static final float SHADOW_SMALL_RADIUS = 1.75f;
|
||||
static final float SHADOW_Y_OFFSET = 2.0f;
|
||||
static final int SHADOW_LARGE_COLOUR = 0xDD000000;
|
||||
static final int SHADOW_SMALL_COLOUR = 0xCC000000;
|
||||
static final float PADDING_H = 8.0f;
|
||||
private static final float SHADOW_LARGE_RADIUS = 4.0f;
|
||||
private static final float SHADOW_SMALL_RADIUS = 1.75f;
|
||||
private static final float SHADOW_Y_OFFSET = 2.0f;
|
||||
private static final int SHADOW_LARGE_COLOUR = 0xDD000000;
|
||||
private static final int SHADOW_SMALL_COLOUR = 0xCC000000;
|
||||
static final float PADDING_V = 3.0f;
|
||||
|
||||
private static final String TAG = "BubbleTextView";
|
||||
@@ -57,14 +55,7 @@ public class BubbleTextView extends TextView {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private HolographicOutlineHelper mOutlineHelper;
|
||||
private final Canvas mTempCanvas = new Canvas();
|
||||
private final Rect mTempRect = new Rect();
|
||||
private boolean mDidInvalidateForPressedState;
|
||||
private Bitmap mPressedOrFocusedBackground;
|
||||
private int mFocusedOutlineColor;
|
||||
private int mFocusedGlowColor;
|
||||
private int mPressedOutlineColor;
|
||||
private int mPressedGlowColor;
|
||||
private Bitmap mPressedBackground;
|
||||
|
||||
private float mSlop;
|
||||
|
||||
@@ -72,14 +63,15 @@ public class BubbleTextView extends TextView {
|
||||
private final boolean mCustomShadowsEnabled;
|
||||
private boolean mIsTextVisible;
|
||||
|
||||
// TODO: Remove custom background handling code, as no instance of BubbleTextView use any
|
||||
// background.
|
||||
private boolean mBackgroundSizeChanged;
|
||||
private final Drawable mBackground;
|
||||
|
||||
private boolean mStayPressed;
|
||||
private boolean mIgnorePressedStateChange;
|
||||
private CheckLongPressHelper mLongPressHelper;
|
||||
|
||||
private CharSequence mDefaultText = "";
|
||||
|
||||
public BubbleTextView(Context context) {
|
||||
this(context, null, 0);
|
||||
}
|
||||
@@ -91,11 +83,8 @@ public class BubbleTextView extends TextView {
|
||||
public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
Resources res = context.getResources();
|
||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
R.styleable.BubbleTextView, defStyle, 0);
|
||||
setGlowColor(a.getColor(R.styleable.BubbleTextView_glowColor,
|
||||
res.getColor(R.color.outline_color)));
|
||||
mCustomShadowsEnabled = a.getBoolean(R.styleable.BubbleTextView_customShadows, true);
|
||||
a.recycle();
|
||||
|
||||
@@ -143,6 +132,7 @@ public class BubbleTextView extends TextView {
|
||||
if (info.contentDescription != null) {
|
||||
setContentDescription(info.contentDescription);
|
||||
}
|
||||
setText(info.title);
|
||||
setTag(info);
|
||||
|
||||
if (info.wasPromise) {
|
||||
@@ -150,6 +140,22 @@ public class BubbleTextView extends TextView {
|
||||
}
|
||||
}
|
||||
|
||||
public void applyFromApplicationInfo(AppInfo info) {
|
||||
LauncherAppState app = LauncherAppState.getInstance();
|
||||
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
||||
|
||||
Drawable topDrawable = Utilities.createIconDrawable(info.iconBitmap);
|
||||
topDrawable.setBounds(0, 0, grid.allAppsIconSizePx, grid.allAppsIconSizePx);
|
||||
setCompoundDrawables(null, topDrawable, null, null);
|
||||
setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
|
||||
setText(info.title);
|
||||
if (info.contentDescription != null) {
|
||||
setContentDescription(info.contentDescription);
|
||||
}
|
||||
setTag(info);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean setFrame(int left, int top, int right, int bottom) {
|
||||
if (getLeft() != left || getRight() != right || getTop() != top || getBottom() != bottom) {
|
||||
@@ -169,98 +175,22 @@ public class BubbleTextView extends TextView {
|
||||
LauncherModel.checkItemInfo((ItemInfo) tag);
|
||||
}
|
||||
super.setTag(tag);
|
||||
if (tag instanceof ShortcutInfo) {
|
||||
final ShortcutInfo info = (ShortcutInfo) tag;
|
||||
mDefaultText = info.title;
|
||||
setText(mDefaultText);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawableStateChanged() {
|
||||
if (isPressed()) {
|
||||
// In this case, we have already created the pressed outline on ACTION_DOWN,
|
||||
// so we just need to do an invalidate to trigger draw
|
||||
if (!mDidInvalidateForPressedState) {
|
||||
setCellLayoutPressedOrFocusedIcon();
|
||||
}
|
||||
} else {
|
||||
// Otherwise, either clear the pressed/focused background, or create a background
|
||||
// for the focused state
|
||||
final boolean backgroundEmptyBefore = mPressedOrFocusedBackground == null;
|
||||
if (!mStayPressed) {
|
||||
mPressedOrFocusedBackground = null;
|
||||
}
|
||||
if (isFocused()) {
|
||||
if (getLayout() == null) {
|
||||
// In some cases, we get focus before we have been layed out. Set the
|
||||
// background to null so that it will get created when the view is drawn.
|
||||
mPressedOrFocusedBackground = null;
|
||||
} else {
|
||||
mPressedOrFocusedBackground = createGlowingOutline(
|
||||
mTempCanvas, mFocusedGlowColor, mFocusedOutlineColor);
|
||||
}
|
||||
mStayPressed = false;
|
||||
setCellLayoutPressedOrFocusedIcon();
|
||||
}
|
||||
final boolean backgroundEmptyNow = mPressedOrFocusedBackground == null;
|
||||
if (!backgroundEmptyBefore && backgroundEmptyNow) {
|
||||
setCellLayoutPressedOrFocusedIcon();
|
||||
}
|
||||
public void setPressed(boolean pressed) {
|
||||
super.setPressed(pressed);
|
||||
|
||||
if (!mIgnorePressedStateChange) {
|
||||
updateIconState();
|
||||
}
|
||||
}
|
||||
|
||||
Drawable d = mBackground;
|
||||
if (d != null && d.isStateful()) {
|
||||
d.setState(getDrawableState());
|
||||
private void updateIconState() {
|
||||
Drawable top = getCompoundDrawables()[1];
|
||||
if (top instanceof FastBitmapDrawable) {
|
||||
((FastBitmapDrawable) top).setPressed(isPressed() || mStayPressed);
|
||||
}
|
||||
super.drawableStateChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw this BubbleTextView into the given Canvas.
|
||||
*
|
||||
* @param destCanvas the canvas to draw on
|
||||
* @param padding the horizontal and vertical padding to use when drawing
|
||||
*/
|
||||
private void drawWithPadding(Canvas destCanvas, int padding) {
|
||||
final Rect clipRect = mTempRect;
|
||||
getDrawingRect(clipRect);
|
||||
|
||||
// adjust the clip rect so that we don't include the text label
|
||||
clipRect.bottom =
|
||||
getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V + getLayout().getLineTop(0);
|
||||
|
||||
// Draw the View into the bitmap.
|
||||
// The translate of scrollX and scrollY is necessary when drawing TextViews, because
|
||||
// they set scrollX and scrollY to large values to achieve centered text
|
||||
destCanvas.save();
|
||||
destCanvas.scale(getScaleX(), getScaleY(),
|
||||
(getWidth() + padding) / 2, (getHeight() + padding) / 2);
|
||||
destCanvas.translate(-getScrollX() + padding / 2, -getScrollY() + padding / 2);
|
||||
destCanvas.clipRect(clipRect, Op.REPLACE);
|
||||
draw(destCanvas);
|
||||
destCanvas.restore();
|
||||
}
|
||||
|
||||
public void setGlowColor(int color) {
|
||||
mFocusedOutlineColor = mFocusedGlowColor = mPressedOutlineColor = mPressedGlowColor = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
|
||||
* Responsibility for the bitmap is transferred to the caller.
|
||||
*/
|
||||
private Bitmap createGlowingOutline(Canvas canvas, int outlineColor, int glowColor) {
|
||||
final int padding = mOutlineHelper.mMaxOuterBlurRadius;
|
||||
final Bitmap b = Bitmap.createBitmap(
|
||||
getWidth() + padding, getHeight() + padding, Bitmap.Config.ARGB_8888);
|
||||
|
||||
canvas.setBitmap(b);
|
||||
drawWithPadding(canvas, padding);
|
||||
mOutlineHelper.applyExtraThickExpensiveOutlineWithBlur(b, canvas, glowColor, outlineColor);
|
||||
canvas.setBitmap(null);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -271,20 +201,11 @@ public class BubbleTextView extends TextView {
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
// So that the pressed outline is visible immediately when isPressed() is true,
|
||||
// So that the pressed outline is visible immediately on setStayPressed(),
|
||||
// we pre-create it on ACTION_DOWN (it takes a small but perceptible amount of time
|
||||
// to create it)
|
||||
if (mPressedOrFocusedBackground == null) {
|
||||
mPressedOrFocusedBackground = createGlowingOutline(
|
||||
mTempCanvas, mPressedGlowColor, mPressedOutlineColor);
|
||||
}
|
||||
// Invalidate so the pressed state is visible, or set a flag so we know that we
|
||||
// have to call invalidate as soon as the state is "pressed"
|
||||
if (isPressed()) {
|
||||
mDidInvalidateForPressedState = true;
|
||||
setCellLayoutPressedOrFocusedIcon();
|
||||
} else {
|
||||
mDidInvalidateForPressedState = false;
|
||||
if (mPressedBackground == null) {
|
||||
mPressedBackground = mOutlineHelper.createMediumDropShadow(this);
|
||||
}
|
||||
|
||||
mLongPressHelper.postCheckForLongPress();
|
||||
@@ -294,7 +215,7 @@ public class BubbleTextView extends TextView {
|
||||
// If we've touched down and up on an item, and it's still not "pressed", then
|
||||
// destroy the pressed outline
|
||||
if (!isPressed()) {
|
||||
mPressedOrFocusedBackground = null;
|
||||
mPressedBackground = null;
|
||||
}
|
||||
|
||||
mLongPressHelper.cancelLongPress();
|
||||
@@ -311,34 +232,47 @@ public class BubbleTextView extends TextView {
|
||||
void setStayPressed(boolean stayPressed) {
|
||||
mStayPressed = stayPressed;
|
||||
if (!stayPressed) {
|
||||
mPressedOrFocusedBackground = null;
|
||||
mPressedBackground = null;
|
||||
}
|
||||
setCellLayoutPressedOrFocusedIcon();
|
||||
|
||||
// Only show the shadow effect when persistent pressed state is set.
|
||||
if (getParent() instanceof ShortcutAndWidgetContainer) {
|
||||
CellLayout layout = (CellLayout) getParent().getParent();
|
||||
layout.setPressedIcon(this, mPressedBackground, mOutlineHelper.shadowBitmapPadding);
|
||||
}
|
||||
|
||||
updateIconState();
|
||||
}
|
||||
|
||||
void setCellLayoutPressedOrFocusedIcon() {
|
||||
// Disable pressed state when the icon is in preloader state.
|
||||
if ((getParent() instanceof ShortcutAndWidgetContainer) &&
|
||||
!(getCompoundDrawables()[1] instanceof PreloadIconDrawable)){
|
||||
ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) getParent();
|
||||
if (parent != null) {
|
||||
CellLayout layout = (CellLayout) parent.getParent();
|
||||
layout.setPressedOrFocusedIcon((mPressedOrFocusedBackground != null) ? this : null);
|
||||
void clearPressedBackground() {
|
||||
setPressed(false);
|
||||
setStayPressed(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (super.onKeyDown(keyCode, event)) {
|
||||
// Pre-create shadow so show immediately on click.
|
||||
if (mPressedBackground == null) {
|
||||
mPressedBackground = mOutlineHelper.createMediumDropShadow(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void clearPressedOrFocusedBackground() {
|
||||
mPressedOrFocusedBackground = null;
|
||||
setCellLayoutPressedOrFocusedIcon();
|
||||
}
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||
// Unlike touch events, keypress event propagate pressed state change immediately,
|
||||
// without waiting for onClickHandler to execute. Disable pressed state changes here
|
||||
// to avoid flickering.
|
||||
mIgnorePressedStateChange = true;
|
||||
boolean result = super.onKeyUp(keyCode, event);
|
||||
|
||||
Bitmap getPressedOrFocusedBackground() {
|
||||
return mPressedOrFocusedBackground;
|
||||
}
|
||||
|
||||
int getPressedOrFocusedBackgroundPadding() {
|
||||
return mOutlineHelper.mMaxOuterBlurRadius / 2;
|
||||
mPressedBackground = null;
|
||||
mIgnorePressedStateChange = false;
|
||||
updateIconState();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -122,7 +122,7 @@ public class CellLayout extends ViewGroup {
|
||||
private int mDragOutlineCurrent = 0;
|
||||
private final Paint mDragOutlinePaint = new Paint();
|
||||
|
||||
private BubbleTextView mPressedOrFocusedIcon;
|
||||
private final FastBitmapView mTouchFeedbackView;
|
||||
|
||||
private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new
|
||||
HashMap<CellLayout.LayoutParams, Animator>();
|
||||
@@ -287,6 +287,9 @@ public class CellLayout extends ViewGroup {
|
||||
mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap,
|
||||
mCountX, mCountY);
|
||||
|
||||
mTouchFeedbackView = new FastBitmapView(context);
|
||||
// Make the feedback view large enough to hold the blur bitmap.
|
||||
addView(mTouchFeedbackView, (int) (grid.cellWidthPx * 1.5), (int) (grid.cellHeightPx * 1.5));
|
||||
addView(mShortcutsAndWidgets);
|
||||
}
|
||||
|
||||
@@ -333,14 +336,6 @@ public class CellLayout extends ViewGroup {
|
||||
return mDropPending;
|
||||
}
|
||||
|
||||
private void invalidateBubbleTextView(BubbleTextView icon) {
|
||||
final int padding = icon.getPressedOrFocusedBackgroundPadding();
|
||||
invalidate(icon.getLeft() + getPaddingLeft() - padding,
|
||||
icon.getTop() + getPaddingTop() - padding,
|
||||
icon.getRight() + getPaddingLeft() + padding,
|
||||
icon.getBottom() + getPaddingTop() + padding);
|
||||
}
|
||||
|
||||
void setOverScrollAmount(float r, boolean left) {
|
||||
if (left && mOverScrollForegroundDrawable != mOverScrollLeft) {
|
||||
mOverScrollForegroundDrawable = mOverScrollLeft;
|
||||
@@ -354,16 +349,23 @@ public class CellLayout extends ViewGroup {
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void setPressedOrFocusedIcon(BubbleTextView icon) {
|
||||
// We draw the pressed or focused BubbleTextView's background in CellLayout because it
|
||||
// requires an expanded clip rect (due to the glow's blur radius)
|
||||
BubbleTextView oldIcon = mPressedOrFocusedIcon;
|
||||
mPressedOrFocusedIcon = icon;
|
||||
if (oldIcon != null) {
|
||||
invalidateBubbleTextView(oldIcon);
|
||||
}
|
||||
if (mPressedOrFocusedIcon != null) {
|
||||
invalidateBubbleTextView(mPressedOrFocusedIcon);
|
||||
void setPressedIcon(BubbleTextView icon, Bitmap background, int padding) {
|
||||
if (icon == null || background == null) {
|
||||
mTouchFeedbackView.setBitmap(null);
|
||||
mTouchFeedbackView.animate().cancel();
|
||||
} else {
|
||||
int offset = getMeasuredWidth() - getPaddingLeft() - getPaddingRight()
|
||||
- (mCountX * mCellWidth);
|
||||
mTouchFeedbackView.setTranslationX(icon.getLeft() + (int) Math.ceil(offset / 2f)
|
||||
- padding);
|
||||
mTouchFeedbackView.setTranslationY(icon.getTop() - padding);
|
||||
if (mTouchFeedbackView.setBitmap(background)) {
|
||||
mTouchFeedbackView.setAlpha(0);
|
||||
mTouchFeedbackView.animate().alpha(1)
|
||||
.setDuration(FastBitmapDrawable.CLICK_FEEDBACK_DURATION)
|
||||
.setInterpolator(FastBitmapDrawable.CLICK_FEEDBACK_INTERPOLATOR)
|
||||
.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,23 +424,6 @@ public class CellLayout extends ViewGroup {
|
||||
}
|
||||
}
|
||||
|
||||
// We draw the pressed or focused BubbleTextView's background in CellLayout because it
|
||||
// requires an expanded clip rect (due to the glow's blur radius)
|
||||
if (mPressedOrFocusedIcon != null) {
|
||||
final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding();
|
||||
final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground();
|
||||
if (b != null) {
|
||||
int offset = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() -
|
||||
(mCountX * mCellWidth);
|
||||
int left = getPaddingLeft() + (int) Math.ceil(offset / 2f);
|
||||
int top = getPaddingTop();
|
||||
canvas.drawBitmap(b,
|
||||
mPressedOrFocusedIcon.getLeft() + left - padding,
|
||||
mPressedOrFocusedIcon.getTop() + top - padding,
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG_VISUALIZE_OCCUPIED) {
|
||||
int[] pt = new int[2];
|
||||
ColorDrawable cd = new ColorDrawable(Color.RED);
|
||||
|
||||
@@ -16,30 +16,62 @@
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.ColorMatrix;
|
||||
import android.graphics.ColorMatrixColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.SparseArray;
|
||||
|
||||
class FastBitmapDrawable extends Drawable {
|
||||
|
||||
static final TimeInterpolator CLICK_FEEDBACK_INTERPOLATOR = new TimeInterpolator() {
|
||||
|
||||
@Override
|
||||
public float getInterpolation(float input) {
|
||||
if (input < 0.05f) {
|
||||
return input / 0.05f;
|
||||
} else if (input < 0.3f){
|
||||
return 1;
|
||||
} else {
|
||||
return (1 - input) / 0.7f;
|
||||
}
|
||||
}
|
||||
};
|
||||
static final long CLICK_FEEDBACK_DURATION = 2000;
|
||||
|
||||
private static final int PRESSED_BRIGHTNESS = 100;
|
||||
private static ColorMatrix sGhostModeMatrix;
|
||||
private static final ColorMatrix sTempMatrix = new ColorMatrix();
|
||||
|
||||
/**
|
||||
* Store the brightness colors filters to optimize animations during icon press. This
|
||||
* only works for non-ghost-mode icons.
|
||||
*/
|
||||
private static final SparseArray<ColorFilter> sCachedBrightnessFilter =
|
||||
new SparseArray<ColorFilter>();
|
||||
|
||||
private static final int GHOST_MODE_MIN_COLOR_RANGE = 130;
|
||||
|
||||
private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
|
||||
private Bitmap mBitmap;
|
||||
private final Bitmap mBitmap;
|
||||
private int mAlpha;
|
||||
|
||||
private int mBrightness = 0;
|
||||
private boolean mGhostModeEnabled = false;
|
||||
|
||||
private boolean mPressed = false;
|
||||
private ObjectAnimator mPressedAnimator;
|
||||
|
||||
FastBitmapDrawable(Bitmap b) {
|
||||
mAlpha = 255;
|
||||
mBitmap = b;
|
||||
@@ -114,6 +146,23 @@ class FastBitmapDrawable extends Drawable {
|
||||
}
|
||||
}
|
||||
|
||||
public void setPressed(boolean pressed) {
|
||||
if (mPressed != pressed) {
|
||||
mPressed = pressed;
|
||||
if (mPressed) {
|
||||
mPressedAnimator = ObjectAnimator
|
||||
.ofInt(this, "brightness", PRESSED_BRIGHTNESS)
|
||||
.setDuration(CLICK_FEEDBACK_DURATION);
|
||||
mPressedAnimator.setInterpolator(CLICK_FEEDBACK_INTERPOLATOR);
|
||||
mPressedAnimator.start();
|
||||
} else if (mPressedAnimator != null) {
|
||||
mPressedAnimator.cancel();
|
||||
setBrightness(0);
|
||||
}
|
||||
}
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
public boolean isGhostModeEnabled() {
|
||||
return mGhostModeEnabled;
|
||||
}
|
||||
@@ -122,14 +171,11 @@ class FastBitmapDrawable extends Drawable {
|
||||
return mBrightness;
|
||||
}
|
||||
|
||||
public void addBrightness(int amount) {
|
||||
setBrightness(mBrightness + amount);
|
||||
}
|
||||
|
||||
public void setBrightness(int brightness) {
|
||||
if (mBrightness != brightness) {
|
||||
mBrightness = brightness;
|
||||
updateFilter();
|
||||
invalidateSelf();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,8 +203,13 @@ class FastBitmapDrawable extends Drawable {
|
||||
mPaint.setColorFilter(new ColorMatrixColorFilter(sTempMatrix));
|
||||
}
|
||||
} else if (mBrightness != 0) {
|
||||
setBrightnessMatrix(sTempMatrix, mBrightness);
|
||||
mPaint.setColorFilter(new ColorMatrixColorFilter(sTempMatrix));
|
||||
ColorFilter filter = sCachedBrightnessFilter.get(mBrightness);
|
||||
if (filter == null) {
|
||||
filter = new PorterDuffColorFilter(Color.argb(mBrightness, 255, 255, 255),
|
||||
PorterDuff.Mode.SRC_ATOP);
|
||||
sCachedBrightnessFilter.put(mBrightness, filter);
|
||||
}
|
||||
mPaint.setColorFilter(filter);
|
||||
} else {
|
||||
mPaint.setColorFilter(null);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.view.View;
|
||||
|
||||
public class FastBitmapView extends View {
|
||||
|
||||
private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
|
||||
private Bitmap mBitmap;
|
||||
|
||||
public FastBitmapView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the new bitmap.
|
||||
* @return true if the view was invalidated.
|
||||
*/
|
||||
public boolean setBitmap(Bitmap b) {
|
||||
if (b != mBitmap){
|
||||
if (mBitmap != null) {
|
||||
invalidate(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
|
||||
}
|
||||
mBitmap = b;
|
||||
if (mBitmap != null) {
|
||||
invalidate(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (mBitmap != null) {
|
||||
canvas.drawBitmap(mBitmap, 0, 0, mPaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,8 +22,6 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TabHost;
|
||||
import android.widget.TabWidget;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -89,7 +87,6 @@ public class FocusHelper {
|
||||
|
||||
final PagedViewGridLayout parent = (PagedViewGridLayout) w.getParent();
|
||||
final PagedView container = (PagedView) parent.getParent();
|
||||
final AppsCustomizeTabHost tabHost = findTabHostParent(container);
|
||||
final int widgetIndex = parent.indexOfChild(w);
|
||||
final int widgetCount = parent.getChildCount();
|
||||
final int pageIndex = ((PagedView) container).indexToPage(container.indexOfChild(parent));
|
||||
@@ -228,6 +225,13 @@ public class FocusHelper {
|
||||
* Handles key events in a PageViewCellLayout containing PagedViewIcons.
|
||||
*/
|
||||
static boolean handleAppsCustomizeKeyEvent(View v, int keyCode, KeyEvent e) {
|
||||
final int action = e.getAction();
|
||||
if (((action == KeyEvent.ACTION_DOWN) && v.onKeyDown(keyCode, e))
|
||||
|| ((action == KeyEvent.ACTION_UP) && v.onKeyUp(keyCode, e))) {
|
||||
// Let the view handle the confirmation key.
|
||||
return true;
|
||||
}
|
||||
|
||||
ViewGroup parentLayout;
|
||||
ViewGroup itemContainer;
|
||||
int countX;
|
||||
@@ -246,7 +250,6 @@ public class FocusHelper {
|
||||
// Note we have an extra parent because of the
|
||||
// PagedViewCellLayout/PagedViewCellLayoutChildren relationship
|
||||
final PagedView container = (PagedView) parentLayout.getParent();
|
||||
final AppsCustomizeTabHost tabHost = findTabHostParent(container);
|
||||
final int iconIndex = itemContainer.indexOfChild(v);
|
||||
final int itemCount = itemContainer.getChildCount();
|
||||
final int pageIndex = ((PagedView) container).indexToPage(container.indexOfChild(parentLayout));
|
||||
@@ -255,7 +258,6 @@ public class FocusHelper {
|
||||
final int x = iconIndex % countX;
|
||||
final int y = iconIndex / countX;
|
||||
|
||||
final int action = e.getAction();
|
||||
final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
|
||||
ViewGroup newParent = null;
|
||||
// Side pages do not always load synchronously, so check before focusing child siblings
|
||||
@@ -319,15 +321,6 @@ public class FocusHelper {
|
||||
}
|
||||
wasHandled = true;
|
||||
break;
|
||||
case KeyEvent.KEYCODE_ENTER:
|
||||
case KeyEvent.KEYCODE_DPAD_CENTER:
|
||||
if (handleKeyEvent) {
|
||||
// Simulate a click on the icon
|
||||
View.OnClickListener clickListener = (View.OnClickListener) container;
|
||||
clickListener.onClick(v);
|
||||
}
|
||||
wasHandled = true;
|
||||
break;
|
||||
case KeyEvent.KEYCODE_PAGE_UP:
|
||||
if (handleKeyEvent) {
|
||||
// Select the first icon on the previous page, or the first icon on this page
|
||||
|
||||
@@ -118,10 +118,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
|
||||
|
||||
private FocusIndicatorView mFocusIndicatorHandler;
|
||||
|
||||
private int DRAG_MODE_NONE = 0;
|
||||
private int DRAG_MODE_REORDER = 1;
|
||||
private int mDragMode = DRAG_MODE_NONE;
|
||||
|
||||
// We avoid measuring the scroll view with a 0 width or height, as this
|
||||
// results in CellLayout being measured as UNSPECIFIED, which it does
|
||||
// not support.
|
||||
@@ -254,7 +250,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
|
||||
|
||||
mLauncher.getLauncherClings().dismissFolderCling(null);
|
||||
|
||||
mLauncher.getWorkspace().onDragStartedWithItem(v);
|
||||
mLauncher.getWorkspace().beginDragShared(v, this);
|
||||
|
||||
mCurrentDragInfo = item;
|
||||
@@ -783,9 +778,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
|
||||
mReorderAlarm.setAlarm(REORDER_DELAY);
|
||||
mPreviousTargetCell[0] = mTargetCell[0];
|
||||
mPreviousTargetCell[1] = mTargetCell[1];
|
||||
mDragMode = DRAG_MODE_REORDER;
|
||||
} else {
|
||||
mDragMode = DRAG_MODE_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -841,7 +833,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
|
||||
mOnExitAlarm.setAlarm(ON_EXIT_CLOSE_DELAY);
|
||||
}
|
||||
mReorderAlarm.cancelAlarm();
|
||||
mDragMode = DRAG_MODE_NONE;
|
||||
}
|
||||
|
||||
public void onDropCompleted(final View target, final DragObject d,
|
||||
|
||||
@@ -583,9 +583,10 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
||||
d.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize);
|
||||
if (d instanceof FastBitmapDrawable) {
|
||||
FastBitmapDrawable fd = (FastBitmapDrawable) d;
|
||||
fd.addBrightness(params.overlayAlpha);
|
||||
int oldBrightness = fd.getBrightness();
|
||||
fd.setBrightness(params.overlayAlpha);
|
||||
d.draw(canvas);
|
||||
fd.addBrightness(-params.overlayAlpha);
|
||||
fd.setBrightness(oldBrightness);
|
||||
} else {
|
||||
d.setColorFilter(Color.argb(params.overlayAlpha, 255, 255, 255),
|
||||
PorterDuff.Mode.SRC_ATOP);
|
||||
|
||||
@@ -20,48 +20,49 @@ import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BlurMaskFilter;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region.Op;
|
||||
|
||||
public class HolographicOutlineHelper {
|
||||
private final Paint mHolographicPaint = new Paint();
|
||||
|
||||
private static final Rect sTempRect = new Rect();
|
||||
|
||||
private final Canvas mCanvas = new Canvas();
|
||||
private final Paint mDrawPaint = new Paint();
|
||||
private final Paint mBlurPaint = new Paint();
|
||||
private final Paint mErasePaint = new Paint();
|
||||
|
||||
public int mMaxOuterBlurRadius;
|
||||
public int mMinOuterBlurRadius;
|
||||
private final BlurMaskFilter mMediumOuterBlurMaskFilter;
|
||||
private final BlurMaskFilter mThinOuterBlurMaskFilter;
|
||||
private final BlurMaskFilter mMediumInnerBlurMaskFilter;
|
||||
|
||||
private BlurMaskFilter mExtraThickOuterBlurMaskFilter;
|
||||
private BlurMaskFilter mThickOuterBlurMaskFilter;
|
||||
private BlurMaskFilter mMediumOuterBlurMaskFilter;
|
||||
private BlurMaskFilter mThinOuterBlurMaskFilter;
|
||||
private BlurMaskFilter mThickInnerBlurMaskFilter;
|
||||
private BlurMaskFilter mExtraThickInnerBlurMaskFilter;
|
||||
private BlurMaskFilter mMediumInnerBlurMaskFilter;
|
||||
private final BlurMaskFilter mShaowBlurMaskFilter;
|
||||
private final int mShadowOffset;
|
||||
|
||||
private static final int THICK = 0;
|
||||
private static final int MEDIUM = 1;
|
||||
private static final int EXTRA_THICK = 2;
|
||||
/**
|
||||
* Padding used when creating shadow bitmap;
|
||||
*/
|
||||
final int shadowBitmapPadding;
|
||||
|
||||
static HolographicOutlineHelper INSTANCE;
|
||||
|
||||
private HolographicOutlineHelper(Context context) {
|
||||
final float scale = LauncherAppState.getInstance().getScreenDensity();
|
||||
|
||||
mMinOuterBlurRadius = (int) (scale * 1.0f);
|
||||
mMaxOuterBlurRadius = (int) (scale * 12.0f);
|
||||
|
||||
mExtraThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 12.0f, BlurMaskFilter.Blur.OUTER);
|
||||
mThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.OUTER);
|
||||
mMediumOuterBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.OUTER);
|
||||
mThinOuterBlurMaskFilter = new BlurMaskFilter(scale * 1.0f, BlurMaskFilter.Blur.OUTER);
|
||||
mExtraThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.NORMAL);
|
||||
mThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 4.0f, BlurMaskFilter.Blur.NORMAL);
|
||||
mMediumInnerBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.NORMAL);
|
||||
|
||||
mHolographicPaint.setFilterBitmap(true);
|
||||
mHolographicPaint.setAntiAlias(true);
|
||||
mShaowBlurMaskFilter = new BlurMaskFilter(scale * 4.0f, BlurMaskFilter.Blur.NORMAL);
|
||||
mShadowOffset = (int) (scale * 2.0f);
|
||||
shadowBitmapPadding = (int) (scale * 4.0f);
|
||||
|
||||
mDrawPaint.setFilterBitmap(true);
|
||||
mDrawPaint.setAntiAlias(true);
|
||||
mBlurPaint.setFilterBitmap(true);
|
||||
mBlurPaint.setAntiAlias(true);
|
||||
mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
|
||||
@@ -76,38 +77,16 @@ public class HolographicOutlineHelper {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the interpolated holographic highlight alpha for the effect we want when scrolling
|
||||
* pages.
|
||||
*/
|
||||
public static float highlightAlphaInterpolator(float r) {
|
||||
float maxAlpha = 0.6f;
|
||||
return (float) Math.pow(maxAlpha * (1.0f - r), 1.5f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the interpolated view alpha for the effect we want when scrolling pages.
|
||||
*/
|
||||
public static float viewAlphaInterpolator(float r) {
|
||||
final float pivot = 0.95f;
|
||||
if (r < pivot) {
|
||||
return (float) Math.pow(r / pivot, 1.5f);
|
||||
} else {
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a more expensive and accurate outline to whatever is currently drawn in a specified
|
||||
* bitmap.
|
||||
*/
|
||||
void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
|
||||
int outlineColor, int thickness) {
|
||||
applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true,
|
||||
thickness);
|
||||
int outlineColor) {
|
||||
applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true);
|
||||
}
|
||||
void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
|
||||
int outlineColor, boolean clipAlpha, int thickness) {
|
||||
int outlineColor, boolean clipAlpha) {
|
||||
|
||||
// We start by removing most of the alpha channel so as to ignore shadows, and
|
||||
// other types of partial transparency when defining the shape of the object
|
||||
@@ -127,50 +106,18 @@ public class HolographicOutlineHelper {
|
||||
Bitmap glowShape = srcDst.extractAlpha();
|
||||
|
||||
// calculate the outer blur first
|
||||
BlurMaskFilter outerBlurMaskFilter;
|
||||
switch (thickness) {
|
||||
case EXTRA_THICK:
|
||||
outerBlurMaskFilter = mExtraThickOuterBlurMaskFilter;
|
||||
break;
|
||||
case THICK:
|
||||
outerBlurMaskFilter = mThickOuterBlurMaskFilter;
|
||||
break;
|
||||
case MEDIUM:
|
||||
outerBlurMaskFilter = mMediumOuterBlurMaskFilter;
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Invalid blur thickness");
|
||||
}
|
||||
mBlurPaint.setMaskFilter(outerBlurMaskFilter);
|
||||
mBlurPaint.setMaskFilter(mMediumOuterBlurMaskFilter);
|
||||
int[] outerBlurOffset = new int[2];
|
||||
Bitmap thickOuterBlur = glowShape.extractAlpha(mBlurPaint, outerBlurOffset);
|
||||
if (thickness == EXTRA_THICK) {
|
||||
mBlurPaint.setMaskFilter(mMediumOuterBlurMaskFilter);
|
||||
} else {
|
||||
mBlurPaint.setMaskFilter(mThinOuterBlurMaskFilter);
|
||||
}
|
||||
|
||||
mBlurPaint.setMaskFilter(mThinOuterBlurMaskFilter);
|
||||
int[] brightOutlineOffset = new int[2];
|
||||
Bitmap brightOutline = glowShape.extractAlpha(mBlurPaint, brightOutlineOffset);
|
||||
|
||||
// calculate the inner blur
|
||||
srcDstCanvas.setBitmap(glowShape);
|
||||
srcDstCanvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT);
|
||||
BlurMaskFilter innerBlurMaskFilter;
|
||||
switch (thickness) {
|
||||
case EXTRA_THICK:
|
||||
innerBlurMaskFilter = mExtraThickInnerBlurMaskFilter;
|
||||
break;
|
||||
case THICK:
|
||||
innerBlurMaskFilter = mThickInnerBlurMaskFilter;
|
||||
break;
|
||||
case MEDIUM:
|
||||
innerBlurMaskFilter = mMediumInnerBlurMaskFilter;
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Invalid blur thickness");
|
||||
}
|
||||
mBlurPaint.setMaskFilter(innerBlurMaskFilter);
|
||||
mBlurPaint.setMaskFilter(mMediumInnerBlurMaskFilter);
|
||||
int[] thickInnerBlurOffset = new int[2];
|
||||
Bitmap thickInnerBlur = glowShape.extractAlpha(mBlurPaint, thickInnerBlurOffset);
|
||||
|
||||
@@ -186,16 +133,16 @@ public class HolographicOutlineHelper {
|
||||
// draw the inner and outer blur
|
||||
srcDstCanvas.setBitmap(srcDst);
|
||||
srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
|
||||
mHolographicPaint.setColor(color);
|
||||
mDrawPaint.setColor(color);
|
||||
srcDstCanvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1],
|
||||
mHolographicPaint);
|
||||
mDrawPaint);
|
||||
srcDstCanvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1],
|
||||
mHolographicPaint);
|
||||
mDrawPaint);
|
||||
|
||||
// draw the bright outline
|
||||
mHolographicPaint.setColor(outlineColor);
|
||||
mDrawPaint.setColor(outlineColor);
|
||||
srcDstCanvas.drawBitmap(brightOutline, brightOutlineOffset[0], brightOutlineOffset[1],
|
||||
mHolographicPaint);
|
||||
mDrawPaint);
|
||||
|
||||
// cleanup
|
||||
srcDstCanvas.setBitmap(null);
|
||||
@@ -205,25 +152,52 @@ public class HolographicOutlineHelper {
|
||||
glowShape.recycle();
|
||||
}
|
||||
|
||||
void applyExtraThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
|
||||
int outlineColor) {
|
||||
applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, EXTRA_THICK);
|
||||
}
|
||||
Bitmap createMediumDropShadow(BubbleTextView view) {
|
||||
final Bitmap result = Bitmap.createBitmap(
|
||||
view.getWidth() + shadowBitmapPadding + shadowBitmapPadding,
|
||||
view.getHeight() + shadowBitmapPadding + shadowBitmapPadding + mShadowOffset,
|
||||
Bitmap.Config.ARGB_8888);
|
||||
|
||||
void applyThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
|
||||
int outlineColor) {
|
||||
applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, THICK);
|
||||
}
|
||||
mCanvas.setBitmap(result);
|
||||
|
||||
void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
|
||||
int outlineColor, boolean clipAlpha) {
|
||||
applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, clipAlpha,
|
||||
MEDIUM);
|
||||
}
|
||||
final Rect clipRect = sTempRect;
|
||||
view.getDrawingRect(sTempRect);
|
||||
// adjust the clip rect so that we don't include the text label
|
||||
clipRect.bottom = view.getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V
|
||||
+ view.getLayout().getLineTop(0);
|
||||
|
||||
void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
|
||||
int outlineColor) {
|
||||
applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, MEDIUM);
|
||||
}
|
||||
// Draw the View into the bitmap.
|
||||
// The translate of scrollX and scrollY is necessary when drawing TextViews, because
|
||||
// they set scrollX and scrollY to large values to achieve centered text
|
||||
mCanvas.save();
|
||||
mCanvas.scale(view.getScaleX(), view.getScaleY(),
|
||||
view.getWidth() / 2 + shadowBitmapPadding,
|
||||
view.getHeight() / 2 + shadowBitmapPadding);
|
||||
mCanvas.translate(-view.getScrollX() + shadowBitmapPadding,
|
||||
-view.getScrollY() + shadowBitmapPadding);
|
||||
mCanvas.clipRect(clipRect, Op.REPLACE);
|
||||
view.draw(mCanvas);
|
||||
mCanvas.restore();
|
||||
|
||||
int[] blurOffst = new int[2];
|
||||
mBlurPaint.setMaskFilter(mShaowBlurMaskFilter);
|
||||
Bitmap blurBitmap = result.extractAlpha(mBlurPaint, blurOffst);
|
||||
|
||||
mCanvas.save();
|
||||
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
|
||||
mCanvas.translate(blurOffst[0], blurOffst[1]);
|
||||
|
||||
mDrawPaint.setColor(Color.BLACK);
|
||||
mDrawPaint.setAlpha(30);
|
||||
mCanvas.drawBitmap(blurBitmap, 0, 0, mDrawPaint);
|
||||
|
||||
mDrawPaint.setAlpha(60);
|
||||
mCanvas.drawBitmap(blurBitmap, 0, mShadowOffset, mDrawPaint);
|
||||
mCanvas.restore();
|
||||
|
||||
mCanvas.setBitmap(null);
|
||||
blurBitmap.recycle();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,6 @@ import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View.OnLongClickListener;
|
||||
import android.view.ViewAnimationUtils;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
||||
@@ -1026,10 +1025,6 @@ public class Launcher extends Activity
|
||||
// Resets the previous workspace icon press state
|
||||
mWaitingForResume.setStayPressed(false);
|
||||
}
|
||||
if (mAppsCustomizeContent != null) {
|
||||
// Resets the previous all apps icon press state
|
||||
mAppsCustomizeContent.resetDrawableState();
|
||||
}
|
||||
|
||||
// It is possible that widgets can receive updates while launcher is not in the foreground.
|
||||
// Consequently, the widgets will be inflated in the orientation of the foreground activity
|
||||
@@ -2451,6 +2446,8 @@ public class Launcher extends Activity
|
||||
}
|
||||
} else if (v == mAllAppsButton) {
|
||||
onClickAllAppsButton(v);
|
||||
} else if (tag instanceof AppInfo) {
|
||||
startAppShortcutOrInfoActivity(v);
|
||||
} else if (tag instanceof LauncherAppWidgetInfo) {
|
||||
if (v instanceof PendingAppWidgetHostView) {
|
||||
onClickPendingWidget((PendingAppWidgetHostView) v);
|
||||
@@ -2458,6 +2455,10 @@ public class Launcher extends Activity
|
||||
}
|
||||
}
|
||||
|
||||
public void onClickPagedViewIcon(View v) {
|
||||
startAppShortcutOrInfoActivity(v);
|
||||
}
|
||||
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
return false;
|
||||
}
|
||||
@@ -2538,17 +2539,6 @@ public class Launcher extends Activity
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler for a paged view icon click.
|
||||
* @param v The view that was clicked.
|
||||
* @param appInfo The {link AppInfo} of the view.
|
||||
*/
|
||||
public void onClickPagedViewIcon(View v, AppInfo appInfo) {
|
||||
if (LOGD) Log.d(TAG, "onClickPagedViewIcon");
|
||||
startActivitySafely(v, appInfo.intent, appInfo);
|
||||
getStats().recordLaunch(appInfo.intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler for an app shortcut click.
|
||||
*
|
||||
@@ -2586,7 +2576,7 @@ public class Launcher extends Activity
|
||||
builder.setPositiveButton(R.string.abandoned_search,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
startAppShortcutActivity(v);
|
||||
startAppShortcutOrInfoActivity(v);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -2603,24 +2593,29 @@ public class Launcher extends Activity
|
||||
}
|
||||
|
||||
// Start activities
|
||||
startAppShortcutActivity(v);
|
||||
startAppShortcutOrInfoActivity(v);
|
||||
}
|
||||
|
||||
private void startAppShortcutActivity(View v) {
|
||||
private void startAppShortcutOrInfoActivity(View v) {
|
||||
Object tag = v.getTag();
|
||||
if (!(tag instanceof ShortcutInfo)) {
|
||||
throw new IllegalArgumentException("Input must be a Shortcut");
|
||||
}
|
||||
final ShortcutInfo shortcut = (ShortcutInfo) tag;
|
||||
final Intent intent = shortcut.intent;
|
||||
final ShortcutInfo shortcut;
|
||||
final Intent intent;
|
||||
if (tag instanceof ShortcutInfo) {
|
||||
shortcut = (ShortcutInfo) tag;
|
||||
intent = shortcut.intent;
|
||||
int[] pos = new int[2];
|
||||
v.getLocationOnScreen(pos);
|
||||
intent.setSourceBounds(new Rect(pos[0], pos[1],
|
||||
pos[0] + v.getWidth(), pos[1] + v.getHeight()));
|
||||
|
||||
int[] pos = new int[2];
|
||||
v.getLocationOnScreen(pos);
|
||||
intent.setSourceBounds(new Rect(pos[0], pos[1],
|
||||
pos[0] + v.getWidth(), pos[1] + v.getHeight()));
|
||||
} else if (tag instanceof AppInfo) {
|
||||
shortcut = null;
|
||||
intent = ((AppInfo) tag).intent;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Input must be a Shortcut or AppInfo");
|
||||
}
|
||||
|
||||
boolean success = startActivitySafely(v, intent, tag);
|
||||
|
||||
mStats.recordLaunch(intent, shortcut);
|
||||
|
||||
if (success && v instanceof BubbleTextView) {
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Region;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* An icon on a PagedView, specifically for items in the launcher's paged view (with compound
|
||||
* drawables on the top).
|
||||
*/
|
||||
public class PagedViewIcon extends TextView {
|
||||
/** A simple callback interface to allow a PagedViewIcon to notify when it has been pressed */
|
||||
public static interface PressedCallback {
|
||||
void iconPressed(PagedViewIcon icon);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = "PagedViewIcon";
|
||||
private static final float PRESS_ALPHA = 0.4f;
|
||||
|
||||
private PagedViewIcon.PressedCallback mPressedCallback;
|
||||
private boolean mLockDrawableState = false;
|
||||
|
||||
private Bitmap mIcon;
|
||||
|
||||
public PagedViewIcon(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public PagedViewIcon(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public PagedViewIcon(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
public void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
// Ensure we are using the right text size
|
||||
LauncherAppState app = LauncherAppState.getInstance();
|
||||
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
|
||||
}
|
||||
|
||||
public void applyFromApplicationInfo(AppInfo info, boolean scaleUp,
|
||||
PagedViewIcon.PressedCallback cb) {
|
||||
LauncherAppState app = LauncherAppState.getInstance();
|
||||
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
||||
|
||||
mIcon = info.iconBitmap;
|
||||
mPressedCallback = cb;
|
||||
Drawable icon = Utilities.createIconDrawable(mIcon);
|
||||
icon.setBounds(0, 0, grid.allAppsIconSizePx, grid.allAppsIconSizePx);
|
||||
setCompoundDrawables(null, icon, null, null);
|
||||
setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
|
||||
setText(info.title);
|
||||
if (info.contentDescription != null) {
|
||||
setContentDescription(info.contentDescription);
|
||||
}
|
||||
setTag(info);
|
||||
}
|
||||
|
||||
public void lockDrawableState() {
|
||||
mLockDrawableState = true;
|
||||
}
|
||||
|
||||
public void resetDrawableState() {
|
||||
mLockDrawableState = false;
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
refreshDrawableState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void drawableStateChanged() {
|
||||
super.drawableStateChanged();
|
||||
|
||||
// We keep in the pressed state until resetDrawableState() is called to reset the press
|
||||
// feedback
|
||||
if (isPressed()) {
|
||||
setAlpha(PRESS_ALPHA);
|
||||
if (mPressedCallback != null) {
|
||||
mPressedCallback.iconPressed(this);
|
||||
}
|
||||
} else if (!mLockDrawableState) {
|
||||
setAlpha(1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,6 @@ import android.animation.TimeInterpolator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.animation.ValueAnimator.AnimatorUpdateListener;
|
||||
import android.app.WallpaperManager;
|
||||
import android.appwidget.AppWidgetHost;
|
||||
import android.appwidget.AppWidgetHostView;
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.ComponentName;
|
||||
@@ -47,9 +46,7 @@ import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Handler;
|
||||
import android.os.Handler.Callback;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.Parcelable;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.util.AttributeSet;
|
||||
@@ -76,9 +73,7 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* The workspace is a wide area with a wallpaper and a finite number of pages.
|
||||
@@ -212,7 +207,7 @@ public class Workspace extends SmoothPagedView
|
||||
|
||||
private HolographicOutlineHelper mOutlineHelper;
|
||||
private Bitmap mDragOutline = null;
|
||||
private final Rect mTempRect = new Rect();
|
||||
private static final Rect sTempRect = new Rect();
|
||||
private final int[] mTempXY = new int[2];
|
||||
private int[] mTempVisiblePagesRange = new int[2];
|
||||
private boolean mOverscrollEffectSet;
|
||||
@@ -241,6 +236,8 @@ public class Workspace extends SmoothPagedView
|
||||
private DropTarget.DragEnforcer mDragEnforcer;
|
||||
private float mMaxDistanceForFolderCreation;
|
||||
|
||||
private final Canvas mCanvas = new Canvas();
|
||||
|
||||
// Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget)
|
||||
private float mXDown;
|
||||
private float mYDown;
|
||||
@@ -1980,14 +1977,7 @@ public class Workspace extends SmoothPagedView
|
||||
* appearance).
|
||||
*
|
||||
*/
|
||||
public void onDragStartedWithItem(View v) {
|
||||
final Canvas canvas = new Canvas();
|
||||
|
||||
// The outline is used to visualize where the item will land if dropped
|
||||
mDragOutline = createDragOutline(v, canvas, DRAG_BITMAP_PADDING);
|
||||
}
|
||||
|
||||
private Rect getDrawableBounds(Drawable d) {
|
||||
private static Rect getDrawableBounds(Drawable d) {
|
||||
Rect bounds = new Rect();
|
||||
d.copyBounds(bounds);
|
||||
if (bounds.width() == 0 || bounds.height() == 0) {
|
||||
@@ -2003,8 +1993,6 @@ public class Workspace extends SmoothPagedView
|
||||
}
|
||||
|
||||
public void onExternalDragStartedWithItem(View v) {
|
||||
final Canvas canvas = new Canvas();
|
||||
|
||||
// Compose a drag bitmap with the view scaled to the icon size
|
||||
LauncherAppState app = LauncherAppState.getInstance();
|
||||
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
||||
@@ -2024,22 +2012,19 @@ public class Workspace extends SmoothPagedView
|
||||
// Compose the bitmap to create the icon from
|
||||
Bitmap b = Bitmap.createBitmap(bmpWidth, bmpHeight,
|
||||
Bitmap.Config.ARGB_8888);
|
||||
Canvas c = new Canvas(b);
|
||||
drawDragView(v, c, 0);
|
||||
c.setBitmap(null);
|
||||
mCanvas.setBitmap(b);
|
||||
drawDragView(v, mCanvas, 0);
|
||||
mCanvas.setBitmap(null);
|
||||
|
||||
// The outline is used to visualize where the item will land if dropped
|
||||
mDragOutline = createDragOutline(b, canvas, DRAG_BITMAP_PADDING, iconSize, iconSize, true);
|
||||
mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, iconSize, iconSize, true);
|
||||
}
|
||||
|
||||
public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) {
|
||||
final Canvas canvas = new Canvas();
|
||||
|
||||
int[] size = estimateItemSize(info.spanX, info.spanY, info, false);
|
||||
|
||||
// The outline is used to visualize where the item will land if dropped
|
||||
mDragOutline = createDragOutline(b, canvas, DRAG_BITMAP_PADDING, size[0],
|
||||
size[1], clipAlpha);
|
||||
mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, size[0], size[1], clipAlpha);
|
||||
}
|
||||
|
||||
public void exitWidgetResizeMode() {
|
||||
@@ -2537,8 +2522,8 @@ public class Workspace extends SmoothPagedView
|
||||
* @param destCanvas the canvas to draw on
|
||||
* @param padding the horizontal and vertical padding to use when drawing
|
||||
*/
|
||||
private void drawDragView(View v, Canvas destCanvas, int padding) {
|
||||
final Rect clipRect = mTempRect;
|
||||
private static void drawDragView(View v, Canvas destCanvas, int padding) {
|
||||
final Rect clipRect = sTempRect;
|
||||
v.getDrawingRect(clipRect);
|
||||
|
||||
boolean textVisible = false;
|
||||
@@ -2577,7 +2562,7 @@ public class Workspace extends SmoothPagedView
|
||||
* @param expectedPadding padding to add to the drag view. If a different padding was used
|
||||
* its value will be changed
|
||||
*/
|
||||
public Bitmap createDragBitmap(View v, Canvas canvas, AtomicInteger expectedPadding) {
|
||||
public Bitmap createDragBitmap(View v, AtomicInteger expectedPadding) {
|
||||
Bitmap b;
|
||||
|
||||
int padding = expectedPadding.get();
|
||||
@@ -2592,9 +2577,9 @@ public class Workspace extends SmoothPagedView
|
||||
v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
|
||||
}
|
||||
|
||||
canvas.setBitmap(b);
|
||||
drawDragView(v, canvas, padding);
|
||||
canvas.setBitmap(null);
|
||||
mCanvas.setBitmap(b);
|
||||
drawDragView(v, mCanvas, padding);
|
||||
mCanvas.setBitmap(null);
|
||||
|
||||
return b;
|
||||
}
|
||||
@@ -2603,15 +2588,15 @@ public class Workspace extends SmoothPagedView
|
||||
* Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
|
||||
* Responsibility for the bitmap is transferred to the caller.
|
||||
*/
|
||||
private Bitmap createDragOutline(View v, Canvas canvas, int padding) {
|
||||
private Bitmap createDragOutline(View v, int padding) {
|
||||
final int outlineColor = getResources().getColor(R.color.outline_color);
|
||||
final Bitmap b = Bitmap.createBitmap(
|
||||
v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
|
||||
|
||||
canvas.setBitmap(b);
|
||||
drawDragView(v, canvas, padding);
|
||||
mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor);
|
||||
canvas.setBitmap(null);
|
||||
mCanvas.setBitmap(b);
|
||||
drawDragView(v, mCanvas, padding);
|
||||
mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor);
|
||||
mCanvas.setBitmap(null);
|
||||
return b;
|
||||
}
|
||||
|
||||
@@ -2619,11 +2604,11 @@ public class Workspace extends SmoothPagedView
|
||||
* Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
|
||||
* Responsibility for the bitmap is transferred to the caller.
|
||||
*/
|
||||
private Bitmap createDragOutline(Bitmap orig, Canvas canvas, int padding, int w, int h,
|
||||
private Bitmap createDragOutline(Bitmap orig, int padding, int w, int h,
|
||||
boolean clipAlpha) {
|
||||
final int outlineColor = getResources().getColor(R.color.outline_color);
|
||||
final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
|
||||
canvas.setBitmap(b);
|
||||
mCanvas.setBitmap(b);
|
||||
|
||||
Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight());
|
||||
float scaleFactor = Math.min((w - padding) / (float) orig.getWidth(),
|
||||
@@ -2635,10 +2620,10 @@ public class Workspace extends SmoothPagedView
|
||||
// center the image
|
||||
dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);
|
||||
|
||||
canvas.drawBitmap(orig, src, dst, null);
|
||||
mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor,
|
||||
mCanvas.drawBitmap(orig, src, dst, null);
|
||||
mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor,
|
||||
clipAlpha);
|
||||
canvas.setBitmap(null);
|
||||
mCanvas.setBitmap(null);
|
||||
|
||||
return b;
|
||||
}
|
||||
@@ -2656,21 +2641,20 @@ public class Workspace extends SmoothPagedView
|
||||
CellLayout layout = (CellLayout) child.getParent().getParent();
|
||||
layout.prepareChildForDrag(child);
|
||||
|
||||
child.clearFocus();
|
||||
child.setPressed(false);
|
||||
|
||||
final Canvas canvas = new Canvas();
|
||||
|
||||
// The outline is used to visualize where the item will land if dropped
|
||||
mDragOutline = createDragOutline(child, canvas, DRAG_BITMAP_PADDING);
|
||||
beginDragShared(child, this);
|
||||
}
|
||||
|
||||
public void beginDragShared(View child, DragSource source) {
|
||||
child.clearFocus();
|
||||
child.setPressed(false);
|
||||
|
||||
// The outline is used to visualize where the item will land if dropped
|
||||
mDragOutline = createDragOutline(child, DRAG_BITMAP_PADDING);
|
||||
|
||||
mLauncher.onDragStarted(child);
|
||||
// The drag bitmap follows the touch point around on the screen
|
||||
AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING);
|
||||
final Bitmap b = createDragBitmap(child, new Canvas(), padding);
|
||||
final Bitmap b = createDragBitmap(child, padding);
|
||||
|
||||
final int bmpWidth = b.getWidth();
|
||||
final int bmpHeight = b.getHeight();
|
||||
@@ -2684,7 +2668,7 @@ public class Workspace extends SmoothPagedView
|
||||
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
||||
Point dragVisualizeOffset = null;
|
||||
Rect dragRect = null;
|
||||
if (child instanceof BubbleTextView || child instanceof PagedViewIcon) {
|
||||
if (child instanceof BubbleTextView) {
|
||||
int iconSize = grid.iconSizePx;
|
||||
int top = child.getPaddingTop();
|
||||
int left = (bmpWidth - iconSize) / 2;
|
||||
@@ -2703,7 +2687,7 @@ public class Workspace extends SmoothPagedView
|
||||
// Clear the pressed state if necessary
|
||||
if (child instanceof BubbleTextView) {
|
||||
BubbleTextView icon = (BubbleTextView) child;
|
||||
icon.clearPressedOrFocusedBackground();
|
||||
icon.clearPressedBackground();
|
||||
} else if (child instanceof FolderIcon) {
|
||||
// The folder cling isn't flexible enough to be shown in non-default workspace positions
|
||||
// Also if they are dragging it a folder, we assume they don't need to see the cling.
|
||||
@@ -2738,14 +2722,14 @@ public class Workspace extends SmoothPagedView
|
||||
|
||||
// Compose a new drag bitmap that is of the icon size
|
||||
AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING);
|
||||
final Bitmap tmpB = createDragBitmap(child, new Canvas(), padding);
|
||||
final Bitmap tmpB = createDragBitmap(child, padding);
|
||||
Bitmap b = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
|
||||
Paint p = new Paint();
|
||||
p.setFilterBitmap(true);
|
||||
Canvas c = new Canvas(b);
|
||||
c.drawBitmap(tmpB, new Rect(0, 0, tmpB.getWidth(), tmpB.getHeight()),
|
||||
mCanvas.setBitmap(b);
|
||||
mCanvas.drawBitmap(tmpB, new Rect(0, 0, tmpB.getWidth(), tmpB.getHeight()),
|
||||
new Rect(0, 0, iconSize, iconSize), p);
|
||||
c.setBitmap(null);
|
||||
mCanvas.setBitmap(null);
|
||||
|
||||
// Find the child's location on the screen
|
||||
int bmpWidth = tmpB.getWidth();
|
||||
@@ -4020,12 +4004,12 @@ public class Workspace extends SmoothPagedView
|
||||
int height = MeasureSpec.makeMeasureSpec(unScaledSize[1], MeasureSpec.EXACTLY);
|
||||
Bitmap b = Bitmap.createBitmap(unScaledSize[0], unScaledSize[1],
|
||||
Bitmap.Config.ARGB_8888);
|
||||
Canvas c = new Canvas(b);
|
||||
mCanvas.setBitmap(b);
|
||||
|
||||
layout.measure(width, height);
|
||||
layout.layout(0, 0, unScaledSize[0], unScaledSize[1]);
|
||||
layout.draw(c);
|
||||
c.setBitmap(null);
|
||||
layout.draw(mCanvas);
|
||||
mCanvas.setBitmap(null);
|
||||
layout.setVisibility(visibility);
|
||||
return b;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user