am 9f8d59ee: Merge change 26714 into eclair
Merge commit '9f8d59eea1bdb3f979aaa8a5bdf9b1bdada7728b' into eclair-plus-aosp * commit '9f8d59eea1bdb3f979aaa8a5bdf9b1bdada7728b': Update RotarySelector to support vertical orientation, and add resolution specific assets (removing old ones).
@@ -18,7 +18,12 @@ package com.android.internal.widget;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.Matrix;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Vibrator;
|
import android.os.Vibrator;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
@@ -38,6 +43,9 @@ import com.android.internal.R;
|
|||||||
* security pattern is set.
|
* security pattern is set.
|
||||||
*/
|
*/
|
||||||
public class RotarySelector extends View {
|
public class RotarySelector extends View {
|
||||||
|
public static final int HORIZONTAL = 0;
|
||||||
|
public static final int VERTICAL = 1;
|
||||||
|
|
||||||
private static final String LOG_TAG = "RotarySelector";
|
private static final String LOG_TAG = "RotarySelector";
|
||||||
private static final boolean DBG = false;
|
private static final boolean DBG = false;
|
||||||
|
|
||||||
@@ -47,15 +55,15 @@ public class RotarySelector extends View {
|
|||||||
private float mDensity;
|
private float mDensity;
|
||||||
|
|
||||||
// UI elements
|
// UI elements
|
||||||
private Drawable mBackground;
|
private Bitmap mBackground;
|
||||||
private Drawable mDimple;
|
private Drawable mDimple;
|
||||||
|
|
||||||
private Drawable mLeftHandleIcon;
|
private Drawable mLeftHandleIcon;
|
||||||
private Drawable mRightHandleIcon;
|
private Drawable mRightHandleIcon;
|
||||||
|
|
||||||
private Drawable mArrowShortLeftAndRight;
|
private Bitmap mArrowShortLeftAndRight;
|
||||||
private Drawable mArrowLongLeft; // Long arrow starting on the left, pointing clockwise
|
private Bitmap mArrowLongLeft; // Long arrow starting on the left, pointing clockwise
|
||||||
private Drawable mArrowLongRight; // Long arrow starting on the right, pointing CCW
|
private Bitmap mArrowLongRight; // Long arrow starting on the right, pointing CCW
|
||||||
|
|
||||||
// positions of the left and right handle
|
// positions of the left and right handle
|
||||||
private int mLeftHandleX;
|
private int mLeftHandleX;
|
||||||
@@ -74,6 +82,12 @@ public class RotarySelector extends View {
|
|||||||
|
|
||||||
private DecelerateInterpolator mInterpolator;
|
private DecelerateInterpolator mInterpolator;
|
||||||
|
|
||||||
|
private Paint mPaint = new Paint();
|
||||||
|
|
||||||
|
// used to rotate the background and arrow assets depending on orientation
|
||||||
|
final Matrix mBgMatrix = new Matrix();
|
||||||
|
final Matrix mArrowMatrix = new Matrix();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the user is currently dragging something.
|
* If the user is currently dragging something.
|
||||||
*/
|
*/
|
||||||
@@ -117,7 +131,6 @@ public class RotarySelector extends View {
|
|||||||
static final int SNAP_BACK_ANIMATION_DURATION_MILLIS = 300;
|
static final int SNAP_BACK_ANIMATION_DURATION_MILLIS = 300;
|
||||||
static final int SPIN_ANIMATION_DURATION_MILLIS = 800;
|
static final int SPIN_ANIMATION_DURATION_MILLIS = 800;
|
||||||
|
|
||||||
private static final boolean DRAW_CENTER_DIMPLE = true;
|
|
||||||
private int mEdgeTriggerThresh;
|
private int mEdgeTriggerThresh;
|
||||||
private int mDimpleWidth;
|
private int mDimpleWidth;
|
||||||
private int mBackgroundWidth;
|
private int mBackgroundWidth;
|
||||||
@@ -137,6 +150,10 @@ public class RotarySelector extends View {
|
|||||||
*/
|
*/
|
||||||
private int mDimplesOfFling = 0;
|
private int mDimplesOfFling = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Either {@link #HORIZONTAL} or {@link #VERTICAL}.
|
||||||
|
*/
|
||||||
|
private int mOrientation;
|
||||||
|
|
||||||
|
|
||||||
public RotarySelector(Context context) {
|
public RotarySelector(Context context) {
|
||||||
@@ -148,28 +165,23 @@ public class RotarySelector extends View {
|
|||||||
*/
|
*/
|
||||||
public RotarySelector(Context context, AttributeSet attrs) {
|
public RotarySelector(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
if (DBG) log("IncomingCallDialWidget constructor...");
|
|
||||||
|
TypedArray a =
|
||||||
|
context.obtainStyledAttributes(attrs, R.styleable.RotarySelector);
|
||||||
|
mOrientation = a.getInt(R.styleable.RotarySelector_orientation, HORIZONTAL);
|
||||||
|
a.recycle();
|
||||||
|
|
||||||
Resources r = getResources();
|
Resources r = getResources();
|
||||||
mDensity = r.getDisplayMetrics().density;
|
mDensity = r.getDisplayMetrics().density;
|
||||||
if (DBG) log("- Density: " + mDensity);
|
if (DBG) log("- Density: " + mDensity);
|
||||||
|
|
||||||
// Assets (all are BitmapDrawables).
|
// Assets (all are BitmapDrawables).
|
||||||
mBackground = r.getDrawable(R.drawable.jog_dial_bg_cropped);
|
mBackground = getBitmapFor(R.drawable.jog_dial_bg);
|
||||||
mDimple = r.getDrawable(R.drawable.jog_dial_dimple);
|
mDimple = r.getDrawable(R.drawable.jog_dial_dimple);
|
||||||
|
|
||||||
mArrowLongLeft = r.getDrawable(R.drawable.jog_dial_arrow_long_left_green);
|
mArrowLongLeft = getBitmapFor(R.drawable.jog_dial_arrow_long_left_green);
|
||||||
mArrowLongRight = r.getDrawable(R.drawable.jog_dial_arrow_long_right_red);
|
mArrowLongRight = getBitmapFor(R.drawable.jog_dial_arrow_long_right_red);
|
||||||
mArrowShortLeftAndRight = r.getDrawable(R.drawable.jog_dial_arrow_short_left_and_right);
|
mArrowShortLeftAndRight = getBitmapFor(R.drawable.jog_dial_arrow_short_left_and_right);
|
||||||
|
|
||||||
// Arrows:
|
|
||||||
// All arrow assets are the same size (they're the full width of
|
|
||||||
// the screen) regardless of which arrows are actually visible.
|
|
||||||
int arrowW = mArrowShortLeftAndRight.getIntrinsicWidth();
|
|
||||||
int arrowH = mArrowShortLeftAndRight.getIntrinsicHeight();
|
|
||||||
mArrowShortLeftAndRight.setBounds(0, 0, arrowW, arrowH);
|
|
||||||
mArrowLongLeft.setBounds(0, 0, arrowW, arrowH);
|
|
||||||
mArrowLongRight.setBounds(0, 0, arrowW, arrowH);
|
|
||||||
|
|
||||||
mInterpolator = new DecelerateInterpolator(1f);
|
mInterpolator = new DecelerateInterpolator(1f);
|
||||||
|
|
||||||
@@ -177,8 +189,8 @@ public class RotarySelector extends View {
|
|||||||
|
|
||||||
mDimpleWidth = mDimple.getIntrinsicWidth();
|
mDimpleWidth = mDimple.getIntrinsicWidth();
|
||||||
|
|
||||||
mBackgroundWidth = mBackground.getIntrinsicWidth();
|
mBackgroundWidth = mBackground.getWidth();
|
||||||
mBackgroundHeight = mBackground.getIntrinsicHeight();
|
mBackgroundHeight = mBackground.getHeight();
|
||||||
mOuterRadius = (int) (mDensity * OUTER_ROTARY_RADIUS_DIP);
|
mOuterRadius = (int) (mDensity * OUTER_ROTARY_RADIUS_DIP);
|
||||||
mInnerRadius = (int) ((OUTER_ROTARY_RADIUS_DIP - ROTARY_STROKE_WIDTH_DIP) * mDensity);
|
mInnerRadius = (int) ((OUTER_ROTARY_RADIUS_DIP - ROTARY_STROKE_WIDTH_DIP) * mDensity);
|
||||||
|
|
||||||
@@ -187,15 +199,35 @@ public class RotarySelector extends View {
|
|||||||
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
|
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Bitmap getBitmapFor(int resId) {
|
||||||
|
return BitmapFactory.decodeResource(getContext().getResources(), resId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||||
super.onSizeChanged(w, h, oldw, oldh);
|
super.onSizeChanged(w, h, oldw, oldh);
|
||||||
|
|
||||||
mLeftHandleX = (int) (EDGE_PADDING_DIP * mDensity) + mDimpleWidth / 2;
|
final int edgePadding = (int) (EDGE_PADDING_DIP * mDensity);
|
||||||
mRightHandleX =
|
mLeftHandleX = edgePadding + mDimpleWidth / 2;
|
||||||
getWidth() - (int) (EDGE_PADDING_DIP * mDensity) - mDimpleWidth / 2;
|
final int length = isHoriz() ? w : h;
|
||||||
|
mRightHandleX = length - edgePadding - mDimpleWidth / 2;
|
||||||
|
mDimpleSpacing = (length / 2) - mLeftHandleX;
|
||||||
|
|
||||||
mDimpleSpacing = (getWidth() / 2) - mLeftHandleX;
|
// bg matrix only needs to be calculated once
|
||||||
|
mBgMatrix.setTranslate(0, 0);
|
||||||
|
if (!isHoriz()) {
|
||||||
|
// set up matrix for translating drawing of background and arrow assets
|
||||||
|
final int left = w - mBackgroundHeight;
|
||||||
|
mBgMatrix.preRotate(-90, 0, 0);
|
||||||
|
mBgMatrix.postTranslate(left, h);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
mBgMatrix.postTranslate(0, h - mBackgroundHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isHoriz() {
|
||||||
|
return mOrientation == HORIZONTAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -252,28 +284,35 @@ public class RotarySelector extends View {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
final int width = MeasureSpec.getSize(widthMeasureSpec); // screen width
|
final int length = isHoriz() ?
|
||||||
|
MeasureSpec.getSize(widthMeasureSpec) :
|
||||||
final int arrowH = mArrowShortLeftAndRight.getIntrinsicHeight();
|
MeasureSpec.getSize(heightMeasureSpec);
|
||||||
final int backgroundH = mBackgroundHeight;
|
final int arrowScrunch = (int) (ARROW_SCRUNCH_DIP * mDensity);
|
||||||
|
final int arrowH = mArrowShortLeftAndRight.getHeight();
|
||||||
|
|
||||||
// by making the height less than arrow + bg, arrow and bg will be scrunched together,
|
// by making the height less than arrow + bg, arrow and bg will be scrunched together,
|
||||||
// overlaying somewhat (though on transparent portions of the drawable).
|
// overlaying somewhat (though on transparent portions of the drawable).
|
||||||
// this works because the arrows are drawn from the top, and the rotary bg is drawn
|
// this works because the arrows are drawn from the top, and the rotary bg is drawn
|
||||||
// from the bottom.
|
// from the bottom.
|
||||||
final int arrowScrunch = (int) (ARROW_SCRUNCH_DIP * mDensity);
|
final int height = mBackgroundHeight + arrowH - arrowScrunch;
|
||||||
setMeasuredDimension(width, backgroundH + arrowH - arrowScrunch);
|
|
||||||
}
|
|
||||||
|
|
||||||
// private Paint mPaint = new Paint();
|
if (isHoriz()) {
|
||||||
|
setMeasuredDimension(length, height);
|
||||||
|
} else {
|
||||||
|
setMeasuredDimension(height, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDraw(Canvas canvas) {
|
protected void onDraw(Canvas canvas) {
|
||||||
super.onDraw(canvas);
|
super.onDraw(canvas);
|
||||||
if (DBG) {
|
|
||||||
log(String.format("onDraw: mAnimating=%s, mRotaryOffsetX=%d, mGrabbedState=%d",
|
final int width = getWidth();
|
||||||
mAnimating, mRotaryOffsetX, mGrabbedState));
|
|
||||||
}
|
// DEBUG: draw bounding box around widget
|
||||||
|
// mPaint.setColor(Color.RED);
|
||||||
|
// mPaint.setStyle(Paint.Style.STROKE);
|
||||||
|
// canvas.drawRect(0, 0, width, getHeight(), mPaint);
|
||||||
|
|
||||||
final int height = getHeight();
|
final int height = getHeight();
|
||||||
|
|
||||||
@@ -283,76 +322,113 @@ public class RotarySelector extends View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Background:
|
// Background:
|
||||||
final int backgroundW = mBackgroundWidth;
|
canvas.drawBitmap(mBackground, mBgMatrix, mPaint);
|
||||||
final int backgroundH = mBackgroundHeight;
|
|
||||||
final int backgroundY = height - backgroundH;
|
|
||||||
if (DBG) log("- Background INTRINSIC: " + backgroundW + " x " + backgroundH);
|
|
||||||
mBackground.setBounds(0, backgroundY,
|
|
||||||
backgroundW, backgroundY + backgroundH);
|
|
||||||
if (DBG) log(" Background BOUNDS: " + mBackground.getBounds());
|
|
||||||
mBackground.draw(canvas);
|
|
||||||
|
|
||||||
|
|
||||||
// Draw the correct arrow(s) depending on the current state:
|
// Draw the correct arrow(s) depending on the current state:
|
||||||
Drawable currentArrow;
|
mArrowMatrix.reset();
|
||||||
switch (mGrabbedState) {
|
switch (mGrabbedState) {
|
||||||
case NOTHING_GRABBED:
|
case NOTHING_GRABBED:
|
||||||
currentArrow = null; //mArrowShortLeftAndRight;
|
//mArrowShortLeftAndRight;
|
||||||
break;
|
break;
|
||||||
case LEFT_HANDLE_GRABBED:
|
case LEFT_HANDLE_GRABBED:
|
||||||
currentArrow = mArrowLongLeft;
|
mArrowMatrix.setTranslate(0, 0);
|
||||||
|
if (!isHoriz()) {
|
||||||
|
mArrowMatrix.preRotate(-90, 0, 0);
|
||||||
|
mArrowMatrix.postTranslate(0, height);
|
||||||
|
}
|
||||||
|
canvas.drawBitmap(mArrowLongLeft, mArrowMatrix, mPaint);
|
||||||
break;
|
break;
|
||||||
case RIGHT_HANDLE_GRABBED:
|
case RIGHT_HANDLE_GRABBED:
|
||||||
currentArrow = mArrowLongRight;
|
mArrowMatrix.setTranslate(0, 0);
|
||||||
|
if (!isHoriz()) {
|
||||||
|
mArrowMatrix.preRotate(-90, 0, 0);
|
||||||
|
// since bg width is > height of screen in landscape mode...
|
||||||
|
mArrowMatrix.postTranslate(0, height + (mBackgroundWidth - height));
|
||||||
|
}
|
||||||
|
canvas.drawBitmap(mArrowLongRight, mArrowMatrix, mPaint);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("invalid mGrabbedState: " + mGrabbedState);
|
throw new IllegalStateException("invalid mGrabbedState: " + mGrabbedState);
|
||||||
}
|
}
|
||||||
if (currentArrow != null) currentArrow.draw(canvas);
|
|
||||||
|
|
||||||
// debug: draw circle that should match the outer arc (good sanity check)
|
final int bgHeight = mBackgroundHeight;
|
||||||
// mPaint.setColor(Color.RED);
|
final int bgTop = isHoriz() ?
|
||||||
// mPaint.setStyle(Paint.Style.STROKE);
|
height - bgHeight:
|
||||||
|
width - bgHeight;
|
||||||
|
// DEBUG: draw circle bounding arc drawable: good sanity check we're doing the math
|
||||||
|
// correctly
|
||||||
// float or = OUTER_ROTARY_RADIUS_DIP * mDensity;
|
// float or = OUTER_ROTARY_RADIUS_DIP * mDensity;
|
||||||
// canvas.drawCircle(getWidth() / 2, or + mBackground.getBounds().top, or, mPaint);
|
// final int vOffset = mBackgroundWidth - height;
|
||||||
|
// final int midX = isHoriz() ?
|
||||||
|
// width / 2 :
|
||||||
|
// mBackgroundWidth / 2 - vOffset;
|
||||||
|
// if (isHoriz()) {
|
||||||
|
// canvas.drawCircle(midX, or + bgTop, or, mPaint);
|
||||||
|
// } else {
|
||||||
|
// canvas.drawCircle(or + bgTop, midX, or, mPaint);
|
||||||
|
// }
|
||||||
|
|
||||||
final int bgTop = mBackground.getBounds().top;
|
// left dimple / icon
|
||||||
{
|
{
|
||||||
final int xOffset = mLeftHandleX + mRotaryOffsetX;
|
final int xOffset = mLeftHandleX + mRotaryOffsetX;
|
||||||
final int drawableY = getYOnArc(
|
final int drawableY = getYOnArc(
|
||||||
mBackground,
|
mBackgroundWidth,
|
||||||
mInnerRadius,
|
mInnerRadius,
|
||||||
mOuterRadius,
|
mOuterRadius,
|
||||||
xOffset);
|
xOffset);
|
||||||
|
if (isHoriz()) {
|
||||||
drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
|
drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
|
||||||
if (mGrabbedState != RIGHT_HANDLE_GRABBED) {
|
if (mGrabbedState != RIGHT_HANDLE_GRABBED) {
|
||||||
drawCentered(mLeftHandleIcon, canvas, xOffset, drawableY + bgTop);
|
drawCentered(mLeftHandleIcon, canvas, xOffset, drawableY + bgTop);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// vertical
|
||||||
|
drawCentered(mDimple, canvas, drawableY + bgTop, height - xOffset);
|
||||||
|
if (mGrabbedState != RIGHT_HANDLE_GRABBED) {
|
||||||
|
drawCentered(mLeftHandleIcon, canvas, drawableY + bgTop, height - xOffset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DRAW_CENTER_DIMPLE) {
|
// center dimple
|
||||||
final int xOffset = getWidth() / 2 + mRotaryOffsetX;
|
{
|
||||||
|
final int xOffset = isHoriz() ?
|
||||||
|
width / 2 + mRotaryOffsetX:
|
||||||
|
height / 2 + mRotaryOffsetX;
|
||||||
final int drawableY = getYOnArc(
|
final int drawableY = getYOnArc(
|
||||||
mBackground,
|
mBackgroundWidth,
|
||||||
mInnerRadius,
|
mInnerRadius,
|
||||||
mOuterRadius,
|
mOuterRadius,
|
||||||
xOffset);
|
xOffset);
|
||||||
|
|
||||||
drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
|
if (isHoriz()) {
|
||||||
|
drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
|
||||||
|
} else {
|
||||||
|
// vertical
|
||||||
|
drawCentered(mDimple, canvas, drawableY + bgTop, height - xOffset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// right dimple / icon
|
||||||
{
|
{
|
||||||
final int xOffset = mRightHandleX + mRotaryOffsetX;
|
final int xOffset = mRightHandleX + mRotaryOffsetX;
|
||||||
final int drawableY = getYOnArc(
|
final int drawableY = getYOnArc(
|
||||||
mBackground,
|
mBackgroundWidth,
|
||||||
mInnerRadius,
|
mInnerRadius,
|
||||||
mOuterRadius,
|
mOuterRadius,
|
||||||
xOffset);
|
xOffset);
|
||||||
|
|
||||||
drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
|
if (isHoriz()) {
|
||||||
if (mGrabbedState != LEFT_HANDLE_GRABBED) {
|
drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
|
||||||
drawCentered(mRightHandleIcon, canvas, xOffset, drawableY + bgTop);
|
if (mGrabbedState != LEFT_HANDLE_GRABBED) {
|
||||||
|
drawCentered(mRightHandleIcon, canvas, xOffset, drawableY + bgTop);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// vertical
|
||||||
|
drawCentered(mDimple, canvas, drawableY + bgTop, height - xOffset);
|
||||||
|
if (mGrabbedState != LEFT_HANDLE_GRABBED) {
|
||||||
|
drawCentered(mRightHandleIcon, canvas, drawableY + bgTop, height - xOffset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,12 +437,16 @@ public class RotarySelector extends View {
|
|||||||
final int halfdimple = mDimpleWidth / 2;
|
final int halfdimple = mDimpleWidth / 2;
|
||||||
while (dimpleLeft > -halfdimple) {
|
while (dimpleLeft > -halfdimple) {
|
||||||
final int drawableY = getYOnArc(
|
final int drawableY = getYOnArc(
|
||||||
mBackground,
|
mBackgroundWidth,
|
||||||
mInnerRadius,
|
mInnerRadius,
|
||||||
mOuterRadius,
|
mOuterRadius,
|
||||||
dimpleLeft);
|
dimpleLeft);
|
||||||
|
|
||||||
drawCentered(mDimple, canvas, dimpleLeft, drawableY + bgTop);
|
if (isHoriz()) {
|
||||||
|
drawCentered(mDimple, canvas, dimpleLeft, drawableY + bgTop);
|
||||||
|
} else {
|
||||||
|
drawCentered(mDimple, canvas, drawableY + bgTop, height - dimpleLeft);
|
||||||
|
}
|
||||||
dimpleLeft -= mDimpleSpacing;
|
dimpleLeft -= mDimpleSpacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,40 +455,43 @@ public class RotarySelector extends View {
|
|||||||
final int rightThresh = mRight + halfdimple;
|
final int rightThresh = mRight + halfdimple;
|
||||||
while (dimpleRight < rightThresh) {
|
while (dimpleRight < rightThresh) {
|
||||||
final int drawableY = getYOnArc(
|
final int drawableY = getYOnArc(
|
||||||
mBackground,
|
mBackgroundWidth,
|
||||||
mInnerRadius,
|
mInnerRadius,
|
||||||
mOuterRadius,
|
mOuterRadius,
|
||||||
dimpleRight);
|
dimpleRight);
|
||||||
|
|
||||||
drawCentered(mDimple, canvas, dimpleRight, drawableY + bgTop);
|
if (isHoriz()) {
|
||||||
|
drawCentered(mDimple, canvas, dimpleRight, drawableY + bgTop);
|
||||||
|
} else {
|
||||||
|
drawCentered(mDimple, canvas, drawableY + bgTop, height - dimpleRight);
|
||||||
|
}
|
||||||
dimpleRight += mDimpleSpacing;
|
dimpleRight += mDimpleSpacing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assuming drawable is a bounding box around a piece of an arc drawn by two concentric circles
|
* Assuming bitmap is a bounding box around a piece of an arc drawn by two concentric circles
|
||||||
* (as the background drawable for the rotary widget is), and given an x coordinate along the
|
* (as the background drawable for the rotary widget is), and given an x coordinate along the
|
||||||
* drawable, return the y coordinate of a point on the arc that is between the two concentric
|
* drawable, return the y coordinate of a point on the arc that is between the two concentric
|
||||||
* circles. The resulting y combined with the incoming x is a point along the circle in
|
* circles. The resulting y combined with the incoming x is a point along the circle in
|
||||||
* between the two concentric circles.
|
* between the two concentric circles.
|
||||||
*
|
*
|
||||||
* @param drawable The drawable.
|
* @param backgroundWidth The width of the asset (the bottom of the box surrounding the arc).
|
||||||
* @param innerRadius The radius of the circle that intersects the drawable at the bottom two
|
* @param innerRadius The radius of the circle that intersects the drawable at the bottom two
|
||||||
* corders of the drawable (top two corners in terms of drawing coordinates).
|
* corders of the drawable (top two corners in terms of drawing coordinates).
|
||||||
* @param outerRadius The radius of the circle who's top most point is the top center of the
|
* @param outerRadius The radius of the circle who's top most point is the top center of the
|
||||||
* drawable (bottom center in terms of drawing coordinates).
|
* drawable (bottom center in terms of drawing coordinates).
|
||||||
* @param x The distance along the x axis of the desired point.
|
* @param x The distance along the x axis of the desired point. @return The y coordinate, in drawing coordinates, that will place (x, y) along the circle
|
||||||
* @return The y coordinate, in drawing coordinates, that will place (x, y) along the circle
|
|
||||||
* in between the two concentric circles.
|
* in between the two concentric circles.
|
||||||
*/
|
*/
|
||||||
private int getYOnArc(Drawable drawable, int innerRadius, int outerRadius, int x) {
|
private int getYOnArc(int backgroundWidth, int innerRadius, int outerRadius, int x) {
|
||||||
|
|
||||||
// the hypotenuse
|
// the hypotenuse
|
||||||
final int halfWidth = (outerRadius - innerRadius) / 2;
|
final int halfWidth = (outerRadius - innerRadius) / 2;
|
||||||
final int middleRadius = innerRadius + halfWidth;
|
final int middleRadius = innerRadius + halfWidth;
|
||||||
|
|
||||||
// the bottom leg of the triangle
|
// the bottom leg of the triangle
|
||||||
final int triangleBottom = (drawable.getIntrinsicWidth() / 2) - x;
|
final int triangleBottom = (backgroundWidth / 2) - x;
|
||||||
|
|
||||||
// "Our offense is like the pythagorean theorem: There is no answer!" - Shaquille O'Neal
|
// "Our offense is like the pythagorean theorem: There is no answer!" - Shaquille O'Neal
|
||||||
final int triangleY =
|
final int triangleY =
|
||||||
@@ -437,8 +520,11 @@ public class RotarySelector extends View {
|
|||||||
}
|
}
|
||||||
mVelocityTracker.addMovement(event);
|
mVelocityTracker.addMovement(event);
|
||||||
|
|
||||||
|
final int height = getHeight();
|
||||||
|
|
||||||
final int eventX = (int) event.getX();
|
final int eventX = isHoriz() ?
|
||||||
|
(int) event.getX():
|
||||||
|
height - ((int) event.getY());
|
||||||
final int hitWindow = mDimpleWidth;
|
final int hitWindow = mDimpleWidth;
|
||||||
|
|
||||||
final int action = event.getAction();
|
final int action = event.getAction();
|
||||||
@@ -468,12 +554,16 @@ public class RotarySelector extends View {
|
|||||||
if (mGrabbedState == LEFT_HANDLE_GRABBED) {
|
if (mGrabbedState == LEFT_HANDLE_GRABBED) {
|
||||||
mRotaryOffsetX = eventX - mLeftHandleX;
|
mRotaryOffsetX = eventX - mLeftHandleX;
|
||||||
invalidate();
|
invalidate();
|
||||||
if (eventX >= getRight() - mEdgeTriggerThresh && !mTriggered) {
|
final int rightThresh = isHoriz() ? getRight() : height;
|
||||||
|
if (eventX >= rightThresh - mEdgeTriggerThresh && !mTriggered) {
|
||||||
mTriggered = true;
|
mTriggered = true;
|
||||||
dispatchTriggerEvent(OnDialTriggerListener.LEFT_HANDLE);
|
dispatchTriggerEvent(OnDialTriggerListener.LEFT_HANDLE);
|
||||||
final VelocityTracker velocityTracker = mVelocityTracker;
|
final VelocityTracker velocityTracker = mVelocityTracker;
|
||||||
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
|
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
|
||||||
final int velocity = Math.max(mMinimumVelocity, (int) velocityTracker.getXVelocity());
|
final int rawVelocity = isHoriz() ?
|
||||||
|
(int) velocityTracker.getXVelocity():
|
||||||
|
-(int) velocityTracker.getYVelocity();
|
||||||
|
final int velocity = Math.max(mMinimumVelocity, rawVelocity);
|
||||||
mDimplesOfFling = Math.max(
|
mDimplesOfFling = Math.max(
|
||||||
8,
|
8,
|
||||||
Math.abs(velocity / mDimpleSpacing));
|
Math.abs(velocity / mDimpleSpacing));
|
||||||
@@ -490,7 +580,10 @@ public class RotarySelector extends View {
|
|||||||
dispatchTriggerEvent(OnDialTriggerListener.RIGHT_HANDLE);
|
dispatchTriggerEvent(OnDialTriggerListener.RIGHT_HANDLE);
|
||||||
final VelocityTracker velocityTracker = mVelocityTracker;
|
final VelocityTracker velocityTracker = mVelocityTracker;
|
||||||
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
|
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
|
||||||
final int velocity = Math.min(-mMinimumVelocity, (int) velocityTracker.getXVelocity());
|
final int rawVelocity = isHoriz() ?
|
||||||
|
(int) velocityTracker.getXVelocity():
|
||||||
|
- (int) velocityTracker.getYVelocity();
|
||||||
|
final int velocity = Math.min(-mMinimumVelocity, rawVelocity);
|
||||||
mDimplesOfFling = Math.max(
|
mDimplesOfFling = Math.max(
|
||||||
8,
|
8,
|
||||||
Math.abs(velocity / mDimpleSpacing));
|
Math.abs(velocity / mDimpleSpacing));
|
||||||
@@ -559,6 +652,7 @@ public class RotarySelector extends View {
|
|||||||
final long millisSoFar = currentAnimationTimeMillis() - mAnimationStartTime;
|
final long millisSoFar = currentAnimationTimeMillis() - mAnimationStartTime;
|
||||||
final long millisLeft = mAnimationDuration - millisSoFar;
|
final long millisLeft = mAnimationDuration - millisSoFar;
|
||||||
final int totalDeltaX = mAnimatingDeltaXStart - mAnimatingDeltaXEnd;
|
final int totalDeltaX = mAnimatingDeltaXStart - mAnimatingDeltaXEnd;
|
||||||
|
final boolean goingRight = totalDeltaX < 0;
|
||||||
if (DBG) log("millisleft for animating: " + millisLeft);
|
if (DBG) log("millisleft for animating: " + millisLeft);
|
||||||
if (millisLeft <= 0) {
|
if (millisLeft <= 0) {
|
||||||
reset();
|
reset();
|
||||||
@@ -569,13 +663,17 @@ public class RotarySelector extends View {
|
|||||||
mInterpolator.getInterpolation((float) millisSoFar / mAnimationDuration);
|
mInterpolator.getInterpolation((float) millisSoFar / mAnimationDuration);
|
||||||
final int dx = (int) (totalDeltaX * (1 - interpolation));
|
final int dx = (int) (totalDeltaX * (1 - interpolation));
|
||||||
mRotaryOffsetX = mAnimatingDeltaXEnd + dx;
|
mRotaryOffsetX = mAnimatingDeltaXEnd + dx;
|
||||||
|
|
||||||
|
// once we have gone far enough to animate the current buttons off screen, we start
|
||||||
|
// wrapping the offset back to the other side so that when the animation is finished,
|
||||||
|
// the buttons will come back into their original places.
|
||||||
if (mDimplesOfFling > 0) {
|
if (mDimplesOfFling > 0) {
|
||||||
if (mRotaryOffsetX < 4 * mDimpleSpacing) {
|
if (!goingRight && mRotaryOffsetX < 3 * mDimpleSpacing) {
|
||||||
// wrap around on fling left
|
// wrap around on fling left
|
||||||
mRotaryOffsetX += (4 + mDimplesOfFling - 4) * mDimpleSpacing;
|
mRotaryOffsetX += mDimplesOfFling * mDimpleSpacing;
|
||||||
} else if (mRotaryOffsetX > 4 * mDimpleSpacing) {
|
} else if (goingRight && mRotaryOffsetX > 3 * mDimpleSpacing) {
|
||||||
// wrap around on fling right
|
// wrap around on fling right
|
||||||
mRotaryOffsetX -= (4 + mDimplesOfFling - 4) * mDimpleSpacing;
|
mRotaryOffsetX -= mDimplesOfFling * mDimpleSpacing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
invalidate();
|
invalidate();
|
||||||
|
|||||||
BIN
core/res/res/drawable-hdpi/ic_jog_dial_sound_off.png
Executable file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
core/res/res/drawable-hdpi/ic_jog_dial_sound_on.png
Executable file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
core/res/res/drawable-hdpi/ic_jog_dial_unlock.png
Executable file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
core/res/res/drawable-hdpi/jog_dial_arrow_long_left_green.png
Executable file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
core/res/res/drawable-hdpi/jog_dial_arrow_long_left_yellow.png
Executable file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
core/res/res/drawable-hdpi/jog_dial_arrow_long_middle_yellow.png
Executable file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
core/res/res/drawable-hdpi/jog_dial_arrow_long_right_red.png
Executable file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
core/res/res/drawable-hdpi/jog_dial_arrow_long_right_yellow.png
Executable file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
core/res/res/drawable-hdpi/jog_dial_arrow_short_left.png
Executable file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
core/res/res/drawable-hdpi/jog_dial_arrow_short_left_and_right.png
Executable file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
core/res/res/drawable-hdpi/jog_dial_arrow_short_right.png
Executable file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
core/res/res/drawable-hdpi/jog_dial_bg.png
Executable file
|
After Width: | Height: | Size: 21 KiB |
BIN
core/res/res/drawable-hdpi/jog_dial_dimple.png
Executable file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
core/res/res/drawable-mdpi/ic_jog_dial_sound_off.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
core/res/res/drawable-mdpi/ic_jog_dial_sound_on.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
0
core/res/res/drawable/ic_jog_dial_unlock.png → core/res/res/drawable-mdpi/ic_jog_dial_unlock.png
Normal file → Executable file
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
0
core/res/res/drawable/jog_dial_arrow_long_left_green.png → core/res/res/drawable-mdpi/jog_dial_arrow_long_left_green.png
Normal file → Executable file
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
0
core/res/res/drawable/jog_dial_arrow_long_left_yellow.png → core/res/res/drawable-mdpi/jog_dial_arrow_long_left_yellow.png
Normal file → Executable file
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
0
core/res/res/drawable/jog_dial_arrow_long_middle_yellow.png → core/res/res/drawable-mdpi/jog_dial_arrow_long_middle_yellow.png
Normal file → Executable file
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
0
core/res/res/drawable/jog_dial_arrow_long_right_red.png → core/res/res/drawable-mdpi/jog_dial_arrow_long_right_red.png
Normal file → Executable file
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
0
core/res/res/drawable/jog_dial_arrow_long_right_yellow.png → core/res/res/drawable-mdpi/jog_dial_arrow_long_right_yellow.png
Normal file → Executable file
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
0
core/res/res/drawable/jog_dial_arrow_short_left.png → core/res/res/drawable-mdpi/jog_dial_arrow_short_left.png
Normal file → Executable file
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
0
core/res/res/drawable/jog_dial_arrow_short_right.png → core/res/res/drawable-mdpi/jog_dial_arrow_short_right.png
Normal file → Executable file
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
BIN
core/res/res/drawable-mdpi/jog_dial_bg.png
Executable file
|
After Width: | Height: | Size: 13 KiB |
0
core/res/res/drawable/jog_dial_dimple.png → core/res/res/drawable-mdpi/jog_dial_dimple.png
Normal file → Executable file
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 16 KiB |
145
core/res/res/layout/keyguard_screen_rotary_unlock_land.xml
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
**
|
||||||
|
** Copyright 2009, The Android Open Source Project
|
||||||
|
**
|
||||||
|
** Licensed under the Apache License, Version 2.0 (the "License")
|
||||||
|
** you may not use this file except in compliance with the License.
|
||||||
|
** You may obtain a copy of the License at
|
||||||
|
**
|
||||||
|
** http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
**
|
||||||
|
** Unless required by applicable law or agreed to in writing, software
|
||||||
|
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
** See the License for the specific language governing permissions and
|
||||||
|
** limitations under the License.
|
||||||
|
*/
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- This is the general lock screen which shows information about the
|
||||||
|
state of the device, as well as instructions on how to get past it
|
||||||
|
depending on the state of the device.-->
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:rotaryunlock="http://schemas.android.com/apk/res/com.android.rotaryunlock"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:id="@+id/root"
|
||||||
|
>
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:background="#A0000000"
|
||||||
|
>
|
||||||
|
|
||||||
|
<!-- left side -->
|
||||||
|
<RelativeLayout
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="0dip"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:layout_weight="1.0"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/carrier"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_marginTop="20dip"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/time"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/carrier"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_marginTop="25dip"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
|
android:textSize="55sp"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/date"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/time"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_marginTop="-12dip"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/divider"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="1dip"
|
||||||
|
android:layout_marginTop="10dip"
|
||||||
|
android:layout_below="@id/date"
|
||||||
|
android:background="@android:drawable/divider_horizontal_dark"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/status1"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/divider"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_marginTop="6dip"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:drawablePadding="4dip"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/status2"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/status1"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_marginTop="6dip"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:drawablePadding="4dip"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/screenLocked"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/status2"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_marginTop="12dip"
|
||||||
|
/>
|
||||||
|
<!-- emergency call button shown when sim is missing or PUKd -->
|
||||||
|
<Button
|
||||||
|
android:id="@+id/emergencyCallButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/screenLocked"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_marginTop="24dip"
|
||||||
|
android:drawableLeft="@drawable/ic_emergency"
|
||||||
|
android:drawablePadding="8dip"
|
||||||
|
/>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- right side -->
|
||||||
|
<com.android.internal.widget.RotarySelector
|
||||||
|
android:id="@+id/rotary"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
@@ -2295,6 +2295,14 @@
|
|||||||
<attr name="layout_scale" format="float" />
|
<attr name="layout_scale" format="float" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
|
<!-- attributes for internal rotary widget used in lock screen and phone app
|
||||||
|
@hide -->
|
||||||
|
<declare-styleable name="RotarySelector">
|
||||||
|
<!-- Use "horizontal" or "vertical". The default is horizontal. -->
|
||||||
|
<attr name="orientation" />
|
||||||
|
</declare-styleable>
|
||||||
|
|
||||||
|
|
||||||
<!-- ========================= -->
|
<!-- ========================= -->
|
||||||
<!-- Drawable class attributes -->
|
<!-- Drawable class attributes -->
|
||||||
<!-- ========================= -->
|
<!-- ========================= -->
|
||||||
|
|||||||