aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPardis Beikzadeh <pardis@google.com>2020-06-02 14:05:15 -0700
committerPardis Beikzadeh <pardis@google.com>2020-06-11 19:54:25 -0700
commitb4d094e1c6c5b9bdbf0f2476ba47f865b91e3c13 (patch)
tree9bf852e0743cb4c93377bdead211609c76f992a7
parent97c16099017c074fc8292c17959966a5e4e26f61 (diff)
downloadtests-b4d094e1c6c5b9bdbf0f2476ba47f865b91e3c13.tar.gz
Add direct manipulation sys window widgets.
In particular, adding 2 SeekBars and 2 RadialTimePickerViews. 2 because in a system window, a given View can be marked as "supports direct manipulation mode" or not. So we add 1 of each thing that supports DM mode and one that doesn't. For the ones that support, entering DM mode allows rotary controls to be used to manipulate the value. For the ones that don't, the event that would have entered DM mode instead triggers an ACTION_CLICK which in our implementation changes the background color on every other invocation. Test: manual, build, install, run the app BUG: 153888753 Change-Id: If1d4de9def33c8bf062e6f0ce202b99797e2d014
-rw-r--r--RotaryPlayground/res/layout/rotary_menu.xml6
-rw-r--r--RotaryPlayground/res/layout/rotary_sys_ui_direct_manipulation.xml86
-rw-r--r--RotaryPlayground/res/values/ids.xml23
-rw-r--r--RotaryPlayground/res/values/strings.xml6
-rw-r--r--RotaryPlayground/src/com/android/car/rotaryplayground/DirectManipulationHandler.java2
-rw-r--r--RotaryPlayground/src/com/android/car/rotaryplayground/L.java24
-rw-r--r--RotaryPlayground/src/com/android/car/rotaryplayground/RotaryMenu.java18
-rw-r--r--RotaryPlayground/src/com/android/car/rotaryplayground/RotarySysUiDirectManipulationWidgets.java95
8 files changed, 259 insertions, 1 deletions
diff --git a/RotaryPlayground/res/layout/rotary_menu.xml b/RotaryPlayground/res/layout/rotary_menu.xml
index 659f119..df3ec19 100644
--- a/RotaryPlayground/res/layout/rotary_menu.xml
+++ b/RotaryPlayground/res/layout/rotary_menu.xml
@@ -33,6 +33,12 @@
android:layout_weight="1"
android:text="Direct Manipulation" />
<Button
+ android:id="@+id/sys_ui_direct_manipulation"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:text="Sys UI Manipulation" />
+ <Button
android:id="@+id/grid"
android:layout_width="match_parent"
android:layout_height="0dp"
diff --git a/RotaryPlayground/res/layout/rotary_sys_ui_direct_manipulation.xml b/RotaryPlayground/res/layout/rotary_sys_ui_direct_manipulation.xml
new file mode 100644
index 0000000..9e30a1d
--- /dev/null
+++ b/RotaryPlayground/res/layout/rotary_sys_ui_direct_manipulation.xml
@@ -0,0 +1,86 @@
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+<!--
+The purpose of this screen is to demonstrate the direct manipulation capabilities in a
+system window. Not all widgets in a system window may support direct manipulation. Some
+of the widgets in this page support direct manipulation and some are left as unsupported for
+demonstrating the relevant behavior.
+
+Note that nudges are not supported in direct manipulation mode for system windows.
+
+The behavior of the UI on this page is intended to be tested while setting the value of
+RotaryController#TREAT_APP_WINDOW_AS_SYSTEM_WINDOW constant to true.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <!-- Widgets in the first half of the screen support Direct Manipulation and
+ those in the second half don't. This is set programmatically. -->
+ <com.android.car.ui.FocusArea
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:text="@string/sys_ui_supports_dm">
+ </TextView>
+ <SeekBar
+ android:id="@+id/direct_manipulation_supported_seek_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/seek_bar_background">
+ </SeekBar>
+ <RadialTimePickerView
+ android:id="@+id/direct_manipulation_supported_radial_time_picker"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:focusable="true">
+ </RadialTimePickerView>
+ </com.android.car.ui.FocusArea>
+
+ <com.android.car.ui.FocusArea
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:text="@string/sys_ui_does_not_support_dm">
+ </TextView>
+ <SeekBar
+ android:id="@+id/direct_manipulation_unsupported_seek_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/seek_bar_background">
+ </SeekBar>
+ <RadialTimePickerView
+ android:id="@+id/direct_manipulation_unsupported_radial_time_picker"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:focusable="true">
+ </RadialTimePickerView>
+ </com.android.car.ui.FocusArea>
+</LinearLayout>
diff --git a/RotaryPlayground/res/values/ids.xml b/RotaryPlayground/res/values/ids.xml
new file mode 100644
index 0000000..083862e
--- /dev/null
+++ b/RotaryPlayground/res/values/ids.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+<resources>
+ <!--
+ Used for storing and retrieving the background of a View in order to change it to an
+ alternative background but have the ability to restore it back to its original look.
+ -->
+ <item type="id" name="saved_background_tag"/>
+</resources> \ No newline at end of file
diff --git a/RotaryPlayground/res/values/strings.xml b/RotaryPlayground/res/values/strings.xml
index 35c960a..7720216 100644
--- a/RotaryPlayground/res/values/strings.xml
+++ b/RotaryPlayground/res/values/strings.xml
@@ -33,4 +33,10 @@
<string name="lorem" translatable="false">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et velit finibus, tempor ipsum vel, pellentesque lorem. Suspendisse congue urna pulvinar, congue dolor in, eleifend orci. Nam egestas sodales sapien. Integer sit amet ligula in ex commodo semper. Phasellus ac facilisis ligula. Ut mollis risus eu nunc consequat, eu molestie dolor maximus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Donec commodo lectus non est lacinia accumsan. Nulla tristique cursus iaculis. Sed in hendrerit nulla, vel faucibus mi. Aenean placerat turpis eros, non sagittis enim viverra id. Vestibulum vel rutrum est, eu consequat felis. Maecenas ac suscipit ante. Fusce dapibus ut libero blandit vehicula. Vivamus vel ipsum condimentum, maximus tellus nec, rutrum lorem.
</string>
+ <string name="sys_ui_supports_dm" translatable="true">
+ Supports Direct Manipulation Mode
+ </string>
+ <string name="sys_ui_does_not_support_dm" translatable="true">
+ Doesn\'t support Direct Manipulation Mode
+ </string>
</resources>
diff --git a/RotaryPlayground/src/com/android/car/rotaryplayground/DirectManipulationHandler.java b/RotaryPlayground/src/com/android/car/rotaryplayground/DirectManipulationHandler.java
index 8a87467..fc06754 100644
--- a/RotaryPlayground/src/com/android/car/rotaryplayground/DirectManipulationHandler.java
+++ b/RotaryPlayground/src/com/android/car/rotaryplayground/DirectManipulationHandler.java
@@ -103,7 +103,7 @@ public class DirectManipulationHandler implements View.OnKeyListener,
@Override
public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
boolean isActionUp = keyEvent.getAction() == KeyEvent.ACTION_UP;
- Log.d("RotaryPlayGround", "View: " + view + " is handling " + keyCode
+ Log.d(L.TAG, "View: " + view + " is handling " + keyCode
+ " and action " + keyEvent.getAction()
+ " direct manipulation mode is "
+ (mDirectManipulationMode.isActive() ? "active" : "inactive"));
diff --git a/RotaryPlayground/src/com/android/car/rotaryplayground/L.java b/RotaryPlayground/src/com/android/car/rotaryplayground/L.java
new file mode 100644
index 0000000..d970f6d
--- /dev/null
+++ b/RotaryPlayground/src/com/android/car/rotaryplayground/L.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package com.android.car.rotaryplayground;
+
+/**
+ * A class to facilitate app-wide logging.
+ */
+public class L {
+ public static final String TAG = "RotaryPlayground";
+}
diff --git a/RotaryPlayground/src/com/android/car/rotaryplayground/RotaryMenu.java b/RotaryPlayground/src/com/android/car/rotaryplayground/RotaryMenu.java
index a1ede40..c87fe1b 100644
--- a/RotaryPlayground/src/com/android/car/rotaryplayground/RotaryMenu.java
+++ b/RotaryPlayground/src/com/android/car/rotaryplayground/RotaryMenu.java
@@ -34,12 +34,14 @@ public class RotaryMenu extends Fragment {
private Fragment mRotaryCards = null;
private Fragment mRotaryGrid = null;
private Fragment mDirectManipulation = null;
+ private Fragment mSysUiDirectManipulation = null;
private Fragment mNotificationFragment = null;
private Fragment mScrollFragment = null;
private Button mCardButton;
private Button mGridButton;
private Button mDirectManipulationButton;
+ private Button mSysUiDirectManipulationButton;
private Button mNotificationButton;
private Button mScrollButton;
@@ -62,6 +64,12 @@ public class RotaryMenu extends Fragment {
mDirectManipulationButton.setOnClickListener(
(v -> showDirectManipulationExamples(/* hasFocus= */ true)));
+ mSysUiDirectManipulationButton = view.findViewById(R.id.sys_ui_direct_manipulation);
+ mSysUiDirectManipulationButton.setOnFocusChangeListener(
+ (v, hasFocus) -> showSysUiDirectManipulationExamples(hasFocus));
+ mSysUiDirectManipulationButton.setOnClickListener(
+ (v -> showSysUiDirectManipulationExamples(/* hasFocus= */ true)));
+
mNotificationButton = view.findViewById(R.id.notification);
mNotificationButton.setOnFocusChangeListener(
(v, hasFocus) -> showNotificationExample(hasFocus));
@@ -106,6 +114,16 @@ public class RotaryMenu extends Fragment {
showFragment(mDirectManipulation);
}
+ private void showSysUiDirectManipulationExamples(boolean hasFocus) {
+ if (!hasFocus) {
+ return; // Do nothing if no focus.
+ }
+ if (mSysUiDirectManipulation == null) {
+ mSysUiDirectManipulation = new RotarySysUiDirectManipulationWidgets();
+ }
+ showFragment(mSysUiDirectManipulation);
+ }
+
private void showNotificationExample(boolean hasFocus) {
if (!hasFocus) {
return; // do nothing if no focus.
diff --git a/RotaryPlayground/src/com/android/car/rotaryplayground/RotarySysUiDirectManipulationWidgets.java b/RotaryPlayground/src/com/android/car/rotaryplayground/RotarySysUiDirectManipulationWidgets.java
new file mode 100644
index 0000000..85fce89
--- /dev/null
+++ b/RotaryPlayground/src/com/android/car/rotaryplayground/RotarySysUiDirectManipulationWidgets.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package com.android.car.rotaryplayground;
+
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import com.android.car.ui.utils.DirectManipulationHelper;
+
+public class RotarySysUiDirectManipulationWidgets extends Fragment {
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.rotary_sys_ui_direct_manipulation, container, false);
+
+ View directManipulationSupportedSeekBar = view.findViewById(
+ R.id.direct_manipulation_supported_seek_bar);
+ DirectManipulationHelper.setSupportsDirectManipulation(
+ directManipulationSupportedSeekBar, true);
+
+ View directManipulationUnsupportedSeekBar = view.findViewById(
+ R.id.direct_manipulation_unsupported_seek_bar);
+ directManipulationUnsupportedSeekBar.setOnClickListener(
+ new ChangeBackgroundColorOnClickListener());
+
+ View directManipulationSupportedRadialTimePickerView = view.findViewById(
+ R.id.direct_manipulation_supported_radial_time_picker);
+ DirectManipulationHelper.setSupportsDirectManipulation(
+ directManipulationSupportedRadialTimePickerView, true);
+
+ View directManipulationUnsupportedRadialTimePickerView = view.findViewById(
+ R.id.direct_manipulation_unsupported_radial_time_picker);
+ directManipulationUnsupportedRadialTimePickerView.setOnClickListener(
+ new ChangeBackgroundColorOnClickListener());
+
+ return view;
+ }
+
+ /**
+ * An {@link android.view.View.OnClickListener} object that changes the background of the
+ * view it is registered on to {@link Color#BLUE} and back to whatever it was before on
+ * subsequent calls. This is just to demo doing something visually obvious in the UI.
+ */
+ private static class ChangeBackgroundColorOnClickListener implements View.OnClickListener {
+
+ /** Just some random color to switch the background to for demo purposes. */
+ private static final int ALTERNATIVE_BACKGROUND_COLOR = Color.BLUE;
+
+ /**
+ * The purpose of this boolean is to change color every other time {@link #onClick} is
+ * called.
+ */
+ private boolean mFlipFlop = true;
+
+ @Override
+ public void onClick(View v) {
+ Log.d(L.TAG,
+ "Handling onClick for " + v + " and going " + (mFlipFlop ? "flip" : "flop"));
+ if (mFlipFlop) {
+ Log.d(L.TAG, "Background about to be overwritten: " + v.getBackground());
+ v.setTag(R.id.saved_background_tag, v.getBackground());
+ v.setBackgroundColor(ALTERNATIVE_BACKGROUND_COLOR);
+ } else {
+ Object savedBackground = v.getTag(R.id.saved_background_tag);
+ Log.d(L.TAG, "Restoring background: " + savedBackground);
+ v.setBackground((Drawable) savedBackground);
+ }
+ // Flip mode bit.
+ mFlipFlop = !mFlipFlop;
+ }
+ }
+} \ No newline at end of file