summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/android/launcher2/AppsCustomizePagedView.java106
-rw-r--r--src/com/android/launcher2/DeleteDropTarget.java24
-rw-r--r--src/com/android/launcher2/DragLayer.java73
-rw-r--r--src/com/android/launcher2/DragView.java36
-rw-r--r--src/com/android/launcher2/FolderIcon.java5
-rw-r--r--src/com/android/launcher2/Launcher.java139
-rw-r--r--src/com/android/launcher2/PagedViewWidget.java65
-rw-r--r--src/com/android/launcher2/PendingAddItemInfo.java4
-rw-r--r--src/com/android/launcher2/Workspace.java132
9 files changed, 464 insertions, 120 deletions
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
index 7cfe3be2f..de96edade 100644
--- a/src/com/android/launcher2/AppsCustomizePagedView.java
+++ b/src/com/android/launcher2/AppsCustomizePagedView.java
@@ -19,6 +19,7 @@ package com.android.launcher2;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
+import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
@@ -39,6 +40,8 @@ import android.graphics.Rect;
import android.graphics.TableMaskFilter;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.Process;
import android.util.AttributeSet;
import android.util.Log;
@@ -167,7 +170,7 @@ class AppsCustomizeAsyncTask extends AsyncTask<AsyncTaskPageData, Void, AsyncTas
*/
public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements
AllAppsView, View.OnClickListener, View.OnKeyListener, DragSource,
- PagedViewIcon.PressedCallback {
+ PagedViewIcon.PressedCallback, PagedViewWidget.ShortPressListener {
static final String LOG_TAG = "AppsCustomizePagedView";
/**
@@ -229,6 +232,14 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
ArrayList<AppsCustomizeAsyncTask> mRunningTasks;
private static final int sPageSleepDelay = 200;
+ private Runnable mInflateWidgetRunnable = null;
+ private Runnable mBindWidgetRunnable = null;
+ static final int WIDGET_NO_CLEANUP_REQUIRED = -1;
+ static final int WIDGET_BOUND = 0;
+ static final int WIDGET_INFLATED = 1;
+ int mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED;
+ int mWidgetLoadingId = -1;
+
public AppsCustomizePagedView(Context context, AttributeSet attrs) {
super(context, attrs);
mLayoutInflater = LayoutInflater.from(context);
@@ -536,7 +547,64 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
mLauncher.getWorkspace().beginDragShared(v, this);
}
+ private void loadWidgetInBackground(final PendingAddWidgetInfo info) {
+ final AppWidgetProviderInfo pInfo = info.info;
+ if (pInfo.configure != null) {
+ return;
+ }
+
+ mBindWidgetRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId();
+ AppWidgetManager.getInstance(mLauncher).bindAppWidgetId(mWidgetLoadingId,
+ info.componentName);
+ mWidgetCleanupState = WIDGET_BOUND;
+ }
+ };
+ post(mBindWidgetRunnable);
+
+ mInflateWidgetRunnable = new Runnable() {
+ @Override
+ public void run() {
+ AppWidgetHostView hostView =
+ mLauncher.getAppWidgetHost().createView(mContext, mWidgetLoadingId, pInfo);
+ info.boundWidget = hostView;
+ mWidgetCleanupState = WIDGET_INFLATED;
+ }
+ };
+ post(mInflateWidgetRunnable);
+ }
+
+ @Override
+ public void onShortPress(View v) {
+ // We are anticipating a long press, and we use this time to load bind and instantiate
+ // the widget. This will need to be cleaned up if it turns out no long press occurs.
+ PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) v.getTag();
+ loadWidgetInBackground(createWidgetInfo);
+ }
+
+ @Override
+ public void cleanUpShortPress(View v) {
+ PendingAddWidgetInfo info = (PendingAddWidgetInfo) v.getTag();
+ if (mWidgetCleanupState >= 0 && mWidgetLoadingId != -1) {
+ mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
+ }
+ if (mWidgetCleanupState == WIDGET_BOUND) {
+ removeCallbacks(mInflateWidgetRunnable);
+ } else if (mWidgetCleanupState == WIDGET_INFLATED) {
+ AppWidgetHostView widget = info.boundWidget;
+ int widgetId = widget.getAppWidgetId();
+ mLauncher.getAppWidgetHost().deleteAppWidgetId(widgetId);
+ }
+ mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED;
+ mWidgetLoadingId = -1;
+ }
+
private void beginDraggingWidget(View v) {
+ mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED;
+ mWidgetLoadingId = -1;
+
// Get the widget preview as the drag representation
ImageView image = (ImageView) v.findViewById(R.id.widget_preview);
PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
@@ -547,13 +615,13 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
if (createItemInfo instanceof PendingAddWidgetInfo) {
PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) createItemInfo;
int[] spanXY = mLauncher.getSpanForWidget(createWidgetInfo, null);
+ int[] size = mLauncher.getWorkspace().estimateItemSize(spanXY[0],
+ spanXY[1], createWidgetInfo, true);
createItemInfo.spanX = spanXY[0];
createItemInfo.spanY = spanXY[1];
- int[] maxSize = mLauncher.getWorkspace().estimateItemSize(spanXY[0], spanXY[1],
- createWidgetInfo, true);
preview = getWidgetPreview(createWidgetInfo.componentName, createWidgetInfo.previewImage,
- createWidgetInfo.icon, spanXY[0], spanXY[1], maxSize[0], maxSize[1]);
+ createWidgetInfo.icon, spanXY[0], spanXY[1], size[0], size[1]);
} else {
// Workaround for the fact that we don't keep the original ResolveInfo associated with
// the shortcut around. To get the icon, we just render the preview image (which has
@@ -593,24 +661,33 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
outline.recycle();
preview.recycle();
}
- @Override
- protected boolean beginDragging(View v) {
- // Dismiss the cling
- mLauncher.dismissAllAppsCling(null);
+ @Override
+ protected boolean beginDragging(final View v) {
if (!super.beginDragging(v)) return false;
- // Reset the alpha on the dragged icon before we drag
- resetDrawableState();
-
- // Go into spring loaded mode (must happen before we startDrag())
- mLauncher.enterSpringLoadedDragMode();
-
if (v instanceof PagedViewIcon) {
beginDraggingApplication(v);
} else if (v instanceof PagedViewWidget) {
beginDraggingWidget(v);
}
+
+ // We delay entering spring-loaded mode slightly to make sure the UI
+ // thready is free of any work.
+ postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ // Dismiss the cling
+ mLauncher.dismissAllAppsCling(null);
+
+ // Reset the alpha on the dragged icon before we drag
+ resetDrawableState();
+
+ // Go into spring loaded mode (must happen before we startDrag())
+ mLauncher.enterSpringLoadedDragMode();
+ }
+ },150);
+
return true;
}
private void endDragging(View target, boolean success) {
@@ -1045,6 +1122,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
int[] cellSpans = mLauncher.getSpanForWidget(info, null);
widget.applyFromAppWidgetProviderInfo(info, -1, cellSpans);
widget.setTag(createItemInfo);
+ widget.setShortPressListener(this);
} else if (rawInfo instanceof ResolveInfo) {
// Fill in the shortcuts information
ResolveInfo info = (ResolveInfo) rawInfo;
diff --git a/src/com/android/launcher2/DeleteDropTarget.java b/src/com/android/launcher2/DeleteDropTarget.java
index 3b82f9e94..a6b2b5c8b 100644
--- a/src/com/android/launcher2/DeleteDropTarget.java
+++ b/src/com/android/launcher2/DeleteDropTarget.java
@@ -165,23 +165,30 @@ public class DeleteDropTarget extends ButtonDropTarget {
}
}
- private void animateToTrashAndCompleteDrop(final DragObject d) {
+ Rect getDeleteRect(int deleteItemWidth, int deleteItemHeight) {
DragLayer dragLayer = mLauncher.getDragLayer();
- Rect from = new Rect();
+
Rect to = new Rect();
- dragLayer.getViewRectRelativeToSelf(d.dragView, from);
dragLayer.getViewRectRelativeToSelf(this, to);
-
int width = mCurrentDrawable.getIntrinsicWidth();
int height = mCurrentDrawable.getIntrinsicHeight();
to.set(to.left + getPaddingLeft(), to.top + getPaddingTop(),
to.left + getPaddingLeft() + width, to.bottom);
// Center the destination rect about the trash icon
- int xOffset = (int) -(d.dragView.getMeasuredWidth() - width) / 2;
- int yOffset = (int) -(d.dragView.getMeasuredHeight() - height) / 2;
+ int xOffset = (int) -(deleteItemWidth - width) / 2;
+ int yOffset = (int) -(deleteItemHeight - height) / 2;
to.offset(xOffset, yOffset);
+ return to;
+ }
+
+ private void animateToTrashAndCompleteDrop(final DragObject d) {
+ DragLayer dragLayer = mLauncher.getDragLayer();
+ Rect from = new Rect();
+ dragLayer.getViewRectRelativeToSelf(d.dragView, from);
+ Rect to = getDeleteRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight());
+
mSearchDropTargetBar.deferOnDragEnd();
Runnable onAnimationEndRunnable = new Runnable() {
@Override
@@ -191,9 +198,10 @@ public class DeleteDropTarget extends ButtonDropTarget {
completeDrop(d);
}
};
- dragLayer.animateView(d.dragView, from, to, 0.1f, 0.1f,
+ dragLayer.animateView(d.dragView, from, to, 0.1f, 1, 1, 0.1f, 0.1f,
DELETE_ANIMATION_DURATION, new DecelerateInterpolator(2),
- new DecelerateInterpolator(1.5f), onAnimationEndRunnable, false, null);
+ new DecelerateInterpolator(1.5f), onAnimationEndRunnable,
+ DragLayer.ANIMATION_END_DISAPPEAR, null);
}
private void completeDrop(DragObject d) {
diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java
index c315b6018..6f3bcd1ac 100644
--- a/src/com/android/launcher2/DragLayer.java
+++ b/src/com/android/launcher2/DragLayer.java
@@ -67,12 +67,16 @@ public class DragLayer extends FrameLayout {
private View mAnchorView = null;
private int[] mDropViewPos = new int[2];
- private float mDropViewScale;
+ private float mDropViewScaleX;
+ private float mDropViewScaleY;
private float mDropViewAlpha;
private boolean mHoverPointClosesFolder = false;
private Rect mHitRect = new Rect();
private int mWorkspaceIndex = -1;
private int mQsbIndex = -1;
+ public static final int ANIMATION_END_DISAPPEAR = 0;
+ public static final int ANIMATION_END_FADE_OUT = 1;
+ public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
/**
* Used to create a new DragLayer from XML.
@@ -414,15 +418,23 @@ public class DragLayer extends FrameLayout {
animateViewIntoPosition(dragView, child, null);
}
- public void animateViewIntoPosition(DragView dragView, final int[] pos, float scale,
- Runnable onFinishRunnable) {
+ public void animateViewIntoPosition(DragView dragView, final int[] pos, float scaleX, float
+ scaleY, int animationEndStyle, Runnable onFinishRunnable, int duration) {
Rect r = new Rect();
getViewRectRelativeToSelf(dragView, r);
final int fromX = r.left;
final int fromY = r.top;
- animateViewIntoPosition(dragView, fromX, fromY, pos[0], pos[1], scale,
- onFinishRunnable, true, -1, null);
+ animateViewIntoPosition(dragView, fromX, fromY, pos[0], pos[1], 1, 1, 1, scaleX, scaleY,
+ onFinishRunnable, animationEndStyle, duration, null);
+ }
+
+ public void scaleViewIntoPosition(DragView dragView, final int[] pos, float finalAlpha,
+ float scaleX, float scaleY, int animationEndStyle, Runnable onFinishRunnable,
+ int duration) {
+ animateViewIntoPosition(dragView, pos[0], pos[1], pos[0], pos[1], finalAlpha,
+ mDropViewScaleX, mDropViewScaleY, scaleX, scaleY, onFinishRunnable,
+ animationEndStyle, duration, null);
}
public void animateViewIntoPosition(DragView dragView, final View child,
@@ -486,18 +498,19 @@ public class DragLayer extends FrameLayout {
oa.start();
}
};
- animateViewIntoPosition(dragView, fromX, fromY, toX, toY, scale,
- onCompleteRunnable, true, duration, anchorView);
+ animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, scale, scale,
+ onCompleteRunnable, ANIMATION_END_FADE_OUT, duration, anchorView);
}
private void animateViewIntoPosition(final View view, final int fromX, final int fromY,
- final int toX, final int toY, float finalScale, Runnable onCompleteRunnable,
- boolean fadeOut, int duration, View anchorView) {
+ final int toX, final int toY, float finalAlpha, float initScaleX, float initScaleY,
+ float finalScaleX, float finalScaleY, Runnable onCompleteRunnable,
+ int animationEndStyle, int duration, View anchorView) {
Rect from = new Rect(fromX, fromY, fromX +
view.getMeasuredWidth(), fromY + view.getMeasuredHeight());
Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight());
- animateView(view, from, to, 1f, finalScale, duration, null, null,
- onCompleteRunnable, true, anchorView);
+ animateView(view, from, to, finalAlpha, initScaleX, initScaleY, finalScaleX, finalScaleY, duration,
+ null, null, onCompleteRunnable, animationEndStyle, anchorView);
}
/**
@@ -522,9 +535,10 @@ public class DragLayer extends FrameLayout {
* only used for the X dimension for the case of the workspace.
*/
public void animateView(final View view, final Rect from, final Rect to, final float finalAlpha,
- final float finalScale, int duration, final Interpolator motionInterpolator,
+ final float initScaleX, final float initScaleY, final float finalScaleX,
+ final float finalScaleY, int duration, final Interpolator motionInterpolator,
final Interpolator alphaInterpolator, final Runnable onCompleteRunnable,
- final boolean fadeOut, View anchorView) {
+ final int animationEndStyle, View anchorView) {
// Calculate the duration of the animation based on the object's distance
final float dist = (float) Math.sqrt(Math.pow(to.left - from.left, 2) +
Math.pow(to.top - from.top, 2));
@@ -578,10 +592,10 @@ public class DragLayer extends FrameLayout {
mDropViewPos[0] = from.left + (int) Math.round(((to.left - from.left) * motionPercent));
mDropViewPos[1] = from.top + (int) Math.round(((to.top - from.top) * motionPercent));
- mDropViewScale = percent * finalScale + (1 - percent);
+ mDropViewScaleX = percent * finalScaleX + (1 - percent) * initScaleX;
+ mDropViewScaleY = percent * finalScaleY + (1 - percent) * initScaleY;
mDropViewAlpha = alphaPercent * finalAlpha + (1 - alphaPercent) * initialAlpha;
- invalidate(mDropViewPos[0], mDropViewPos[1],
- mDropViewPos[0] + width, mDropViewPos[1] + height);
+ invalidate();
}
});
mDropAnim.addListener(new AnimatorListenerAdapter() {
@@ -589,16 +603,32 @@ public class DragLayer extends FrameLayout {
if (onCompleteRunnable != null) {
onCompleteRunnable.run();
}
- if (fadeOut) {
+ switch (animationEndStyle) {
+ case ANIMATION_END_DISAPPEAR:
+ clearAnimatedView();
+ break;
+ case ANIMATION_END_FADE_OUT:
fadeOutDragView();
- } else {
- mDropView = null;
+ break;
+ case ANIMATION_END_REMAIN_VISIBLE:
+ break;
}
}
});
mDropAnim.start();
}
+ public void clearAnimatedView() {
+ mDropView = null;
+ mDropViewScaleX = 1;
+ mDropViewScaleY = 1;
+ invalidate();
+ }
+
+ public View getAnimatedView() {
+ return mDropView;
+ }
+
private void fadeOutDragView() {
mFadeOutAnim = new ValueAnimator();
mFadeOutAnim.setDuration(150);
@@ -617,6 +647,7 @@ public class DragLayer extends FrameLayout {
mFadeOutAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
mDropView = null;
+ invalidate();
}
});
mFadeOutAnim.start();
@@ -679,8 +710,8 @@ public class DragLayer extends FrameLayout {
int width = mDropView.getMeasuredWidth();
int height = mDropView.getMeasuredHeight();
canvas.translate(xPos, yPos);
- canvas.translate((1 - mDropViewScale) * width / 2, (1 - mDropViewScale) * height / 2);
- canvas.scale(mDropViewScale, mDropViewScale);
+ canvas.translate((1 - mDropViewScaleX) * width / 2, (1 - mDropViewScaleY) * height / 2);
+ canvas.scale(mDropViewScaleX, mDropViewScaleY);
mDropView.setAlpha(mDropViewAlpha);
mDropView.draw(canvas);
canvas.restore();
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
index a3063b6e9..15d9c5449 100644
--- a/src/com/android/launcher2/DragView.java
+++ b/src/com/android/launcher2/DragView.java
@@ -33,6 +33,7 @@ import com.android.launcher.R;
public class DragView extends View {
private Bitmap mBitmap;
+ private Bitmap mCrossFadeBitmap;
private Paint mPaint;
private int mRegistrationX;
private int mRegistrationY;
@@ -41,6 +42,7 @@ public class DragView extends View {
private Rect mDragRegion = null;
private DragLayer mDragLayer = null;
private boolean mHasDrawn = false;
+ private float mCrossFadeProgress = 0f;
ValueAnimator mAnim;
private float mOffsetX = 0.0f;
@@ -164,9 +166,43 @@ public class DragView extends View {
p.setColor(0xaaffffff);
canvas.drawRect(0, 0, getWidth(), getHeight(), p);
}
+ if (mPaint == null) {
+ mPaint = new Paint();
+ }
mHasDrawn = true;
+ boolean crossFade = mCrossFadeProgress > 0 && mCrossFadeBitmap != null;
+ if (crossFade) {
+ int alpha = crossFade ? (int) (255 * (1 - mCrossFadeProgress)) : 255;
+ mPaint.setAlpha(alpha);
+ }
canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
+ if (crossFade) {
+ mPaint.setAlpha((int) (255 * mCrossFadeProgress));
+ canvas.save();
+ float sX = (mBitmap.getWidth() * 1.0f) / mCrossFadeBitmap.getWidth();
+ float sY = (mBitmap.getHeight() * 1.0f) / mCrossFadeBitmap.getHeight();
+ canvas.scale(sX, sY);
+ canvas.drawBitmap(mCrossFadeBitmap, 0.0f, 0.0f, mPaint);
+ canvas.restore();
+ }
+ }
+
+ public void setCrossFadeBitmap(Bitmap crossFadeBitmap) {
+ mCrossFadeBitmap = crossFadeBitmap;
+ }
+
+ public void crossFade(int duration) {
+ ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
+ va.setDuration(duration);
+ va.setInterpolator(new DecelerateInterpolator(1.5f));
+ va.addUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mCrossFadeProgress = animation.getAnimatedFraction();
+ }
+ });
+ va.start();
}
public void setPaint(Paint paint) {
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index 2a711f88b..ca537d8c4 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -359,10 +359,11 @@ public class FolderIcon extends LinearLayout implements FolderListener {
float finalAlpha = index < NUM_ITEMS_IN_PREVIEW ? 0.5f : 0f;
+ float finalScale = scale * scaleRelativeToDragLayer;
dragLayer.animateView(animateView, from, to, finalAlpha,
- scale * scaleRelativeToDragLayer, DROP_IN_ANIMATION_DURATION,
+ 1, 1, finalScale, finalScale, DROP_IN_ANIMATION_DURATION,
new DecelerateInterpolator(2), new AccelerateInterpolator(2),
- postAnimationRunnable, false, null);
+ postAnimationRunnable, DragLayer.ANIMATION_END_DISAPPEAR, null);
postDelayed(new Runnable() {
public void run() {
addItem(item);
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index 7d974a513..708d5d631 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -49,6 +49,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
+import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -246,6 +247,7 @@ public final class Launcher extends Activity
private static Drawable.ConstantState[] sAppMarketIcon = new Drawable.ConstantState[2];
static final ArrayList<String> sDumpLogs = new ArrayList<String>();
+ PendingAddWidgetInfo mWidgetBeingConfigured = null;
private BubbleTextView mWaitingForResume;
@@ -498,7 +500,7 @@ public final class Launcher extends Activity
break;
case REQUEST_CREATE_APPWIDGET:
int appWidgetId = args.intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
- completeAddAppWidget(appWidgetId, args.container, args.screen);
+ completeAddAppWidget(appWidgetId, args.container, args.screen, null, null);
result = true;
break;
case REQUEST_PICK_WALLPAPER:
@@ -509,10 +511,20 @@ public final class Launcher extends Activity
}
@Override
- protected void onActivityResult(final int requestCode, int resultCode, final Intent data) {
+ protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
boolean delayExitSpringLoadedMode = false;
+ boolean isWidgetDrop = (requestCode == REQUEST_PICK_APPWIDGET ||
+ requestCode == REQUEST_CREATE_APPWIDGET);
mWaitingForResult = false;
+ // We have special handling for widgets
+ if (isWidgetDrop) {
+ int appWidgetId = data != null ?
+ data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1) : -1;
+ completeTwoStageWidgetDrop(resultCode, appWidgetId);
+ return;
+ }
+
// The pattern used here is that a user PICKs a specific application,
// which, depending on the target, might need to CREATE the actual target.
@@ -526,26 +538,50 @@ public final class Launcher extends Activity
args.screen = mPendingAddInfo.screen;
args.cellX = mPendingAddInfo.cellX;
args.cellY = mPendingAddInfo.cellY;
-
- // If the loader is still running, defer the add until it is done.
if (isWorkspaceLocked()) {
sPendingAddList.add(args);
} else {
delayExitSpringLoadedMode = completeAdd(args);
}
- } else if ((requestCode == REQUEST_PICK_APPWIDGET ||
- requestCode == REQUEST_CREATE_APPWIDGET) && resultCode == RESULT_CANCELED) {
- if (data != null) {
- // Clean up the appWidgetId if we canceled
- int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
- if (appWidgetId != -1) {
- mAppWidgetHost.deleteAppWidgetId(appWidgetId);
- }
- }
}
-
+ mDragLayer.clearAnimatedView();
// Exit spring loaded mode if necessary after cancelling the configuration of a widget
- exitSpringLoadedDragModeDelayed((resultCode != RESULT_CANCELED), delayExitSpringLoadedMode);
+ exitSpringLoadedDragModeDelayed((resultCode != RESULT_CANCELED), delayExitSpringLoadedMode,
+ null);
+ }
+
+ private void completeTwoStageWidgetDrop(final int resultCode, final int appWidgetId) {
+ CellLayout cellLayout = (CellLayout) mWorkspace.getChildAt(mWidgetBeingConfigured.screen);
+ Runnable onCompleteRunnable = null;
+ int animationType = 0;
+
+ if (resultCode == RESULT_OK) {
+ animationType = Workspace.COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION;
+ final AppWidgetHostView layout = mAppWidgetHost.createView(this, appWidgetId,
+ mWidgetBeingConfigured.info);
+ mWidgetBeingConfigured.boundWidget = layout;
+ onCompleteRunnable = new Runnable() {
+ @Override
+ public void run() {
+ completeAddAppWidget(appWidgetId, mPendingAddInfo.container,
+ mPendingAddInfo.screen, layout, null);
+ exitSpringLoadedDragModeDelayed((resultCode != RESULT_CANCELED), false,
+ null);
+ }
+ };
+ } else if (resultCode == RESULT_CANCELED) {
+ animationType = Workspace.CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION;
+ onCompleteRunnable = new Runnable() {
+ @Override
+ public void run() {
+ exitSpringLoadedDragModeDelayed((resultCode != RESULT_CANCELED), false,
+ null);
+ }
+ };
+ }
+ mWorkspace.animateExternalDrop(mWidgetBeingConfigured, cellLayout,
+ (DragView) mDragLayer.getAnimatedView(), onCompleteRunnable,
+ animationType);
}
@Override
@@ -934,8 +970,11 @@ public final class Launcher extends Activity
* @param appWidgetId The app widget id
* @param cellInfo The position on screen where to create the widget.
*/
- private void completeAddAppWidget(final int appWidgetId, long container, int screen) {
- AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
+ private void completeAddAppWidget(final int appWidgetId, long container, int screen,
+ AppWidgetHostView hostView, AppWidgetProviderInfo appWidgetInfo) {
+ if (appWidgetInfo == null) {
+ appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
+ }
// Calculate the grid spans needed to fit this widget
CellLayout layout = getCellLayout(container, screen);
@@ -984,12 +1023,16 @@ public final class Launcher extends Activity
container, screen, cellXY[0], cellXY[1], false);
if (!mRestoring) {
- // Perform actual inflation because we're live
- launcherInfo.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
+ if (hostView == null) {
+ // Perform actual inflation because we're live
+ launcherInfo.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
+ launcherInfo.hostView.setAppWidget(appWidgetId, appWidgetInfo);
+ } else {
+ // The AppWidgetHostView has already been inflated and instantiated
+ launcherInfo.hostView = hostView;
+ }
- launcherInfo.hostView.setAppWidget(appWidgetId, appWidgetInfo);
launcherInfo.hostView.setTag(launcherInfo);
-
mWorkspace.addInScreen(launcherInfo.hostView, container, screen, cellXY[0], cellXY[1],
launcherInfo.spanX, launcherInfo.spanY, isWorkspaceLocked());
@@ -1427,9 +1470,9 @@ public final class Launcher extends Activity
addAppWidgetImpl(appWidgetId, null);
}
- void addAppWidgetImpl(int appWidgetId, PendingAddWidgetInfo info) {
- AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
-
+ void addAppWidgetImpl(final int appWidgetId, final PendingAddWidgetInfo info) {
+ final AppWidgetProviderInfo appWidget = info.info;
+ Runnable configurationActivity = null;
if (appWidget.configure != null) {
// Launch over to configure widget, if needed
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
@@ -1437,9 +1480,8 @@ public final class Launcher extends Activity
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
if (info != null) {
if (info.mimeType != null && !info.mimeType.isEmpty()) {
- intent.putExtra(
- InstallWidgetReceiver.EXTRA_APPWIDGET_CONFIGURATION_DATA_MIME_TYPE,
- info.mimeType);
+ intent.putExtra(InstallWidgetReceiver.
+ EXTRA_APPWIDGET_CONFIGURATION_DATA_MIME_TYPE, info.mimeType);
final String mimeType = info.mimeType;
final ClipData clipData = (ClipData) info.configurationData;
@@ -1450,8 +1492,8 @@ public final class Launcher extends Activity
final CharSequence stringData = item.getText();
final Uri uriData = item.getUri();
final Intent intentData = item.getIntent();
- final String key =
- InstallWidgetReceiver.EXTRA_APPWIDGET_CONFIGURATION_DATA;
+ final String key = InstallWidgetReceiver.
+ EXTRA_APPWIDGET_CONFIGURATION_DATA;
if (uriData != null) {
intent.putExtra(key, uriData);
} else if (intentData != null) {
@@ -1464,14 +1506,13 @@ public final class Launcher extends Activity
}
}
}
-
startActivityForResultSafely(intent, REQUEST_CREATE_APPWIDGET);
+ mWidgetBeingConfigured = info;
} else {
// Otherwise just add it
- completeAddAppWidget(appWidgetId, info.container, info.screen);
-
+ completeAddAppWidget(appWidgetId, info.container, info.screen, info.boundWidget, appWidget);
// Exit spring loaded mode if necessary after adding the widget
- exitSpringLoadedDragModeDelayed(true, false);
+ exitSpringLoadedDragModeDelayed(true, false, null);
}
}
@@ -1519,9 +1560,16 @@ public final class Launcher extends Activity
mPendingAddInfo.cellY = cell[1];
}
- int appWidgetId = getAppWidgetHost().allocateAppWidgetId();
- AppWidgetManager.getInstance(this).bindAppWidgetId(appWidgetId, info.componentName);
+ AppWidgetHostView hostView = info.boundWidget;
+ int appWidgetId;
+ if (hostView != null) {
+ appWidgetId = hostView.getAppWidgetId();
+ } else {
+ appWidgetId = getAppWidgetHost().allocateAppWidgetId();
+ AppWidgetManager.getInstance(this).bindAppWidgetId(appWidgetId, info.componentName);
+ }
addAppWidgetImpl(appWidgetId, info);
+
}
void processShortcut(Intent intent) {
@@ -2368,8 +2416,9 @@ public final class Launcher extends Activity
* This is the opposite of showAppsCustomizeHelper.
* @param animated If true, the transition will be animated.
*/
- private void hideAppsCustomizeHelper(
- State toState, final boolean animated, final boolean springLoaded) {
+ private void hideAppsCustomizeHelper(State toState, final boolean animated,
+ final boolean springLoaded, final Runnable onCompleteRunnable) {
+
if (mStateAnimation != null) {
mStateAnimation.cancel();
mStateAnimation = null;
@@ -2426,6 +2475,9 @@ public final class Launcher extends Activity
dispatchOnLauncherTransitionEnd(fromView, animated, true);
dispatchOnLauncherTransitionEnd(toView, animated, true);
mWorkspace.hideScrollingIndicator(false);
+ if (onCompleteRunnable != null) {
+ onCompleteRunnable.run();
+ }
}
});
@@ -2453,9 +2505,13 @@ public final class Launcher extends Activity
}
void showWorkspace(boolean animated) {
+ showWorkspace(animated, null);
+ }
+
+ void showWorkspace(boolean animated, Runnable onCompleteRunnable) {
if (mState != State.WORKSPACE) {
mWorkspace.setVisibility(View.VISIBLE);
- hideAppsCustomizeHelper(State.WORKSPACE, animated, false);
+ hideAppsCustomizeHelper(State.WORKSPACE, animated, false, onCompleteRunnable);
// Show the search bar and hotseat
mSearchDropTargetBar.showSearchBar(animated);
@@ -2504,13 +2560,14 @@ public final class Launcher extends Activity
void enterSpringLoadedDragMode() {
if (mState == State.APPS_CUSTOMIZE) {
- hideAppsCustomizeHelper(State.APPS_CUSTOMIZE_SPRING_LOADED, true, true);
+ hideAppsCustomizeHelper(State.APPS_CUSTOMIZE_SPRING_LOADED, true, true, null);
hideDockDivider();
mState = State.APPS_CUSTOMIZE_SPRING_LOADED;
}
}
- void exitSpringLoadedDragModeDelayed(final boolean successfulDrop, boolean extendedDelay) {
+ void exitSpringLoadedDragModeDelayed(final boolean successfulDrop, boolean extendedDelay,
+ final Runnable onCompleteRunnable) {
if (mState != State.APPS_CUSTOMIZE_SPRING_LOADED) return;
mHandler.postDelayed(new Runnable() {
@@ -2522,7 +2579,7 @@ public final class Launcher extends Activity
// clean up our state transition functions
mAppsCustomizeTabHost.setVisibility(View.GONE);
mSearchDropTargetBar.showSearchBar(true);
- showWorkspace(true);
+ showWorkspace(true, onCompleteRunnable);
} else {
exitSpringLoadedDragMode();
}
diff --git a/src/com/android/launcher2/PagedViewWidget.java b/src/com/android/launcher2/PagedViewWidget.java
index 12e9c4673..5ba869118 100644
--- a/src/com/android/launcher2/PagedViewWidget.java
+++ b/src/com/android/launcher2/PagedViewWidget.java
@@ -23,6 +23,7 @@ import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.util.AttributeSet;
import android.view.MotionEvent;
+import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -40,6 +41,9 @@ public class PagedViewWidget extends LinearLayout {
private ImageView mPreviewImageView;
private String mDimensionsFormatString;
+ CheckForShortPress mPendingCheckForShortPress = null;
+ ShortPressListener mShortPressListener = null;
+ boolean mShortPressTriggered = false;
public PagedViewWidget(Context context) {
this(context, null);
@@ -127,8 +131,67 @@ public class PagedViewWidget extends LinearLayout {
}
}
+ void setShortPressListener(ShortPressListener listener) {
+ mShortPressListener = listener;
+ }
+
+ interface ShortPressListener {
+ void onShortPress(View v);
+ void cleanUpShortPress(View v);
+ }
+
+ class CheckForShortPress implements Runnable {
+ public void run() {
+ if (mShortPressListener != null) {
+ mShortPressListener.onShortPress(PagedViewWidget.this);
+ }
+ mShortPressTriggered = true;
+ }
+ }
+
+ private void checkForShortPress() {
+ if (mPendingCheckForShortPress == null) {
+ mPendingCheckForShortPress = new CheckForShortPress();
+ }
+ postDelayed(mPendingCheckForShortPress, 120);
+ }
+
+ /**
+ * Remove the longpress detection timer.
+ */
+ private void removeShortPressCallback() {
+ if (mPendingCheckForShortPress != null) {
+ removeCallbacks(mPendingCheckForShortPress);
+ }
+ }
+
+ private void cleanUpShortPress() {
+ removeShortPressCallback();
+ if (mShortPressTriggered) {
+ if (mShortPressListener != null) {
+ mShortPressListener.cleanUpShortPress(PagedViewWidget.this);
+ }
+ mShortPressTriggered = false;
+ }
+ }
+
@Override
public boolean onTouchEvent(MotionEvent event) {
+ super.onTouchEvent(event);
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_UP:
+ cleanUpShortPress();
+ break;
+ case MotionEvent.ACTION_DOWN:
+ checkForShortPress();
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ cleanUpShortPress();
+ break;
+ case MotionEvent.ACTION_MOVE:
+ break;
+ }
// We eat up the touch events here, since the PagedView (which uses the same swiping
// touch code as Workspace previously) uses onInterceptTouchEvent() to determine when
// the user is scrolling between pages. This means that if the pages themselves don't
@@ -136,6 +199,6 @@ public class PagedViewWidget extends LinearLayout {
// onTouchEvent() handling will prevent further intercept touch events from being called
// (it's the same view in that case). This is not ideal, but to prevent more changes,
// we just always mark the touch event as handled.
- return super.onTouchEvent(event) || true;
+ return true;
}
}
diff --git a/src/com/android/launcher2/PendingAddItemInfo.java b/src/com/android/launcher2/PendingAddItemInfo.java
index 9c52ecfa0..851dddb15 100644
--- a/src/com/android/launcher2/PendingAddItemInfo.java
+++ b/src/com/android/launcher2/PendingAddItemInfo.java
@@ -16,6 +16,7 @@
package com.android.launcher2;
+import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.os.Parcelable;
@@ -35,6 +36,8 @@ class PendingAddWidgetInfo extends PendingAddItemInfo {
int minHeight;
int previewImage;
int icon;
+ AppWidgetProviderInfo info;
+ AppWidgetHostView boundWidget;
// Any configuration data that we want to pass to a configuration activity when
// starting up a widget
@@ -43,6 +46,7 @@ class PendingAddWidgetInfo extends PendingAddItemInfo {
public PendingAddWidgetInfo(AppWidgetProviderInfo i, String dataMimeType, Parcelable data) {
itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
+ this.info = i;
componentName = i.provider;
minWidth = i.minWidth;
minHeight = i.minHeight;
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 746c68229..c8cab163c 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -56,6 +56,7 @@ import android.view.DragEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.View.MeasureSpec;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
import android.widget.TextView;
@@ -204,6 +205,11 @@ public class Workspace extends SmoothPagedView
final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3;
final static float TOUCH_SLOP_DAMPING_FACTOR = 4;
+ // Relating to the animation of items being dropped externally
+ public static final int ANIMATE_INTO_POSITION = 0;
+ public static final int COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION = 1;
+ public static final int CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION = 2;
+
// These variables are used for storing the initial and final values during workspace animations
private int mSavedScrollX;
private float mSavedRotationY;
@@ -334,15 +340,6 @@ public class Workspace extends SmoothPagedView
int hCell, int vCell, int hSpan, int vSpan) {
RectF r = new RectF();
cl.cellToRect(hCell, vCell, hSpan, vSpan, r);
- if (pendingInfo instanceof PendingAddWidgetInfo) {
- PendingAddWidgetInfo widgetInfo = (PendingAddWidgetInfo) pendingInfo;
- Rect p = AppWidgetHostView.getDefaultPaddingForWidget(mContext,
- widgetInfo.componentName, null);
- r.top += p.top;
- r.left += p.left;
- r.right -= p.right;
- r.bottom -= p.bottom;
- }
return r;
}
@@ -502,10 +499,12 @@ public class Workspace extends SmoothPagedView
child.setOnKeyListener(new IconKeyEventListener());
}
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
- if (lp == null) {
+ LayoutParams genericLp = child.getLayoutParams();
+ CellLayout.LayoutParams lp;
+ if (genericLp == null || !(genericLp instanceof CellLayout.LayoutParams)) {
lp = new CellLayout.LayoutParams(x, y, spanX, spanY);
} else {
+ lp = (CellLayout.LayoutParams) genericLp;
lp.cellX = x;
lp.cellY = y;
lp.cellHSpan = spanX;
@@ -2869,7 +2868,7 @@ public class Workspace extends SmoothPagedView
final Runnable exitSpringLoadedRunnable = new Runnable() {
@Override
public void run() {
- mLauncher.exitSpringLoadedDragModeDelayed(true, false);
+ mLauncher.exitSpringLoadedDragModeDelayed(true, false, null);
}
};
@@ -2930,27 +2929,8 @@ public class Workspace extends SmoothPagedView
}
};
- // Now we animate the dragView, (ie. the widget or shortcut preview) into its final
- // location and size on the home screen.
- RectF r = estimateItemPosition(cellLayout, pendingInfo,
- mTargetCell[0], mTargetCell[1], spanX, spanY);
- int loc[] = new int[2];
- loc[0] = (int) r.left;
- loc[1] = (int) r.top;
- setFinalTransitionTransform(cellLayout);
- float cellLayoutScale =
- mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(cellLayout, loc);
- resetTransitionTransform(cellLayout);
-
- float dragViewScale = Math.min(r.width() / d.dragView.getMeasuredWidth(),
- r.height() / d.dragView.getMeasuredHeight());
- // The animation will scale the dragView about its center, so we need to center about
- // the final location.
- loc[0] -= (d.dragView.getMeasuredWidth() - cellLayoutScale * r.width()) / 2;
- loc[1] -= (d.dragView.getMeasuredHeight() - cellLayoutScale * r.height()) / 2;
-
- mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, loc,
- dragViewScale * cellLayoutScale, onAnimationCompleteRunnable);
+ animateExternalDrop((PendingAddItemInfo) info, cellLayout, d.dragView,
+ onAnimationCompleteRunnable, ANIMATE_INTO_POSITION);
} else {
// This is for other drag/drop cases, like dragging from All Apps
View view = null;
@@ -3016,6 +2996,92 @@ public class Workspace extends SmoothPagedView
}
}
+ // The following methods deal with animating an item from external drop
+ void onPreDraw(View v) {
+ if (v instanceof ViewGroup) {
+ ViewGroup vg = (ViewGroup) v;
+ for (int i = 0; i < vg.getChildCount(); i++) {
+ View child = vg.getChildAt(i);
+ onPreDraw(child);
+ }
+ } else if (v instanceof TextView) {
+ ((TextView) v).onPreDraw();
+ }
+ }
+
+ public Bitmap createWidgetBitmap(PendingAddWidgetInfo widgetInfo) {
+ int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo.spanX,
+ widgetInfo.spanY, widgetInfo, false);
+ View layout = widgetInfo.boundWidget;
+ layout.setVisibility(VISIBLE);
+
+ int width = MeasureSpec.makeMeasureSpec(unScaledSize[0], MeasureSpec.EXACTLY);
+ 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);
+
+ layout.measure(width, height);
+ layout.layout(0, 0, unScaledSize[0], unScaledSize[1]);
+ onPreDraw(layout);
+ layout.draw(c);
+ c.setBitmap(null);
+ return b;
+ }
+
+ public void animateExternalDrop(PendingAddItemInfo pendingInfo, CellLayout cellLayout,
+ DragView dragView, Runnable onCompleteRunnable, int animationType) {
+ // Now we animate the dragView, (ie. the widget or shortcut preview) into its final
+ // location and size on the home screen.
+ int spanX = pendingInfo.spanX;
+ int spanY = pendingInfo.spanY;
+ RectF r = estimateItemPosition(cellLayout, pendingInfo,
+ mTargetCell[0], mTargetCell[1], spanX, spanY);
+ int loc[] = new int[2];
+ loc[0] = (int) r.left;
+ loc[1] = (int) r.top;
+ setFinalTransitionTransform(cellLayout);
+ float cellLayoutScale =
+ mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(cellLayout, loc);
+ resetTransitionTransform(cellLayout);
+
+ float dragViewScaleX = r.width() / dragView.getMeasuredWidth();
+ float dragViewScaleY = r.height() / dragView.getMeasuredHeight();
+ // The animation will scale the dragView about its center, so we need to center about
+ // the final location.
+ loc[0] -= (dragView.getMeasuredWidth() - cellLayoutScale * r.width()) / 2;
+ loc[1] -= (dragView.getMeasuredHeight() - cellLayoutScale * r.height()) / 2;
+
+ float scaleX = dragViewScaleX * cellLayoutScale;
+ float scaleY = dragViewScaleY * cellLayoutScale;
+
+ Resources res = mLauncher.getResources();
+ int duration = res.getInteger(R.integer.config_dropAnimMaxDuration) - 200;
+
+ int animationEnd = DragLayer.ANIMATION_END_REMAIN_VISIBLE;
+ if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET &&
+ (((PendingAddWidgetInfo) pendingInfo).info.configure == null ||
+ animationType == COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION)) {
+ Bitmap crossFadeBitmap = createWidgetBitmap((PendingAddWidgetInfo) pendingInfo);
+ dragView.setCrossFadeBitmap(crossFadeBitmap);
+ dragView.crossFade((int) (duration * 0.8f));
+ animationEnd = DragLayer.ANIMATION_END_DISAPPEAR;
+ } else {
+ scaleX = scaleY = Math.min(scaleX, scaleY);
+ }
+
+ if (animationType == COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION) {
+ mLauncher.getDragLayer().scaleViewIntoPosition(dragView, loc, 1, scaleX, scaleY,
+ animationEnd, onCompleteRunnable, duration);
+ } else if (animationType == CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION) {
+ mLauncher.getDragLayer().scaleViewIntoPosition(dragView, loc, 0, 0.1f, 0.1f,
+ DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration);
+ } else {
+ mLauncher.getDragLayer().animateViewIntoPosition(dragView, loc, scaleX, scaleY,
+ animationEnd, onCompleteRunnable, duration);
+ }
+ }
+
public void setFinalTransitionTransform(CellLayout layout) {
if (isSwitchingState()) {
int index = indexOfChild(layout);