aboutsummaryrefslogtreecommitdiff
path: root/RotaryPlayground
diff options
context:
space:
mode:
authorYabin Huang <yabinh@google.com>2020-05-15 16:50:17 -0700
committerYabin Huang <yabinh@google.com>2020-05-19 11:36:46 -0700
commit56e5ab553a063664118d8f55ab6ac9d2d6e75be5 (patch)
tree5852a3d4105d03d3bfb6b0cbe7fd3301a8fe3bd9 /RotaryPlayground
parentb5b8a5d6a783e12ca0ee06e7770b94dae44a1d9a (diff)
downloadtests-56e5ab553a063664118d8f55ab6ac9d2d6e75be5.tar.gz
Exit direct manipulation mode when the fragment is not active
This is to prevent the app stuck in DM mode. This CL also refactors the fragmet to allow to initialize multiple direct manipulation views easily. Fixes: 156787734 Test: manual Change-Id: I63c78c897cb87c78c2883eed0b726049dce76884
Diffstat (limited to 'RotaryPlayground')
-rw-r--r--RotaryPlayground/src/com/android/car/rotaryplayground/RotaryDirectManipulationWidgets.java176
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);
}
}