am e3a55a9f: Merge "Updating the virtual preloader UX." into ub-now-porkchop
* commit 'e3a55a9f4253e77c770f376c00366774cec2bead': Updating the virtual preloader UX.
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
@@ -152,6 +152,12 @@
|
|||||||
<attr name="workspace" format="reference" />
|
<attr name="workspace" format="reference" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
|
<declare-styleable name="PreloadIconDrawable">
|
||||||
|
<attr name="background" format="reference" />
|
||||||
|
<attr name="ringOutset" format="dimension" />
|
||||||
|
<attr name="indicatorSize" format="dimension" />
|
||||||
|
</declare-styleable>
|
||||||
|
|
||||||
<!-- Only used in the device overlays -->
|
<!-- Only used in the device overlays -->
|
||||||
<declare-styleable name="CustomClingTitleText">
|
<declare-styleable name="CustomClingTitleText">
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|||||||
@@ -161,6 +161,18 @@
|
|||||||
<item name="android:shadowRadius">2.0</item>
|
<item name="android:shadowRadius">2.0</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="PreloadIcon">
|
||||||
|
<item name="background">@drawable/virtual_preload</item>
|
||||||
|
<item name="indicatorSize">4dp</item>
|
||||||
|
<item name="ringOutset">4dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="PreloadIcon.Folder">
|
||||||
|
<item name="background">@drawable/virtual_preload_folder</item>
|
||||||
|
<item name="indicatorSize">4dp</item>
|
||||||
|
<item name="ringOutset">4dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<!-- Overridden in device overlays -->
|
<!-- Overridden in device overlays -->
|
||||||
<style name="CustomClingTitleText">
|
<style name="CustomClingTitleText">
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package com.android.launcher3;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.content.res.Resources.Theme;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
@@ -28,6 +29,7 @@ import android.graphics.Region.Op;
|
|||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.SparseArray;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.ViewConfiguration;
|
import android.view.ViewConfiguration;
|
||||||
@@ -39,6 +41,9 @@ import android.widget.TextView;
|
|||||||
* too aggressive.
|
* too aggressive.
|
||||||
*/
|
*/
|
||||||
public class BubbleTextView extends TextView {
|
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_LARGE_RADIUS = 4.0f;
|
||||||
static final float SHADOW_SMALL_RADIUS = 1.75f;
|
static final float SHADOW_SMALL_RADIUS = 1.75f;
|
||||||
static final float SHADOW_Y_OFFSET = 2.0f;
|
static final float SHADOW_Y_OFFSET = 2.0f;
|
||||||
@@ -128,10 +133,7 @@ public class BubbleTextView extends TextView {
|
|||||||
LauncherAppState app = LauncherAppState.getInstance();
|
LauncherAppState app = LauncherAppState.getInstance();
|
||||||
|
|
||||||
FastBitmapDrawable iconDrawable = Utilities.createIconDrawable(b);
|
FastBitmapDrawable iconDrawable = Utilities.createIconDrawable(b);
|
||||||
if (info.isDisabled) {
|
iconDrawable.setGhostModeEnabled(info.isDisabled);
|
||||||
iconDrawable.setSaturation(0);
|
|
||||||
iconDrawable.setBrightness(20);
|
|
||||||
}
|
|
||||||
|
|
||||||
setCompoundDrawables(null, iconDrawable, null, null);
|
setCompoundDrawables(null, iconDrawable, null, null);
|
||||||
if (setDefaultPadding) {
|
if (setDefaultPadding) {
|
||||||
@@ -315,7 +317,9 @@ public class BubbleTextView extends TextView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setCellLayoutPressedOrFocusedIcon() {
|
void setCellLayoutPressedOrFocusedIcon() {
|
||||||
if (getParent() instanceof ShortcutAndWidgetContainer) {
|
// Disable pressed state when the icon is in preloader state.
|
||||||
|
if ((getParent() instanceof ShortcutAndWidgetContainer) &&
|
||||||
|
!(getCompoundDrawables()[1] instanceof PreloadIconDrawable)){
|
||||||
ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) getParent();
|
ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) getParent();
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
CellLayout layout = (CellLayout) parent.getParent();
|
CellLayout layout = (CellLayout) parent.getParent();
|
||||||
@@ -385,7 +389,13 @@ public class BubbleTextView extends TextView {
|
|||||||
@Override
|
@Override
|
||||||
protected void onAttachedToWindow() {
|
protected void onAttachedToWindow() {
|
||||||
super.onAttachedToWindow();
|
super.onAttachedToWindow();
|
||||||
|
|
||||||
if (mBackground != null) mBackground.setCallback(this);
|
if (mBackground != null) mBackground.setCallback(this);
|
||||||
|
Drawable top = getCompoundDrawables()[1];
|
||||||
|
|
||||||
|
if (top instanceof PreloadIconDrawable) {
|
||||||
|
((PreloadIconDrawable) top).applyTheme(getPreloaderTheme());
|
||||||
|
}
|
||||||
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
|
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,7 +476,7 @@ public class BubbleTextView extends TextView {
|
|||||||
if (top instanceof PreloadIconDrawable) {
|
if (top instanceof PreloadIconDrawable) {
|
||||||
preloadDrawable = (PreloadIconDrawable) top;
|
preloadDrawable = (PreloadIconDrawable) top;
|
||||||
} else {
|
} else {
|
||||||
preloadDrawable = new PreloadIconDrawable(top, getResources());
|
preloadDrawable = new PreloadIconDrawable(top, getPreloaderTheme());
|
||||||
setCompoundDrawables(drawables[0], preloadDrawable, drawables[2], drawables[3]);
|
setCompoundDrawables(drawables[0], preloadDrawable, drawables[2], drawables[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,4 +488,18 @@ public class BubbleTextView extends TextView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Theme getPreloaderTheme() {
|
||||||
|
Object tag = getTag();
|
||||||
|
int style = ((tag != null) && (tag instanceof ShortcutInfo) &&
|
||||||
|
(((ShortcutInfo) tag).container >= 0)) ? R.style.PreloadIcon_Folder
|
||||||
|
: R.style.PreloadIcon;
|
||||||
|
Theme theme = sPreloaderThemes.get(style);
|
||||||
|
if (theme == null) {
|
||||||
|
theme = getResources().newTheme();
|
||||||
|
theme.applyStyle(style, true);
|
||||||
|
sPreloaderThemes.put(style, theme);
|
||||||
|
}
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -566,6 +566,10 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang
|
|||||||
// the drag view about the scaled child view.
|
// the drag view about the scaled child view.
|
||||||
toY += Math.round(toScale * tv.getPaddingTop());
|
toY += Math.round(toScale * tv.getPaddingTop());
|
||||||
toY -= dragView.getMeasuredHeight() * (1 - toScale) / 2;
|
toY -= dragView.getMeasuredHeight() * (1 - toScale) / 2;
|
||||||
|
if (dragView.getDragVisualizeOffset() != null) {
|
||||||
|
toY -= Math.round(toScale * dragView.getDragVisualizeOffset().y);
|
||||||
|
}
|
||||||
|
|
||||||
toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
|
toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
|
||||||
} else if (child instanceof FolderIcon) {
|
} else if (child instanceof FolderIcon) {
|
||||||
// Account for holographic blur padding on the drag view
|
// Account for holographic blur padding on the drag view
|
||||||
|
|||||||
@@ -28,15 +28,17 @@ import android.graphics.drawable.Drawable;
|
|||||||
|
|
||||||
class FastBitmapDrawable extends Drawable {
|
class FastBitmapDrawable extends Drawable {
|
||||||
|
|
||||||
private static final ColorMatrix sTempSaturationMatrix = new ColorMatrix();
|
private static ColorMatrix sGhostModeMatrix;
|
||||||
private static final ColorMatrix sTempBrightnessMatrix = new ColorMatrix();
|
private static final ColorMatrix sTempMatrix = new ColorMatrix();
|
||||||
|
|
||||||
|
private static final int GHOST_MODE_MIN_COLOR_RANGE = 130;
|
||||||
|
|
||||||
private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
|
private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
|
||||||
private Bitmap mBitmap;
|
private Bitmap mBitmap;
|
||||||
private int mAlpha;
|
private int mAlpha;
|
||||||
|
|
||||||
private float mSatutation = 1;
|
|
||||||
private int mBrightness = 0;
|
private int mBrightness = 0;
|
||||||
|
private boolean mGhostModeEnabled = false;
|
||||||
|
|
||||||
FastBitmapDrawable(Bitmap b) {
|
FastBitmapDrawable(Bitmap b) {
|
||||||
mAlpha = 255;
|
mAlpha = 255;
|
||||||
@@ -101,13 +103,19 @@ class FastBitmapDrawable extends Drawable {
|
|||||||
return mBitmap;
|
return mBitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getSaturation() {
|
/**
|
||||||
return mSatutation;
|
* When enabled, the icon is grayed out and the contrast is increased to give it a 'ghost'
|
||||||
|
* appearance.
|
||||||
|
*/
|
||||||
|
public void setGhostModeEnabled(boolean enabled) {
|
||||||
|
if (mGhostModeEnabled != enabled) {
|
||||||
|
mGhostModeEnabled = enabled;
|
||||||
|
updateFilter();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSaturation(float saturation) {
|
public boolean isGhostModeEnabled() {
|
||||||
mSatutation = saturation;
|
return mGhostModeEnabled;
|
||||||
updateFilter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getBrightness() {
|
public int getBrightness() {
|
||||||
@@ -115,36 +123,58 @@ class FastBitmapDrawable extends Drawable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addBrightness(int amount) {
|
public void addBrightness(int amount) {
|
||||||
mBrightness += amount;
|
setBrightness(mBrightness + amount);
|
||||||
updateFilter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBrightness(int brightness) {
|
public void setBrightness(int brightness) {
|
||||||
mBrightness = brightness;
|
if (mBrightness != brightness) {
|
||||||
updateFilter();
|
mBrightness = brightness;
|
||||||
|
updateFilter();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateFilter() {
|
private void updateFilter() {
|
||||||
if (mSatutation != 1 || mBrightness != 0) {
|
if (mGhostModeEnabled) {
|
||||||
sTempSaturationMatrix.setSaturation(mSatutation);
|
if (sGhostModeMatrix == null) {
|
||||||
|
sGhostModeMatrix = new ColorMatrix();
|
||||||
|
sGhostModeMatrix.setSaturation(0);
|
||||||
|
|
||||||
if (mBrightness != 0) {
|
// For ghost mode, set the color range to [GHOST_MODE_MIN_COLOR_RANGE, 255]
|
||||||
// Brightness: C-new = C-old*(1-amount) + amount
|
float range = (255 - GHOST_MODE_MIN_COLOR_RANGE) / 255.0f;
|
||||||
float scale = 1 - mBrightness / 255.0f;
|
sTempMatrix.set(new float[] {
|
||||||
sTempBrightnessMatrix.setScale(scale, scale, scale, 1);
|
range, 0, 0, 0, GHOST_MODE_MIN_COLOR_RANGE,
|
||||||
float[] array = sTempBrightnessMatrix.getArray();
|
0, range, 0, 0, GHOST_MODE_MIN_COLOR_RANGE,
|
||||||
|
0, 0, range, 0, GHOST_MODE_MIN_COLOR_RANGE,
|
||||||
// Add the amount to RGB components of the matrix, as per the above formula.
|
0, 0, 0, 1, 0 });
|
||||||
// Fifth elements in the array correspond to the constant being added to
|
sGhostModeMatrix.preConcat(sTempMatrix);
|
||||||
// red, blue, green, and alpha channel respectively.
|
|
||||||
array[4] = mBrightness;
|
|
||||||
array[9] = mBrightness;
|
|
||||||
array[14] = mBrightness;
|
|
||||||
sTempSaturationMatrix.preConcat(sTempBrightnessMatrix);
|
|
||||||
}
|
}
|
||||||
mPaint.setColorFilter(new ColorMatrixColorFilter(sTempSaturationMatrix));
|
|
||||||
|
if (mBrightness == 0) {
|
||||||
|
mPaint.setColorFilter(new ColorMatrixColorFilter(sGhostModeMatrix));
|
||||||
|
} else {
|
||||||
|
setBrightnessMatrix(sTempMatrix, mBrightness);
|
||||||
|
sTempMatrix.postConcat(sGhostModeMatrix);
|
||||||
|
mPaint.setColorFilter(new ColorMatrixColorFilter(sTempMatrix));
|
||||||
|
}
|
||||||
|
} else if (mBrightness != 0) {
|
||||||
|
setBrightnessMatrix(sTempMatrix, mBrightness);
|
||||||
|
mPaint.setColorFilter(new ColorMatrixColorFilter(sTempMatrix));
|
||||||
} else {
|
} else {
|
||||||
mPaint.setColorFilter(null);
|
mPaint.setColorFilter(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void setBrightnessMatrix(ColorMatrix matrix, int brightness) {
|
||||||
|
// Brightness: C-new = C-old*(1-amount) + amount
|
||||||
|
float scale = 1 - brightness / 255.0f;
|
||||||
|
matrix.setScale(scale, scale, scale, 1);
|
||||||
|
float[] array = matrix.getArray();
|
||||||
|
|
||||||
|
// Add the amount to RGB components of the matrix, as per the above formula.
|
||||||
|
// Fifth elements in the array correspond to the constant being added to
|
||||||
|
// red, blue, green, and alpha channel respectively.
|
||||||
|
array[4] = brightness;
|
||||||
|
array[9] = brightness;
|
||||||
|
array[14] = brightness;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1182,6 +1182,18 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
|
|||||||
if (mIsExternalDrag) {
|
if (mIsExternalDrag) {
|
||||||
si.cellX = mEmptyCell[0];
|
si.cellX = mEmptyCell[0];
|
||||||
si.cellY = mEmptyCell[1];
|
si.cellY = mEmptyCell[1];
|
||||||
|
|
||||||
|
// Actually move the item in the database if it was an external drag. Call this
|
||||||
|
// before creating the view, so that ShortcutInfo is updated appropriately.
|
||||||
|
LauncherModel.addOrMoveItemInDatabase(
|
||||||
|
mLauncher, si, mInfo.id, 0, si.cellX, si.cellY);
|
||||||
|
|
||||||
|
// We only need to update the locations if it doesn't get handled in #onDropCompleted.
|
||||||
|
if (d.dragSource != this) {
|
||||||
|
updateItemLocationsInDatabaseBatch();
|
||||||
|
}
|
||||||
|
mIsExternalDrag = false;
|
||||||
|
|
||||||
currentDragView = createAndAddShortcut(si);
|
currentDragView = createAndAddShortcut(si);
|
||||||
} else {
|
} else {
|
||||||
currentDragView = mCurrentDragView;
|
currentDragView = mCurrentDragView;
|
||||||
@@ -1209,18 +1221,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
|
|||||||
mItemsInvalidated = true;
|
mItemsInvalidated = true;
|
||||||
setupContentDimensions(getItemCount());
|
setupContentDimensions(getItemCount());
|
||||||
|
|
||||||
// Actually move the item in the database if it was an external drag.
|
|
||||||
if (mIsExternalDrag) {
|
|
||||||
LauncherModel.addOrMoveItemInDatabase(
|
|
||||||
mLauncher, si, mInfo.id, 0, si.cellX, si.cellY);
|
|
||||||
|
|
||||||
// We only need to update the locations if it doesn't get handled in #onDropCompleted.
|
|
||||||
if (d.dragSource != this) {
|
|
||||||
updateItemLocationsInDatabaseBatch();
|
|
||||||
}
|
|
||||||
mIsExternalDrag = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temporarily suppress the listener, as we did all the work already here.
|
// Temporarily suppress the listener, as we did all the work already here.
|
||||||
mSuppressOnAdd = true;
|
mSuppressOnAdd = true;
|
||||||
mInfo.add(si);
|
mInfo.add(si);
|
||||||
|
|||||||
@@ -380,7 +380,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
|||||||
float scaleRelativeToDragLayer, Runnable postAnimationRunnable) {
|
float scaleRelativeToDragLayer, Runnable postAnimationRunnable) {
|
||||||
|
|
||||||
// These correspond two the drawable and view that the icon was dropped _onto_
|
// These correspond two the drawable and view that the icon was dropped _onto_
|
||||||
Drawable animateDrawable = ((TextView) destView).getCompoundDrawables()[1];
|
Drawable animateDrawable = getTopDrawable((TextView) destView);
|
||||||
computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
|
computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
|
||||||
destView.getMeasuredWidth());
|
destView.getMeasuredWidth());
|
||||||
|
|
||||||
@@ -394,7 +394,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void performDestroyAnimation(final View finalView, Runnable onCompleteRunnable) {
|
public void performDestroyAnimation(final View finalView, Runnable onCompleteRunnable) {
|
||||||
Drawable animateDrawable = ((TextView) finalView).getCompoundDrawables()[1];
|
Drawable animateDrawable = getTopDrawable((TextView) finalView);
|
||||||
computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
|
computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
|
||||||
finalView.getMeasuredWidth());
|
finalView.getMeasuredWidth());
|
||||||
|
|
||||||
|
|||||||
@@ -1,96 +1,143 @@
|
|||||||
package com.android.launcher3;
|
package com.android.launcher3;
|
||||||
|
|
||||||
import android.animation.ObjectAnimator;
|
import android.animation.ObjectAnimator;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources.Theme;
|
||||||
import android.graphics.Bitmap;
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.graphics.ColorFilter;
|
import android.graphics.ColorFilter;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Path;
|
|
||||||
import android.graphics.PixelFormat;
|
import android.graphics.PixelFormat;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
|
||||||
class PreloadIconDrawable extends Drawable {
|
class PreloadIconDrawable extends Drawable {
|
||||||
|
|
||||||
private static final float ANIMATION_PROGRESS_STOPPED = -1.0f;
|
private static final float ANIMATION_PROGRESS_STOPPED = -1.0f;
|
||||||
private static final float ANIMATION_PROGRESS_STARTED = 0f;
|
private static final float ANIMATION_PROGRESS_STARTED = 0f;
|
||||||
private static final float ANIMATION_PROGRESS_COMPLETED = 1.0f;
|
private static final float ANIMATION_PROGRESS_COMPLETED = 1.0f;
|
||||||
|
|
||||||
private static final float ICON_SCALE_FACTOR = 0.6f;
|
private static final float MIN_SATUNATION = 0.2f;
|
||||||
|
private static final float MIN_LIGHTNESS = 0.6f;
|
||||||
|
|
||||||
private static Bitmap sProgressBg, sProgressFill;
|
private static final float ICON_SCALE_FACTOR = 0.5f;
|
||||||
|
private static final int DEFAULT_COLOR = 0xFF009688;
|
||||||
|
|
||||||
private final Rect mCanvasClipRect = new Rect();
|
private static final Rect sTempRect = new Rect();
|
||||||
private final RectF mRect = new RectF();
|
|
||||||
private final Path mProgressPath = new Path();
|
|
||||||
private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
|
|
||||||
|
|
||||||
|
private final RectF mIndicatorRect = new RectF();
|
||||||
|
private boolean mIndicatorRectDirty;
|
||||||
|
|
||||||
|
private final Paint mPaint;
|
||||||
final Drawable mIcon;
|
final Drawable mIcon;
|
||||||
|
|
||||||
|
private Drawable mBgDrawable;
|
||||||
|
private int mRingOutset;
|
||||||
|
|
||||||
|
private int mIndicatorColor = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates the progress of the preloader [0-100]. If it goes above 100, only the icon
|
* Indicates the progress of the preloader [0-100]. If it goes above 100, only the icon
|
||||||
* is shown with no progress bar.
|
* is shown with no progress bar.
|
||||||
*/
|
*/
|
||||||
private int mProgress = 0;
|
private int mProgress = 0;
|
||||||
private boolean mPathChanged;
|
|
||||||
|
|
||||||
private float mAnimationProgress = ANIMATION_PROGRESS_STOPPED;
|
private float mAnimationProgress = ANIMATION_PROGRESS_STOPPED;
|
||||||
private ObjectAnimator mAnimator;
|
private ObjectAnimator mAnimator;
|
||||||
|
|
||||||
public PreloadIconDrawable(Drawable icon, Resources res) {
|
public PreloadIconDrawable(Drawable icon, Theme theme) {
|
||||||
mIcon = icon;
|
mIcon = icon;
|
||||||
|
|
||||||
setBounds(icon.getBounds());
|
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
mPathChanged = false;
|
mPaint.setStyle(Paint.Style.STROKE);
|
||||||
|
mPaint.setStrokeCap(Paint.Cap.ROUND);
|
||||||
|
|
||||||
if (sProgressBg == null) {
|
setBounds(icon.getBounds());
|
||||||
sProgressBg = BitmapFactory.decodeResource(res, R.drawable.bg_preloader);
|
applyTheme(theme);
|
||||||
}
|
onLevelChange(0);
|
||||||
if (sProgressFill == null) {
|
}
|
||||||
sProgressFill = BitmapFactory.decodeResource(res, R.drawable.bg_preloader_progress);
|
|
||||||
|
@Override
|
||||||
|
public void applyTheme(Theme t) {
|
||||||
|
TypedArray ta = t.obtainStyledAttributes(R.styleable.PreloadIconDrawable);
|
||||||
|
mBgDrawable = ta.getDrawable(R.styleable.PreloadIconDrawable_background);
|
||||||
|
mBgDrawable.setFilterBitmap(true);
|
||||||
|
mPaint.setStrokeWidth(ta.getDimension(R.styleable.PreloadIconDrawable_indicatorSize, 0));
|
||||||
|
mRingOutset = ta.getDimensionPixelSize(R.styleable.PreloadIconDrawable_ringOutset, 0);
|
||||||
|
ta.recycle();
|
||||||
|
onBoundsChange(getBounds());
|
||||||
|
invalidateSelf();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onBoundsChange(Rect bounds) {
|
||||||
|
mIcon.setBounds(bounds);
|
||||||
|
if (mBgDrawable != null) {
|
||||||
|
sTempRect.set(bounds);
|
||||||
|
sTempRect.inset(-mRingOutset, -mRingOutset);
|
||||||
|
mBgDrawable.setBounds(sTempRect);
|
||||||
}
|
}
|
||||||
|
mIndicatorRectDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOutset() {
|
||||||
|
return mRingOutset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the indicator is same as the content region of the {@link #mBgDrawable} minus
|
||||||
|
* half the stroke size to accommodate the indicator.
|
||||||
|
*/
|
||||||
|
private void initIndicatorRect() {
|
||||||
|
Drawable d = mBgDrawable;
|
||||||
|
Rect bounds = d.getBounds();
|
||||||
|
|
||||||
|
d.getPadding(sTempRect);
|
||||||
|
// Amount by which padding has to be scaled
|
||||||
|
float paddingScaleX = ((float) bounds.width()) / d.getIntrinsicWidth();
|
||||||
|
float paddingScaleY = ((float) bounds.height()) / d.getIntrinsicHeight();
|
||||||
|
mIndicatorRect.set(
|
||||||
|
bounds.left + sTempRect.left * paddingScaleX,
|
||||||
|
bounds.top + sTempRect.top * paddingScaleY,
|
||||||
|
bounds.right - sTempRect.right * paddingScaleX,
|
||||||
|
bounds.bottom - sTempRect.bottom * paddingScaleY);
|
||||||
|
|
||||||
|
float inset = mPaint.getStrokeWidth() / 2;
|
||||||
|
mIndicatorRect.inset(inset, inset);
|
||||||
|
mIndicatorRectDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(Canvas canvas) {
|
public void draw(Canvas canvas) {
|
||||||
final Rect r = getBounds();
|
final Rect r = new Rect(getBounds());
|
||||||
if (canvas.getClipBounds(mCanvasClipRect) && !Rect.intersects(mCanvasClipRect, r)) {
|
if (canvas.getClipBounds(sTempRect) && !Rect.intersects(sTempRect, r)) {
|
||||||
// The draw region has been clipped.
|
// The draw region has been clipped.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (mIndicatorRectDirty) {
|
||||||
|
initIndicatorRect();
|
||||||
|
}
|
||||||
final float iconScale;
|
final float iconScale;
|
||||||
|
|
||||||
if ((mAnimationProgress >= ANIMATION_PROGRESS_STARTED)
|
if ((mAnimationProgress >= ANIMATION_PROGRESS_STARTED)
|
||||||
&& (mAnimationProgress < ANIMATION_PROGRESS_COMPLETED)) {
|
&& (mAnimationProgress < ANIMATION_PROGRESS_COMPLETED)) {
|
||||||
mPaint.setAlpha((int) ((1 - mAnimationProgress) * 255));
|
mPaint.setAlpha((int) ((1 - mAnimationProgress) * 255));
|
||||||
canvas.drawBitmap(sProgressBg, null, r, mPaint);
|
mBgDrawable.setAlpha(mPaint.getAlpha());
|
||||||
canvas.drawBitmap(sProgressFill, null, r, mPaint);
|
mBgDrawable.draw(canvas);
|
||||||
iconScale = ICON_SCALE_FACTOR + (1 - ICON_SCALE_FACTOR) * mAnimationProgress;
|
canvas.drawOval(mIndicatorRect, mPaint);
|
||||||
|
|
||||||
|
iconScale = ICON_SCALE_FACTOR + (1 - ICON_SCALE_FACTOR) * mAnimationProgress;
|
||||||
} else if (mAnimationProgress == ANIMATION_PROGRESS_STOPPED) {
|
} else if (mAnimationProgress == ANIMATION_PROGRESS_STOPPED) {
|
||||||
mPaint.setAlpha(255);
|
mPaint.setAlpha(255);
|
||||||
iconScale = ICON_SCALE_FACTOR;
|
iconScale = ICON_SCALE_FACTOR;
|
||||||
canvas.drawBitmap(sProgressBg, null, r, mPaint);
|
mBgDrawable.setAlpha(255);
|
||||||
|
mBgDrawable.draw(canvas);
|
||||||
|
|
||||||
if (mProgress >= 100) {
|
if (mProgress >= 100) {
|
||||||
canvas.drawBitmap(sProgressFill, null, r, mPaint);
|
canvas.drawOval(mIndicatorRect, mPaint);
|
||||||
} else if (mProgress > 0) {
|
} else if (mProgress > 0) {
|
||||||
if (mPathChanged) {
|
canvas.drawArc(mIndicatorRect, -90, mProgress * 3.6f, false, mPaint);
|
||||||
mProgressPath.reset();
|
|
||||||
mProgressPath.moveTo(r.exactCenterX(), r.centerY());
|
|
||||||
|
|
||||||
mRect.set(r);
|
|
||||||
mProgressPath.arcTo(mRect, -90, mProgress * 3.6f);
|
|
||||||
mProgressPath.close();
|
|
||||||
mPathChanged = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas.save();
|
|
||||||
canvas.clipPath(mProgressPath);
|
|
||||||
canvas.drawBitmap(sProgressFill, null, r, mPaint);
|
|
||||||
canvas.restore();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
iconScale = 1;
|
iconScale = 1;
|
||||||
@@ -102,12 +149,6 @@ class PreloadIconDrawable extends Drawable {
|
|||||||
canvas.restore();
|
canvas.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onBoundsChange(Rect bounds) {
|
|
||||||
mIcon.setBounds(bounds);
|
|
||||||
mPathChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getOpacity() {
|
public int getOpacity() {
|
||||||
return PixelFormat.TRANSLUCENT;
|
return PixelFormat.TRANSLUCENT;
|
||||||
@@ -126,7 +167,6 @@ class PreloadIconDrawable extends Drawable {
|
|||||||
@Override
|
@Override
|
||||||
protected boolean onLevelChange(int level) {
|
protected boolean onLevelChange(int level) {
|
||||||
mProgress = level;
|
mProgress = level;
|
||||||
mPathChanged = true;
|
|
||||||
|
|
||||||
// Stop Animation
|
// Stop Animation
|
||||||
if (mAnimator != null) {
|
if (mAnimator != null) {
|
||||||
@@ -134,6 +174,14 @@ class PreloadIconDrawable extends Drawable {
|
|||||||
mAnimator = null;
|
mAnimator = null;
|
||||||
}
|
}
|
||||||
mAnimationProgress = ANIMATION_PROGRESS_STOPPED;
|
mAnimationProgress = ANIMATION_PROGRESS_STOPPED;
|
||||||
|
if (level > 0) {
|
||||||
|
// Set the paint color only when the level changes, so that the dominant color
|
||||||
|
// is only calculated when needed.
|
||||||
|
mPaint.setColor(getIndicatorColor());
|
||||||
|
}
|
||||||
|
if (mIcon instanceof FastBitmapDrawable) {
|
||||||
|
((FastBitmapDrawable) mIcon).setGhostModeEnabled(level <= 0);
|
||||||
|
}
|
||||||
|
|
||||||
invalidateSelf();
|
invalidateSelf();
|
||||||
return true;
|
return true;
|
||||||
@@ -165,4 +213,37 @@ class PreloadIconDrawable extends Drawable {
|
|||||||
public float getAnimationProgress() {
|
public float getAnimationProgress() {
|
||||||
return mAnimationProgress;
|
return mAnimationProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIntrinsicHeight() {
|
||||||
|
return mIcon.getIntrinsicHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIntrinsicWidth() {
|
||||||
|
return mIcon.getIntrinsicWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getIndicatorColor() {
|
||||||
|
if (mIndicatorColor != 0) {
|
||||||
|
return mIndicatorColor;
|
||||||
|
}
|
||||||
|
if (!(mIcon instanceof FastBitmapDrawable)) {
|
||||||
|
mIndicatorColor = DEFAULT_COLOR;
|
||||||
|
return mIndicatorColor;
|
||||||
|
}
|
||||||
|
mIndicatorColor = Utilities.findDominantColorByHue(
|
||||||
|
((FastBitmapDrawable) mIcon).getBitmap(), 20);
|
||||||
|
|
||||||
|
// Make sure that the dominant color has enough saturation to be visible properly.
|
||||||
|
float[] hsv = new float[3];
|
||||||
|
Color.colorToHSV(mIndicatorColor, hsv);
|
||||||
|
if (hsv[1] < MIN_SATUNATION) {
|
||||||
|
mIndicatorColor = DEFAULT_COLOR;
|
||||||
|
return mIndicatorColor;
|
||||||
|
}
|
||||||
|
hsv[2] = Math.max(MIN_LIGHTNESS, hsv[2]);
|
||||||
|
mIndicatorColor = Color.HSVToColor(hsv);
|
||||||
|
return mIndicatorColor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import android.content.pm.ResolveInfo;
|
|||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.PaintFlagsDrawFilter;
|
import android.graphics.PaintFlagsDrawFilter;
|
||||||
@@ -39,6 +40,7 @@ import android.graphics.drawable.PaintDrawable;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.SparseArray;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
@@ -393,4 +395,83 @@ public final class Utilities {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This picks a dominant color, looking for high-saturation, high-value, repeated hues.
|
||||||
|
* @param bitmap The bitmap to scan
|
||||||
|
* @param samples The approximate max number of samples to use.
|
||||||
|
*/
|
||||||
|
static int findDominantColorByHue(Bitmap bitmap, int samples) {
|
||||||
|
final int height = bitmap.getHeight();
|
||||||
|
final int width = bitmap.getWidth();
|
||||||
|
int sampleStride = (int) Math.sqrt((height * width) / samples);
|
||||||
|
if (sampleStride < 1) {
|
||||||
|
sampleStride = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is an out-param, for getting the hsv values for an rgb
|
||||||
|
float[] hsv = new float[3];
|
||||||
|
|
||||||
|
// First get the best hue, by creating a histogram over 360 hue buckets,
|
||||||
|
// where each pixel contributes a score weighted by saturation, value, and alpha.
|
||||||
|
float[] hueScoreHistogram = new float[360];
|
||||||
|
float highScore = -1;
|
||||||
|
int bestHue = -1;
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y += sampleStride) {
|
||||||
|
for (int x = 0; x < width; x += sampleStride) {
|
||||||
|
int argb = bitmap.getPixel(x, y);
|
||||||
|
int alpha = 0xFF & (argb >> 24);
|
||||||
|
if (alpha < 0x80) {
|
||||||
|
// Drop mostly-transparent pixels.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Remove the alpha channel.
|
||||||
|
int rgb = argb | 0xFF000000;
|
||||||
|
Color.colorToHSV(rgb, hsv);
|
||||||
|
// Bucket colors by the 360 integer hues.
|
||||||
|
int hue = (int) hsv[0];
|
||||||
|
if (hue < 0 || hue >= hueScoreHistogram.length) {
|
||||||
|
// Defensively avoid array bounds violations.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
float score = hsv[1] * hsv[2];
|
||||||
|
hueScoreHistogram[hue] += score;
|
||||||
|
if (hueScoreHistogram[hue] > highScore) {
|
||||||
|
highScore = hueScoreHistogram[hue];
|
||||||
|
bestHue = hue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SparseArray<Float> rgbScores = new SparseArray<Float>();
|
||||||
|
int bestColor = 0xff000000;
|
||||||
|
highScore = -1;
|
||||||
|
// Go back over the RGB colors that match the winning hue,
|
||||||
|
// creating a histogram of weighted s*v scores, for up to 100*100 [s,v] buckets.
|
||||||
|
// The highest-scoring RGB color wins.
|
||||||
|
for (int y = 0; y < height; y += sampleStride) {
|
||||||
|
for (int x = 0; x < width; x += sampleStride) {
|
||||||
|
int rgb = bitmap.getPixel(x, y) | 0xff000000;
|
||||||
|
Color.colorToHSV(rgb, hsv);
|
||||||
|
int hue = (int) hsv[0];
|
||||||
|
if (hue == bestHue) {
|
||||||
|
float s = hsv[1];
|
||||||
|
float v = hsv[2];
|
||||||
|
int bucket = (int) (s * 100) + (int) (v * 10000);
|
||||||
|
// Score by cumulative saturation * value.
|
||||||
|
float score = s * v;
|
||||||
|
Float oldTotal = rgbScores.get(bucket);
|
||||||
|
float newTotal = oldTotal == null ? score : oldTotal + score;
|
||||||
|
rgbScores.put(bucket, newTotal);
|
||||||
|
if (newTotal > highScore) {
|
||||||
|
highScore = newTotal;
|
||||||
|
// All the colors in the winning bucket are very similar. Last in wins.
|
||||||
|
bestColor = rgb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestColor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ import java.util.HashSet;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The workspace is a wide area with a wallpaper and a finite number of pages.
|
* The workspace is a wide area with a wallpaper and a finite number of pages.
|
||||||
@@ -1986,6 +1987,12 @@ public class Workspace extends SmoothPagedView
|
|||||||
d.copyBounds(bounds);
|
d.copyBounds(bounds);
|
||||||
if (bounds.width() == 0 || bounds.height() == 0) {
|
if (bounds.width() == 0 || bounds.height() == 0) {
|
||||||
bounds.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
|
bounds.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
|
||||||
|
} else {
|
||||||
|
bounds.offsetTo(0, 0);
|
||||||
|
}
|
||||||
|
if (d instanceof PreloadIconDrawable) {
|
||||||
|
int inset = -((PreloadIconDrawable) d).getOutset();
|
||||||
|
bounds.inset(inset, inset);
|
||||||
}
|
}
|
||||||
return bounds;
|
return bounds;
|
||||||
}
|
}
|
||||||
@@ -2013,7 +2020,7 @@ public class Workspace extends SmoothPagedView
|
|||||||
Bitmap b = Bitmap.createBitmap(bmpWidth, bmpHeight,
|
Bitmap b = Bitmap.createBitmap(bmpWidth, bmpHeight,
|
||||||
Bitmap.Config.ARGB_8888);
|
Bitmap.Config.ARGB_8888);
|
||||||
Canvas c = new Canvas(b);
|
Canvas c = new Canvas(b);
|
||||||
drawDragView(v, c, 0, true);
|
drawDragView(v, c, 0);
|
||||||
c.setBitmap(null);
|
c.setBitmap(null);
|
||||||
|
|
||||||
// The outline is used to visualize where the item will land if dropped
|
// The outline is used to visualize where the item will land if dropped
|
||||||
@@ -2528,18 +2535,18 @@ public class Workspace extends SmoothPagedView
|
|||||||
* @param destCanvas the canvas to draw on
|
* @param destCanvas the canvas to draw on
|
||||||
* @param padding the horizontal and vertical padding to use when drawing
|
* @param padding the horizontal and vertical padding to use when drawing
|
||||||
*/
|
*/
|
||||||
private void drawDragView(View v, Canvas destCanvas, int padding, boolean pruneToDrawable) {
|
private void drawDragView(View v, Canvas destCanvas, int padding) {
|
||||||
final Rect clipRect = mTempRect;
|
final Rect clipRect = mTempRect;
|
||||||
v.getDrawingRect(clipRect);
|
v.getDrawingRect(clipRect);
|
||||||
|
|
||||||
boolean textVisible = false;
|
boolean textVisible = false;
|
||||||
|
|
||||||
destCanvas.save();
|
destCanvas.save();
|
||||||
if (v instanceof TextView && pruneToDrawable) {
|
if (v instanceof TextView) {
|
||||||
Drawable d = ((TextView) v).getCompoundDrawables()[1];
|
Drawable d = ((TextView) v).getCompoundDrawables()[1];
|
||||||
Rect bounds = getDrawableBounds(d);
|
Rect bounds = getDrawableBounds(d);
|
||||||
clipRect.set(0, 0, bounds.width() + padding, bounds.height() + padding);
|
clipRect.set(0, 0, bounds.width() + padding, bounds.height() + padding);
|
||||||
destCanvas.translate(padding / 2, padding / 2);
|
destCanvas.translate(padding / 2 - bounds.left, padding / 2 - bounds.top);
|
||||||
d.draw(destCanvas);
|
d.draw(destCanvas);
|
||||||
} else {
|
} else {
|
||||||
if (v instanceof FolderIcon) {
|
if (v instanceof FolderIcon) {
|
||||||
@@ -2549,14 +2556,6 @@ public class Workspace extends SmoothPagedView
|
|||||||
((FolderIcon) v).setTextVisible(false);
|
((FolderIcon) v).setTextVisible(false);
|
||||||
textVisible = true;
|
textVisible = true;
|
||||||
}
|
}
|
||||||
} else if (v instanceof BubbleTextView) {
|
|
||||||
final BubbleTextView tv = (BubbleTextView) v;
|
|
||||||
clipRect.bottom = tv.getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V +
|
|
||||||
tv.getLayout().getLineTop(0);
|
|
||||||
} else if (v instanceof TextView) {
|
|
||||||
final TextView tv = (TextView) v;
|
|
||||||
clipRect.bottom = tv.getExtendedPaddingTop() - tv.getCompoundDrawablePadding() +
|
|
||||||
tv.getLayout().getLineTop(0);
|
|
||||||
}
|
}
|
||||||
destCanvas.translate(-v.getScrollX() + padding / 2, -v.getScrollY() + padding / 2);
|
destCanvas.translate(-v.getScrollX() + padding / 2, -v.getScrollY() + padding / 2);
|
||||||
destCanvas.clipRect(clipRect, Op.REPLACE);
|
destCanvas.clipRect(clipRect, Op.REPLACE);
|
||||||
@@ -2573,22 +2572,26 @@ public class Workspace extends SmoothPagedView
|
|||||||
/**
|
/**
|
||||||
* Returns a new bitmap to show when the given View is being dragged around.
|
* Returns a new bitmap to show when the given View is being dragged around.
|
||||||
* Responsibility for the bitmap is transferred to the caller.
|
* Responsibility for the bitmap is transferred to the caller.
|
||||||
|
* @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, int padding) {
|
public Bitmap createDragBitmap(View v, Canvas canvas, AtomicInteger expectedPadding) {
|
||||||
Bitmap b;
|
Bitmap b;
|
||||||
|
|
||||||
|
int padding = expectedPadding.get();
|
||||||
if (v instanceof TextView) {
|
if (v instanceof TextView) {
|
||||||
Drawable d = ((TextView) v).getCompoundDrawables()[1];
|
Drawable d = ((TextView) v).getCompoundDrawables()[1];
|
||||||
Rect bounds = getDrawableBounds(d);
|
Rect bounds = getDrawableBounds(d);
|
||||||
b = Bitmap.createBitmap(bounds.width() + padding,
|
b = Bitmap.createBitmap(bounds.width() + padding,
|
||||||
bounds.height() + padding, Bitmap.Config.ARGB_8888);
|
bounds.height() + padding, Bitmap.Config.ARGB_8888);
|
||||||
|
expectedPadding.set(padding - bounds.left - bounds.top);
|
||||||
} else {
|
} else {
|
||||||
b = Bitmap.createBitmap(
|
b = Bitmap.createBitmap(
|
||||||
v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
|
v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.setBitmap(b);
|
canvas.setBitmap(b);
|
||||||
drawDragView(v, canvas, padding, true);
|
drawDragView(v, canvas, padding);
|
||||||
canvas.setBitmap(null);
|
canvas.setBitmap(null);
|
||||||
|
|
||||||
return b;
|
return b;
|
||||||
@@ -2604,7 +2607,7 @@ public class Workspace extends SmoothPagedView
|
|||||||
v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
|
v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
|
||||||
|
|
||||||
canvas.setBitmap(b);
|
canvas.setBitmap(b);
|
||||||
drawDragView(v, canvas, padding, true);
|
drawDragView(v, canvas, padding);
|
||||||
mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor);
|
mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor);
|
||||||
canvas.setBitmap(null);
|
canvas.setBitmap(null);
|
||||||
return b;
|
return b;
|
||||||
@@ -2664,7 +2667,8 @@ public class Workspace extends SmoothPagedView
|
|||||||
public void beginDragShared(View child, DragSource source) {
|
public void beginDragShared(View child, DragSource source) {
|
||||||
mLauncher.onDragStarted(child);
|
mLauncher.onDragStarted(child);
|
||||||
// The drag bitmap follows the touch point around on the screen
|
// The drag bitmap follows the touch point around on the screen
|
||||||
final Bitmap b = createDragBitmap(child, new Canvas(), DRAG_BITMAP_PADDING);
|
AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING);
|
||||||
|
final Bitmap b = createDragBitmap(child, new Canvas(), padding);
|
||||||
|
|
||||||
final int bmpWidth = b.getWidth();
|
final int bmpWidth = b.getWidth();
|
||||||
final int bmpHeight = b.getHeight();
|
final int bmpHeight = b.getHeight();
|
||||||
@@ -2672,7 +2676,7 @@ public class Workspace extends SmoothPagedView
|
|||||||
float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY);
|
float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY);
|
||||||
int dragLayerX = Math.round(mTempXY[0] - (bmpWidth - scale * child.getWidth()) / 2);
|
int dragLayerX = Math.round(mTempXY[0] - (bmpWidth - scale * child.getWidth()) / 2);
|
||||||
int dragLayerY = Math.round(mTempXY[1] - (bmpHeight - scale * bmpHeight) / 2
|
int dragLayerY = Math.round(mTempXY[1] - (bmpHeight - scale * bmpHeight) / 2
|
||||||
- DRAG_BITMAP_PADDING / 2);
|
- padding.get() / 2);
|
||||||
|
|
||||||
LauncherAppState app = LauncherAppState.getInstance();
|
LauncherAppState app = LauncherAppState.getInstance();
|
||||||
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
||||||
@@ -2687,7 +2691,7 @@ public class Workspace extends SmoothPagedView
|
|||||||
dragLayerY += top;
|
dragLayerY += top;
|
||||||
// Note: The drag region is used to calculate drag layer offsets, but the
|
// Note: The drag region is used to calculate drag layer offsets, but the
|
||||||
// dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
|
// dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
|
||||||
dragVisualizeOffset = new Point(-DRAG_BITMAP_PADDING / 2, DRAG_BITMAP_PADDING / 2);
|
dragVisualizeOffset = new Point(-padding.get() / 2, padding.get() / 2);
|
||||||
dragRect = new Rect(left, top, right, bottom);
|
dragRect = new Rect(left, top, right, bottom);
|
||||||
} else if (child instanceof FolderIcon) {
|
} else if (child instanceof FolderIcon) {
|
||||||
int previewSize = grid.folderIconSizePx;
|
int previewSize = grid.folderIconSizePx;
|
||||||
@@ -2731,7 +2735,8 @@ public class Workspace extends SmoothPagedView
|
|||||||
mLauncher.onDragStarted(child);
|
mLauncher.onDragStarted(child);
|
||||||
|
|
||||||
// Compose a new drag bitmap that is of the icon size
|
// Compose a new drag bitmap that is of the icon size
|
||||||
final Bitmap tmpB = createDragBitmap(child, new Canvas(), DRAG_BITMAP_PADDING);
|
AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING);
|
||||||
|
final Bitmap tmpB = createDragBitmap(child, new Canvas(), padding);
|
||||||
Bitmap b = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
|
Bitmap b = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
|
||||||
Paint p = new Paint();
|
Paint p = new Paint();
|
||||||
p.setFilterBitmap(true);
|
p.setFilterBitmap(true);
|
||||||
@@ -2749,7 +2754,7 @@ public class Workspace extends SmoothPagedView
|
|||||||
|
|
||||||
// Note: The drag region is used to calculate drag layer offsets, but the
|
// Note: The drag region is used to calculate drag layer offsets, but the
|
||||||
// dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
|
// dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
|
||||||
Point dragVisualizeOffset = new Point(-DRAG_BITMAP_PADDING / 2, DRAG_BITMAP_PADDING / 2);
|
Point dragVisualizeOffset = new Point(-padding.get() / 2, padding.get() / 2);
|
||||||
Rect dragRect = new Rect(0, 0, iconSize, iconSize);
|
Rect dragRect = new Rect(0, 0, iconSize, iconSize);
|
||||||
|
|
||||||
if (child.getTag() == null || !(child.getTag() instanceof ItemInfo)) {
|
if (child.getTag() == null || !(child.getTag() instanceof ItemInfo)) {
|
||||||
@@ -3981,15 +3986,16 @@ public class Workspace extends SmoothPagedView
|
|||||||
} else {
|
} else {
|
||||||
cellLayout.findCellForSpan(mTargetCell, 1, 1);
|
cellLayout.findCellForSpan(mTargetCell, 1, 1);
|
||||||
}
|
}
|
||||||
|
// Add the item to DB before adding to screen ensures that the container and other
|
||||||
|
// values of the info is properly updated.
|
||||||
|
LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId,
|
||||||
|
mTargetCell[0], mTargetCell[1]);
|
||||||
|
|
||||||
addInScreen(view, container, screenId, mTargetCell[0], mTargetCell[1], info.spanX,
|
addInScreen(view, container, screenId, mTargetCell[0], mTargetCell[1], info.spanX,
|
||||||
info.spanY, insertAtFirst);
|
info.spanY, insertAtFirst);
|
||||||
cellLayout.onDropChild(view);
|
cellLayout.onDropChild(view);
|
||||||
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
|
|
||||||
cellLayout.getShortcutsAndWidgets().measureChild(view);
|
cellLayout.getShortcutsAndWidgets().measureChild(view);
|
||||||
|
|
||||||
LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId,
|
|
||||||
lp.cellX, lp.cellY);
|
|
||||||
|
|
||||||
if (d.dragView != null) {
|
if (d.dragView != null) {
|
||||||
// We wrap the animation call in the temporary set and reset of the current
|
// We wrap the animation call in the temporary set and reset of the current
|
||||||
// cellLayout to its final transform -- this means we animate the drag view to
|
// cellLayout to its final transform -- this means we animate the drag view to
|
||||||
|
|||||||
Reference in New Issue
Block a user