diff options
author | Doris Liu <tianliu@google.com> | 2014-02-21 11:12:08 -0800 |
---|---|---|
committer | Doris Liu <tianliu@google.com> | 2014-02-22 11:30:53 -0800 |
commit | 6ababe9379ecee4056a415085e28e7eb5e1249bf (patch) | |
tree | c6a02e2c18625424fe8c1b129b04d41dcf174194 | |
parent | ab2cfcf7bfa5969f60f6a84fd27bb7041dde1c45 (diff) | |
download | android_packages_apps_Camera2-6ababe9379ecee4056a415085e28e7eb5e1249bf.tar.gz android_packages_apps_Camera2-6ababe9379ecee4056a415085e28e7eb5e1249bf.tar.bz2 android_packages_apps_Camera2-6ababe9379ecee4056a415085e28e7eb5e1249bf.zip |
Add a pressed state on mode drawer items
Bug: 13097259
Change-Id: I63ba6a8200d69b451081b3ece8e8b71123b58a6e
-rw-r--r-- | res/drawable/mode_icon_highlight.xml | 2 | ||||
-rw-r--r-- | src/com/android/camera/ui/ModeListView.java | 196 | ||||
-rw-r--r-- | src/com/android/camera/ui/ModeSelectorItem.java | 43 |
3 files changed, 176 insertions, 65 deletions
diff --git a/res/drawable/mode_icon_highlight.xml b/res/drawable/mode_icon_highlight.xml index f9e3d72e9..c5a4e9106 100644 --- a/res/drawable/mode_icon_highlight.xml +++ b/res/drawable/mode_icon_highlight.xml @@ -19,7 +19,7 @@ android:shape="ring" android:thickness="3dp" android:useLevel="false" - android:innerRadius="21dp" > + android:innerRadius="25dp" > <solid android:color="@color/mode_selector_icon_background"/> diff --git a/src/com/android/camera/ui/ModeListView.java b/src/com/android/camera/ui/ModeListView.java index 9e0d9fd7f..c2fddc6db 100644 --- a/src/com/android/camera/ui/ModeListView.java +++ b/src/com/android/camera/ui/ModeListView.java @@ -157,6 +157,8 @@ public class ModeListView extends FrameLayout } }; private boolean mAdjustPositionWhenUncoveredPreviewAreaChanges = false; + private View mChildViewTouched = null; + private MotionEvent mLastChildTouchEvent = null; @Override public void onPreviewAreaSizeChanged(RectF previewArea) { @@ -305,68 +307,11 @@ public class ModeListView extends FrameLayout return false; } - // Ignore the tap if it happens outside of the mode list linear layout. - float x = ev.getX() - mListView.getX(); - float y = ev.getY() - mListView.getY(); - if (x < 0 || x > mListView.getWidth() || y < 0 || y > mListView.getHeight()) { + // If the tap is not inside the mode drawer area, snap back. + if(!isTouchInsideList(ev)) { snapBack(true); return false; } - - int index = getFocusItem(ev.getX(), ev.getY()); - // Validate the selection - if (index != NO_ITEM_SELECTED) { - final int modeId = getModeIndex(index); - // Un-highlight all the modes. - for (int i = 0; i < mModeSelectorItems.length; i++) { - mModeSelectorItems[i].setHighlighted(false); - } - // Select the focused item. - mModeSelectorItems[index].setSelected(true); - mState = MODE_SELECTED; - PeepholeAnimationEffect effect = new PeepholeAnimationEffect(); - effect.setSize(mWidth, mHeight); - effect.setAnimationEndAction(new Runnable() { - @Override - public void run() { - setVisibility(INVISIBLE); - mCurrentEffect = null; - snapBack(false); - } - }); - - // Calculate the position of the icon in the selected item, and - // start animation from that position. - int[] location = new int[2]; - // Gets icon's center position in relative to the window. - mModeSelectorItems[index].getIconCenterLocationInWindow(location); - int iconX = location[0]; - int iconY = location[1]; - // Gets current view's top left position relative to the window. - getLocationInWindow(location); - // Calculate icon location relative to this view - iconX -= location[0]; - iconY -= location[1]; - - effect.setAnimationStartingPosition(iconX, iconY); - if (mScreenShotProvider != null) { - effect.setBackground(mScreenShotProvider - .getPreviewFrame(PREVIEW_DOWN_SAMPLE_FACTOR), mPreviewArea); - effect.setBackgroundOverlay(mScreenShotProvider.getPreviewOverlayAndControls()); - } - mCurrentEffect = effect; - invalidate(); - - // Post mode selection runnable to the end of the message queue - // so that current UI changes can finish before mode initialization - // clogs up UI thread. - post(new Runnable() { - @Override - public void run() { - onModeSelected(modeId); - } - }); - } return true; } @@ -378,6 +323,82 @@ public class ModeListView extends FrameLayout } }; + /** + * Gets called when a mode item in the mode drawer is clicked. + * + * @param selectedItem the item being clicked + */ + private void onItemSelected(ModeSelectorItem selectedItem) { + + final int modeId = selectedItem.getModeId(); + // Un-highlight all the modes. + for (int i = 0; i < mModeSelectorItems.length; i++) { + mModeSelectorItems[i].setHighlighted(false); + mModeSelectorItems[i].setSelected(false); + } + // Select the focused item. + selectedItem.setSelected(true); + mState = MODE_SELECTED; + PeepholeAnimationEffect effect = new PeepholeAnimationEffect(); + effect.setSize(mWidth, mHeight); + effect.setAnimationEndAction(new Runnable() { + @Override + public void run() { + setVisibility(INVISIBLE); + mCurrentEffect = null; + snapBack(false); + } + }); + + // Calculate the position of the icon in the selected item, and + // start animation from that position. + int[] location = new int[2]; + // Gets icon's center position in relative to the window. + selectedItem.getIconCenterLocationInWindow(location); + int iconX = location[0]; + int iconY = location[1]; + // Gets current view's top left position relative to the window. + getLocationInWindow(location); + // Calculate icon location relative to this view + iconX -= location[0]; + iconY -= location[1]; + + effect.setAnimationStartingPosition(iconX, iconY); + if (mScreenShotProvider != null) { + effect.setBackground(mScreenShotProvider + .getPreviewFrame(PREVIEW_DOWN_SAMPLE_FACTOR), mPreviewArea); + effect.setBackgroundOverlay(mScreenShotProvider.getPreviewOverlayAndControls()); + } + mCurrentEffect = effect; + invalidate(); + + // Post mode selection runnable to the end of the message queue + // so that current UI changes can finish before mode initialization + // clogs up UI thread. + post(new Runnable() { + @Override + public void run() { + onModeSelected(modeId); + } + }); + } + + /** + * Checks whether a touch event is inside of the bounds of the mode list. + * + * @param ev touch event to be checked + * @return whether the touch is inside the bounds of the mode list + */ + private boolean isTouchInsideList(MotionEvent ev) { + // Ignore the tap if it happens outside of the mode list linear layout. + float x = ev.getX() - mListView.getX(); + float y = ev.getY() - mListView.getY(); + if (x < 0 || x > mListView.getWidth() || y < 0 || y > mListView.getHeight()) { + return false; + } + return true; + } + public ModeListView(Context context, AttributeSet attrs) { super(context, attrs); mGestureDetector = new GestureDetector(context, mOnGestureListener); @@ -476,7 +497,7 @@ public class ModeListView extends FrameLayout .getSystemService(Context.LAYOUT_INFLATER_SERVICE); mListView = (LinearLayout) findViewById(R.id.mode_list); for (int i = 0; i < mTotalModes; i++) { - ModeSelectorItem selectorItem = + final ModeSelectorItem selectorItem = (ModeSelectorItem) inflater.inflate(R.layout.mode_selector, null); mListView.addView(selectorItem); // Sets the top padding of the top item to 0. @@ -503,6 +524,13 @@ public class ModeListView extends FrameLayout // Set content description (for a11y) selectorItem.setContentDescription(CameraUtil .getCameraModeContentDescription(modeId, getContext())); + selectorItem.setModeId(modeId); + selectorItem.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + onItemSelected(selectorItem); + } + }); mModeSelectorItems[i] = selectorItem; } @@ -567,6 +595,13 @@ public class ModeListView extends FrameLayout if (mState == FULLY_SHOWN) { mFocusItem = NO_ITEM_SELECTED; setSwipeMode(false); + // If the down event happens inside the mode list, find out which + // mode item is being touched and forward all the subsequent touch + // events to that mode item for its pressed state and click handling. + if (isTouchInsideList(ev)) { + mChildViewTouched = mModeSelectorItems[getFocusItem(ev.getX(), ev.getY())]; + } + } else { mFocusItem = getFocusItem(ev.getX(), ev.getY()); setSwipeMode(true); @@ -577,17 +612,39 @@ public class ModeListView extends FrameLayout setSwipeMode(true); } + forwardTouchEventToChild(ev); // Pass all touch events to gesture detector for gesture handling. mGestureDetector.onTouchEvent(ev); if (ev.getActionMasked() == MotionEvent.ACTION_UP || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) { snap(); mFocusItem = NO_ITEM_SELECTED; + // Reset the touch forward recipient at the end of a touch event series, + // i.e. when an up or a cancel event is received. + mChildViewTouched = null; } return true; } /** + * Forward touch events to a recipient child view. Before feeding the motion + * event into the child view, the event needs to be converted in child view's + * coordinates. + */ + private void forwardTouchEventToChild(MotionEvent ev) { + if (mChildViewTouched != null) { + float x = ev.getX() - mListView.getX(); + float y = ev.getY() - mListView.getY(); + x -= mChildViewTouched.getLeft(); + y -= mChildViewTouched.getTop(); + + mLastChildTouchEvent = MotionEvent.obtain(ev); + mLastChildTouchEvent.setLocation(x, y); + mChildViewTouched.onTouchEvent(mLastChildTouchEvent); + } + } + + /** * Sets the swipe mode to indicate whether this is a swiping in * or out, and therefore we can have different animations. * @@ -718,7 +775,7 @@ public class ModeListView extends FrameLayout // Find parent mode in the nav drawer. for (int i = 0; i < mSupportedModes.size(); i++) { if (mSupportedModes.get(i) == parentMode) { - mModeSelectorItems[i].setHighlighted(true); + mModeSelectorItems[i].setSelected(true); } } } @@ -885,6 +942,10 @@ public class ModeListView extends FrameLayout // background should be 50% transparent. int maxVisibleWidth = mModeSelectorItems[0].getMaxVisibleWidth(); focusItemWidth = Math.min(maxVisibleWidth, focusItemWidth); + if (focusItemWidth != maxVisibleWidth) { + // No longer full screen. + cancelForwardingTouchEvent(); + } float openRatio = (float) focusItemWidth / maxVisibleWidth; setBackgroundAlpha((int) (BACKGROUND_TRANSPARENTCY * openRatio)); if (mModeListOpenListener != null) { @@ -895,6 +956,19 @@ public class ModeListView extends FrameLayout } } + /** + * Cancels the touch event forwarding by sending a cancel event to the recipient + * view and resetting the touch forward recipient to ensure no more events + * can be forwarded in the current series of the touch events. + */ + private void cancelForwardingTouchEvent() { + if (mChildViewTouched != null) { + mLastChildTouchEvent.setAction(MotionEvent.ACTION_CANCEL); + mChildViewTouched.onTouchEvent(mLastChildTouchEvent); + mChildViewTouched = null; + } + } + @Override public void onWindowVisibilityChanged(int visibility) { super.onWindowVisibilityChanged(visibility); diff --git a/src/com/android/camera/ui/ModeSelectorItem.java b/src/com/android/camera/ui/ModeSelectorItem.java index 0025e538f..eeb74d312 100644 --- a/src/com/android/camera/ui/ModeSelectorItem.java +++ b/src/com/android/camera/ui/ModeSelectorItem.java @@ -21,6 +21,7 @@ import android.graphics.Canvas; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.util.AttributeSet; +import android.view.MotionEvent; import android.widget.FrameLayout; import android.widget.TextView; @@ -58,10 +59,12 @@ class ModeSelectorItem extends FrameLayout { private int mWidth; private int mDefaultBackgroundColor; private int mDefaultTextColor; + private int mModeId; public ModeSelectorItem(Context context, AttributeSet attrs) { super(context, attrs); setWillNotDraw(false); + setClickable(true); mMinVisibleWidth = getResources() .getDimensionPixelSize(R.dimen.mode_selector_icon_block_width); } @@ -88,15 +91,33 @@ class ModeSelectorItem extends FrameLayout { } public void setHighlighted(boolean highlighted) { - // TODO: Remove the highlight logic if UX design on selection doesn't change - // within a week. - mIcon.setSelected(highlighted); + mIcon.setHighlighted(highlighted); } public void setSelected(boolean selected) { mIcon.setSelected(selected); } + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + // Do not dispatch any touch event, so that all the events that are received + // in onTouchEvent() are only through forwarding. + return false; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + super.onTouchEvent(ev); + return false; + } + + @Override + public void setPressed(boolean pressed) { + super.setPressed(pressed); + // When pressed state changes, highlight the icon. + mIcon.setHighlighted(pressed); + } + /** * When swiping in, we truncate the end of the item if the visible width * is not enough to show the whole item. When swiping out, we truncate the @@ -231,4 +252,20 @@ class ModeSelectorItem extends FrameLayout { loc[0] += mMinVisibleWidth / 2; loc[1] += mMinVisibleWidth / 2; } + + /** + * Sets the mode id of the current item. + * + * @param modeId id of the mode represented by current item. + */ + public void setModeId(int modeId) { + mModeId = modeId; + } + + /** + * Gets the mode id of the current item. + */ + public int getModeId() { + return mModeId; + } } |