diff options
author | Yabin Huang <yabinh@google.com> | 2020-05-19 20:03:29 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-05-19 20:03:29 +0000 |
commit | 653bdf987bcf2e2bb7e94288f52eba06cc5d4e38 (patch) | |
tree | eaba452e9bdf6951067f439077f9ea0dbf2b6e26 | |
parent | 26038d631c5e4a7fa99af86040ba109c1b6b5179 (diff) | |
parent | 56e5ab553a063664118d8f55ab6ac9d2d6e75be5 (diff) | |
download | tests-653bdf987bcf2e2bb7e94288f52eba06cc5d4e38.tar.gz |
Merge "Exit direct manipulation mode when the fragment is not active" into rvc-dev
-rw-r--r-- | RotaryPlayground/src/com/android/car/rotaryplayground/RotaryDirectManipulationWidgets.java | 176 |
1 files changed, 109 insertions, 67 deletions
diff --git a/RotaryPlayground/src/com/android/car/rotaryplayground/RotaryDirectManipulationWidgets.java b/RotaryPlayground/src/com/android/car/rotaryplayground/RotaryDirectManipulationWidgets.java index fb02105..fc99676 100644 --- a/RotaryPlayground/src/com/android/car/rotaryplayground/RotaryDirectManipulationWidgets.java +++ b/RotaryPlayground/src/com/android/car/rotaryplayground/RotaryDirectManipulationWidgets.java @@ -32,8 +32,8 @@ import com.android.car.ui.utils.DirectManipulationHelper; /** * Fragment that demos rotary interactions directly manipulating the state of UI widgets such as a - * {@link android.widget.SeekBar}, {@link android.widget.DatePicker}, and - * {@link android.widget.RadialTimePickerView}. + * {@link android.widget.SeekBar}, {@link android.widget.DatePicker}, + * {@link android.widget.RadialTimePickerView}, and {@link DirectManipulationView}. */ public class RotaryDirectManipulationWidgets extends Fragment { // TODO(agathaman): refactor a common class that takes in a fragment xml id and inflates it, to @@ -45,105 +45,147 @@ public class RotaryDirectManipulationWidgets extends Fragment { /** How many pixels do we want to zoom the {@link DirectManipulationView} for a rotation. */ private static final float DIRECT_MANIPULATION_VIEW_PX_PER_ROTATION = 10f; - /** Background color of {@link DirectManipulationView} when it's in direct manipulation mode. */ + /** Background color of a view when it's in direct manipulation mode. */ private static final int BACKGROUND_COLOR_IN_DIRECT_MANIPULATION_MODE = Color.BLUE; - /** - * Background color of {@link DirectManipulationView} when it's not in direct manipulation - * mode. - */ + /** Background color of a view when it's not in direct manipulation mode. */ private static final int BACKGROUND_COLOR_NOT_IN_DIRECT_MANIPULATION_MODE = Color.TRANSPARENT; - /** Whether any view in this Fragment is in direct manipulation mode. */ - private boolean mInDirectManipulationMode; + /** The view that is in direct manipulation mode, or null if none. */ + private View mViewInDirectManipulationMode; @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.rotary_direct_manipulation, container, false); - DirectManipulationView directManipulationView = - view.findViewById(R.id.direct_manipulation_view); - initDirectManipulationView(directManipulationView); + DirectManipulationView dmv = view.findViewById(R.id.direct_manipulation_view); + initDirectManipulationMode(dmv, /* handleNudge= */ true, /* handleRotate= */ true); return view; } + @Override + public void onPause() { + if (mViewInDirectManipulationMode != null) { + // To ensure that the user doesn't get stuck in direct manipulation mode, disable direct + // manipulation mode when the fragment is not interactive (e.g., a dialog shows up). + enableDirectManipulationMode(mViewInDirectManipulationMode, false); + } + super.onPause(); + } + /** - * Initializes the {@link DirectManipulationView} so that it can enter/exit direct manipulation - * mode and interact with the rotary controller directly. In direct manipulation mode, the - * circle of the DirectManipulationView can move when the controller nudges, and the circle of - * the DirectManipulationView can zoom when the controller rotates. + * Initializes the given view so that it can enter/exit direct manipulation mode and interact + * with the rotary controller directly. + * + * @param dmv the view to enable direct manipulation mode + * @param handleNudge whether to handle controller nudge in direct manipulation mode + * @param handleRotate whether to handle controller rotate in direct manipulation mode */ - private void initDirectManipulationView(@NonNull DirectManipulationView dmv) { + private void initDirectManipulationMode( + @NonNull View dmv, boolean handleNudge, boolean handleRotate) { dmv.setOnKeyListener((view, keyCode, keyEvent) -> { boolean isActionUp = keyEvent.getAction() == KeyEvent.ACTION_UP; switch (keyCode) { // Always consume KEYCODE_DPAD_CENTER and KEYCODE_BACK event. case KeyEvent.KEYCODE_DPAD_CENTER: - if (!mInDirectManipulationMode && isActionUp) { - mInDirectManipulationMode = true; - dmv.setBackgroundColor(BACKGROUND_COLOR_IN_DIRECT_MANIPULATION_MODE); - dmv.invalidate(); - DirectManipulationHelper.enableDirectManipulationMode(dmv, true); + if (mViewInDirectManipulationMode == null && isActionUp) { + enableDirectManipulationMode(dmv, true); } return true; case KeyEvent.KEYCODE_BACK: - if (mInDirectManipulationMode && isActionUp) { - mInDirectManipulationMode = false; - dmv.setBackgroundColor(BACKGROUND_COLOR_NOT_IN_DIRECT_MANIPULATION_MODE); - dmv.invalidate(); - DirectManipulationHelper.enableDirectManipulationMode(dmv, false); + if (mViewInDirectManipulationMode != null && isActionUp) { + enableDirectManipulationMode(dmv, false); } return true; - // Consume controller nudge event (KEYCODE_DPAD_UP, KEYCODE_DPAD_DOWN, - // KEYCODE_DPAD_LEFT, or KEYCODE_DPAD_RIGHT) only when in direct manipulation mode. - // When handling nudge event, move the circle of the DirectManipulationView. + // Consume nudge event if the view handles controller nudge in direct manipulation + // mode. case KeyEvent.KEYCODE_DPAD_UP: - if (!mInDirectManipulationMode) { - return false; - } - if (isActionUp) { - dmv.move(0f, -DIRECT_MANIPULATION_VIEW_PX_PER_NUDGE); - } - return true; case KeyEvent.KEYCODE_DPAD_DOWN: - if (!mInDirectManipulationMode) { - return false; - } - if (isActionUp) { - dmv.move(0f, DIRECT_MANIPULATION_VIEW_PX_PER_NUDGE); - } - return true; case KeyEvent.KEYCODE_DPAD_LEFT: - if (!mInDirectManipulationMode) { - return false; - } - if (isActionUp) { - dmv.move(-DIRECT_MANIPULATION_VIEW_PX_PER_NUDGE, 0f); - } - return true; case KeyEvent.KEYCODE_DPAD_RIGHT: - if (!mInDirectManipulationMode) { - return false; - } - if (isActionUp) { - dmv.move(DIRECT_MANIPULATION_VIEW_PX_PER_NUDGE, 0f); - } - return true; + return handleNudge? handleNudgeEvent(keyEvent) : false; // Don't consume other key events. default: return false; } }); - // When in direct manipulation mode, zoom the circle of the DirectManipulationView on - // controller rotate event. - dmv.setOnGenericMotionListener(((view, motionEvent) -> { - if (!mInDirectManipulationMode) { - return false; - } - float scroll = motionEvent.getAxisValue(MotionEvent.AXIS_SCROLL); - dmv.zoom(DIRECT_MANIPULATION_VIEW_PX_PER_ROTATION * scroll); + // Consume rotate event if the view handles controller rotate in direct manipulation mode. + if (handleRotate) { + dmv.setOnGenericMotionListener(((view, motionEvent) -> { + float scroll = motionEvent.getAxisValue(MotionEvent.AXIS_SCROLL); + return handleRotateEvent(scroll); + })); + } + } + + private void enableDirectManipulationMode(@NonNull View view, boolean enable) { + view.setBackgroundColor(enable + ? BACKGROUND_COLOR_IN_DIRECT_MANIPULATION_MODE + : BACKGROUND_COLOR_NOT_IN_DIRECT_MANIPULATION_MODE); + view.invalidate(); + DirectManipulationHelper.enableDirectManipulationMode(view, enable); + mViewInDirectManipulationMode = enable ? view : null; + } + + /** Handles controller nudge event. Returns whether the event was consumed. */ + private boolean handleNudgeEvent(KeyEvent keyEvent) { + if (mViewInDirectManipulationMode == null) { + return false; + } + if (keyEvent.getAction() != KeyEvent.ACTION_UP) { return true; - })); + } + int keyCode = keyEvent.getKeyCode(); + if (mViewInDirectManipulationMode instanceof DirectManipulationView) { + DirectManipulationView dmv = (DirectManipulationView) mViewInDirectManipulationMode; + handleNudgeEvent(dmv, keyCode); + return true; + } + + // TODO: support other views. + + return true; + } + + /** Handles controller rotate event. Returns whether the event was consumed. */ + private boolean handleRotateEvent(float scroll) { + if (mViewInDirectManipulationMode == null) { + return false; + } + if (mViewInDirectManipulationMode instanceof DirectManipulationView) { + DirectManipulationView dmv = (DirectManipulationView) mViewInDirectManipulationMode; + handleRotateEvent(dmv, scroll); + return true; + } + + // TODO: support other views. + + return true; + } + + /** Moves the circle of the DirectManipulationView when the controller nudges. */ + private void handleNudgeEvent(@NonNull DirectManipulationView dmv, int keyCode) { + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_UP: + dmv.move(0f, -DIRECT_MANIPULATION_VIEW_PX_PER_NUDGE); + return; + case KeyEvent.KEYCODE_DPAD_DOWN: + dmv.move(0f, DIRECT_MANIPULATION_VIEW_PX_PER_NUDGE); + return; + case KeyEvent.KEYCODE_DPAD_LEFT: + dmv.move(-DIRECT_MANIPULATION_VIEW_PX_PER_NUDGE, 0f); + return; + case KeyEvent.KEYCODE_DPAD_RIGHT: + dmv.move(DIRECT_MANIPULATION_VIEW_PX_PER_NUDGE, 0f); + return; + default: + throw new IllegalArgumentException("Invalid keycode :" + keyCode); + } + } + + /** Zooms the circle of the DirectManipulationView when the controller rotates. */ + private void handleRotateEvent(@NonNull DirectManipulationView dmv, float scroll) { + dmv.zoom(DIRECT_MANIPULATION_VIEW_PX_PER_ROTATION * scroll); } } |