diff options
Diffstat (limited to 'src/com/android/launcher2/AppWidgetResizeFrame.java')
-rw-r--r-- | src/com/android/launcher2/AppWidgetResizeFrame.java | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/src/com/android/launcher2/AppWidgetResizeFrame.java b/src/com/android/launcher2/AppWidgetResizeFrame.java new file mode 100644 index 000000000..6ddb5b8c3 --- /dev/null +++ b/src/com/android/launcher2/AppWidgetResizeFrame.java @@ -0,0 +1,298 @@ +package com.android.launcher2; + +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.appwidget.AppWidgetProviderInfo; +import android.content.Context; +import android.view.Gravity; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.android.launcher.R; + +public class AppWidgetResizeFrame extends FrameLayout { + + private ItemInfo mItemInfo; + private LauncherAppWidgetHostView mWidgetView; + private CellLayout mCellLayout; + private ImageView mLeftHandle; + private ImageView mRightHandle; + private ImageView mTopHandle; + private ImageView mBottomHandle; + + private boolean mLeftBorderActive; + private boolean mRightBorderActive; + private boolean mTopBorderActive; + private boolean mBottomBorderActive; + + private int mBaselineWidth; + private int mBaselineHeight; + private int mBaselineX; + private int mBaselineY; + private int mResizeMode; + + private int mRunningHInc; + private int mRunningVInc; + private int mMinHSpan; + private int mMinVSpan; + private int mDeltaX; + private int mDeltaY; + + private int mExpandability[] = new int[4]; + + final int BORDER_WIDTH = 50; + final int FRAME_MARGIN = 15; + final int SNAP_DURATION = 150; + + public AppWidgetResizeFrame(Context context, ItemInfo itemInfo, + LauncherAppWidgetHostView widgetView, CellLayout cellLayout) { + + super(context); + mContext = context; + mItemInfo = itemInfo; + mCellLayout = cellLayout; + mWidgetView = widgetView; + mResizeMode = widgetView.getAppWidgetInfo().resizableMode; + + final AppWidgetProviderInfo info = widgetView.getAppWidgetInfo(); + int[] result = mCellLayout.rectToCell(info.minWidth, info.minHeight, null); + mMinHSpan = result[0]; + mMinVSpan = result[1]; + + setBackgroundResource(R.drawable.resize_frame); + setPadding(0, 0, 0, 0); + + LayoutParams lp; + mLeftHandle = new ImageView(context); + mLeftHandle.setImageResource(R.drawable.h_handle); + lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, + Gravity.LEFT | Gravity.CENTER_VERTICAL); + addView(mLeftHandle, lp); + + mRightHandle = new ImageView(context); + mRightHandle.setImageResource(R.drawable.h_handle); + lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, + Gravity.RIGHT | Gravity.CENTER_VERTICAL); + addView(mRightHandle, lp); + + mTopHandle = new ImageView(context); + mTopHandle.setImageResource(R.drawable.v_handle); + lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, + Gravity.CENTER_HORIZONTAL | Gravity.TOP); + addView(mTopHandle, lp); + + mBottomHandle = new ImageView(context); + mBottomHandle.setImageResource(R.drawable.v_handle); + lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, + Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM); + addView(mBottomHandle, lp); + + if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) { + mTopHandle.setVisibility(GONE); + mBottomHandle.setVisibility(GONE); + } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) { + mLeftHandle.setVisibility(GONE); + mRightHandle.setVisibility(GONE); + } + } + + public boolean beginResizeIfPointInRegion(int x, int y) { + boolean horizontalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0; + boolean verticalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0; + mLeftBorderActive = (x < BORDER_WIDTH) && horizontalActive; + mRightBorderActive = (x > getWidth() - BORDER_WIDTH) && horizontalActive; + mTopBorderActive = (y < BORDER_WIDTH) && verticalActive; + mBottomBorderActive = (y > getHeight() - BORDER_WIDTH) && verticalActive; + + boolean anyBordersActive = mLeftBorderActive || mRightBorderActive + || mTopBorderActive || mBottomBorderActive; + + mBaselineWidth = getMeasuredWidth(); + mBaselineHeight = getMeasuredHeight(); + mBaselineX = getLeft(); + mBaselineY = getTop(); + mRunningHInc = 0; + mRunningVInc = 0; + + if (anyBordersActive) { + mLeftHandle.setAlpha(mLeftBorderActive ? 1.0f : 0.5f); + mRightHandle.setAlpha(mRightBorderActive ? 1.0f : 0.5f); + mTopHandle.setAlpha(mTopBorderActive ? 1.0f : 0.5f); + mBottomHandle.setAlpha(mBottomBorderActive ? 1.0f : 0.5f); + } + mCellLayout.getExpandabilityArrayForView(mWidgetView, mExpandability); + return anyBordersActive; + } + + public void updateDeltas(int deltaX, int deltaY) { + if (mLeftBorderActive) { + mDeltaX = Math.max(-mBaselineX, deltaX); + mDeltaX = Math.min(mBaselineWidth - 2*BORDER_WIDTH, mDeltaX); + } else if (mRightBorderActive) { + mDeltaX = Math.min(mCellLayout.getWidth() - (mBaselineX + mBaselineWidth), deltaX); + mDeltaX = Math.max(-mBaselineWidth + 2*BORDER_WIDTH, mDeltaX); + } + + if (mTopBorderActive) { + mDeltaY = Math.max(-mBaselineY, deltaY); + mDeltaY = Math.min(mBaselineHeight - 2*BORDER_WIDTH, mDeltaY); + } else if (mBottomBorderActive) { + mDeltaY = Math.min(mCellLayout.getHeight() - (mBaselineY + mBaselineHeight), deltaY); + mDeltaY = Math.max(-mBaselineHeight + 2*BORDER_WIDTH, mDeltaY); + } + } + + public void visualizeResizeForDelta(int deltaX, int deltaY) { + updateDeltas(deltaX, deltaY); + CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams(); + if (mLeftBorderActive) { + lp.x = mBaselineX + mDeltaX; + lp.width = mBaselineWidth - mDeltaX; + } else if (mRightBorderActive) { + lp.width = mBaselineWidth + mDeltaX; + } + + if (mTopBorderActive) { + lp.y = mBaselineY + mDeltaY; + lp.height = mBaselineHeight - mDeltaY; + } else if (mBottomBorderActive) { + lp.height = mBaselineHeight + mDeltaY; + } + + resizeWidgetIfNeeded(); + requestLayout(); + } + + private void resizeWidgetIfNeeded() { + // TODO: these computations probably aren't quite right... think about them + + //System.out.println("runningIncX before: " + mRunningHInc); + //System.out.println("runningIncY before: " + mRunningVInc); + + int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap(); + int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap(); + + int hSpanInc = (int) Math.round(1.0f * mDeltaX / xThreshold) - mRunningHInc; + int vSpanInc = (int) Math.round(1.0f * mDeltaY / yThreshold) - mRunningVInc; + int cellXInc = 0; + int cellYInc = 0; + + if (hSpanInc == 0 && vSpanInc == 0) return; + + // Before we change the widget, we clear the occupied cells associated with it. + // The new set of occupied cells is marked below, once the layout params are updated. + mCellLayout.markCellsAsUnoccupiedForView(mWidgetView); + + CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams(); + if (mLeftBorderActive) { + cellXInc = Math.max(-mExpandability[0], hSpanInc); + cellXInc = Math.min(lp.cellHSpan - mMinHSpan, cellXInc); + hSpanInc *= -1; + hSpanInc = Math.min(mExpandability[0], hSpanInc); + hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc); + mRunningHInc -= hSpanInc; + } else if (mRightBorderActive) { + hSpanInc = Math.min(mExpandability[2], hSpanInc); + hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc); + mRunningHInc += hSpanInc; + } + + if (mTopBorderActive) { + cellYInc = Math.max(-mExpandability[1], vSpanInc); + cellYInc = Math.min(lp.cellVSpan - mMinVSpan, cellYInc); + vSpanInc *= -1; + vSpanInc = Math.min(mExpandability[1], vSpanInc); + vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc); + mRunningVInc -= vSpanInc; + } else if (mBottomBorderActive) { + vSpanInc = Math.min(mExpandability[3], vSpanInc); + vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc); + mRunningVInc += vSpanInc; + } + + // Update the widget's dimensions and position according to the deltas computed above + if (mLeftBorderActive || mRightBorderActive) { + lp.cellHSpan += hSpanInc; + lp.cellX += cellXInc; + } + + if (mTopBorderActive || mBottomBorderActive) { + lp.cellVSpan += vSpanInc; + lp.cellY += cellYInc; + } + + try { + mCellLayout.getExpandabilityArrayForView(mWidgetView, mExpandability); + } catch (Exception e) { + System.out.println("Problem!"); + } + + // Update the cells occupied by this widget + mCellLayout.markCellsAsOccupiedForView(mWidgetView); + } + + public void commitResizeForDelta(int deltaX, int deltaY) { + visualizeResizeForDelta(deltaX, deltaY); + + CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams(); + LauncherModel.resizeItemInDatabase(getContext(), mItemInfo, lp.cellX, lp.cellY, + lp.cellHSpan, lp.cellVSpan); + mWidgetView.requestLayout(); + + // Once our widget resizes (hence the post), we want to snap the resize frame to it + post(new Runnable() { + public void run() { + snapToWidget(true); + } + }); + } + + public void snapToWidget(boolean animate) { + final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams(); + + final int newWidth = mWidgetView.getWidth() + 2 * FRAME_MARGIN; + final int newHeight = mWidgetView.getHeight() + 2 * FRAME_MARGIN; + final int newX = mWidgetView.getLeft() - FRAME_MARGIN; + final int newY = mWidgetView.getTop() - FRAME_MARGIN; + if (!animate) { + lp.width = newWidth; + lp.height = newHeight; + lp.x = newX; + lp.y = newY; + mLeftHandle.setAlpha(1.0f); + mRightHandle.setAlpha(1.0f); + mTopHandle.setAlpha(1.0f); + mBottomHandle.setAlpha(1.0f); + requestLayout(); + } else { + PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", lp.width, newWidth); + PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", lp.height, newHeight); + PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX); + PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY); + ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y); + ObjectAnimator leftOa = ObjectAnimator.ofFloat(mLeftHandle, "alpha", 1.0f); + ObjectAnimator rightOa = ObjectAnimator.ofFloat(mRightHandle, "alpha", 1.0f); + ObjectAnimator topOa = ObjectAnimator.ofFloat(mTopHandle, "alpha", 1.0f); + ObjectAnimator bottomOa = ObjectAnimator.ofFloat(mBottomHandle, "alpha", 1.0f); + oa.addUpdateListener(new AnimatorUpdateListener() { + public void onAnimationUpdate(ValueAnimator animation) { + requestLayout(); + } + }); + AnimatorSet set = new AnimatorSet(); + if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) { + set.playTogether(oa, topOa, bottomOa); + } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) { + set.playTogether(oa, leftOa, rightOa); + } else { + set.playTogether(oa, leftOa, rightOa, topOa, bottomOa); + } + + set.setDuration(SNAP_DURATION); + set.start(); + } + } +} |