Merge "Match CarUiRecyclerViewLayout.GRID and styleable attribute" into rvc-qpr-dev
diff --git a/car-apps-common/src/com/android/car/apps/common/ControlBar.java b/car-apps-common/src/com/android/car/apps/common/ControlBar.java
index 4ed3d45..4181867 100644
--- a/car-apps-common/src/com/android/car/apps/common/ControlBar.java
+++ b/car-apps-common/src/com/android/car/apps/common/ControlBar.java
@@ -95,6 +95,8 @@
     private ExpandCollapseCallback mExpandCollapseCallback;
     // The root of the transition animation.
     private ViewGroup mTransitionRoot;
+    // Whether this control bar has focus.
+    private boolean mHasFocus;
 
     // Default number of columns, if unspecified
     private static final int DEFAULT_COLUMNS = 3;
@@ -165,6 +167,15 @@
         mDefaultExpandCollapseView.setContentDescription(context.getString(
                 R.string.control_bar_expand_collapse_button));
         mDefaultExpandCollapseView.setOnClickListener(v -> onExpandCollapse());
+
+        // Collapse the control bar when it is expanded and loses focus.
+        getViewTreeObserver().addOnGlobalFocusChangeListener((oldFocus, newFocus) -> {
+            boolean hasFocus = hasFocus();
+            if (mHasFocus && !hasFocus && mIsExpanded) {
+                onExpandCollapse();
+            }
+            mHasFocus = hasFocus;
+        });
     }
 
     private int getSlotIndex(@SlotPosition int slotPosition) {
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/FocusAreaTest.java b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/FocusAreaTest.java
index 14d23b3..810e65a 100644
--- a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/FocusAreaTest.java
+++ b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/FocusAreaTest.java
@@ -53,7 +53,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-/** Unit tests for {@link FocusArea}. */
+/** Unit tests for {@link FocusArea} not in touch mode. */
 public class FocusAreaTest {
     private static final long WAIT_TIME_MS = 3000;
 
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/FocusAreaTouchModeTest.java b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/FocusAreaTouchModeTest.java
new file mode 100644
index 0000000..5c06f84
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/FocusAreaTouchModeTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.ui;
+
+import static android.view.View.FOCUS_RIGHT;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.graphics.Rect;
+import android.view.View;
+
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.car.ui.test.R;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+/** Unit tests for {@link FocusArea} in touch mode. */
+public class FocusAreaTouchModeTest {
+    @Rule
+    public ActivityTestRule<FocusAreaTestActivity> mActivityRule =
+            new ActivityTestRule<>(FocusAreaTestActivity.class, /* initialTouchMode= */ true);
+
+    private FocusAreaTestActivity mActivity;
+    private TestFocusArea mFocusArea2;
+    private View mView1;
+
+    @Before
+    public void setUp() {
+        mActivity = mActivityRule.getActivity();
+        mFocusArea2 = mActivity.findViewById(R.id.focus_area2);
+        mView1 = mActivity.findViewById(R.id.view1);
+    }
+
+    @Test
+    public void testOnRequestFocusInDescendants_doesNothing() {
+        mFocusArea2.post(() -> {
+            Rect previouslyFocusedRect = new Rect();
+            previouslyFocusedRect.left = mView1.getLeft();
+            previouslyFocusedRect.top = mView1.getTop();
+            previouslyFocusedRect.right = previouslyFocusedRect.left + mView1.getWidth();
+            previouslyFocusedRect.bottom = previouslyFocusedRect.top + mView1.getHeight();
+            boolean focusTaken =
+                    mFocusArea2.onRequestFocusInDescendants(FOCUS_RIGHT, previouslyFocusedRect);
+
+            assertWithMessage("onRequestFocusInDescendants returned").that(focusTaken).isFalse();
+            assertWithMessage("No view should be focused")
+                    .that(mFocusArea2.getRootView().findFocus()).isNull();
+        });
+    }
+}
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/FocusParkingViewTest.java b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/FocusParkingViewTest.java
index 6c9630b..325de40 100644
--- a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/FocusParkingViewTest.java
+++ b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/FocusParkingViewTest.java
@@ -38,7 +38,7 @@
 import org.junit.Rule;
 import org.junit.Test;
 
-/** Unit test for {@link FocusParkingView}. */
+/** Unit test for {@link FocusParkingView} not in touch mode. */
 public class FocusParkingViewTest {
 
     private static final int NUM_ITEMS = 40;
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/FocusParkingViewTouchModeTest.java b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/FocusParkingViewTouchModeTest.java
new file mode 100644
index 0000000..3c69854
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/FocusParkingViewTouchModeTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.ui;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.car.ui.test.R;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+/** Unit test for {@link FocusParkingView} in touch mode. */
+public class FocusParkingViewTouchModeTest {
+
+    @Rule
+    public ActivityTestRule<FocusParkingViewTestActivity> mActivityRule =
+            new ActivityTestRule<>(FocusParkingViewTestActivity.class,
+                    /* initialTouchMode= */ true);
+
+    private FocusParkingView mFpv;
+
+    @Before
+    public void setUp() {
+        FocusParkingViewTestActivity activity = mActivityRule.getActivity();
+        mFpv = activity.findViewById(R.id.fpv);
+    }
+
+    @Test
+    public void testRestoreDefaultFocus_doesNothing() {
+        mFpv.post(() -> {
+            assertThat(mFpv.getRootView().findFocus()).isNull();
+
+            mFpv.restoreDefaultFocus();
+
+            assertWithMessage("No view should be focused")
+                    .that(mFpv.getRootView().findFocus()).isNull();
+        });
+    }
+}
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/FocusArea.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/FocusArea.java
index 5bf1fb9..fe578ce 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/FocusArea.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/FocusArea.java
@@ -668,6 +668,9 @@
 
     @Override
     protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
+        if (isInTouchMode()) {
+            return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
+        }
         return maybeAdjustFocus();
     }
 
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/FocusParkingView.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/FocusParkingView.java
index 085ae23..e1d8010 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/FocusParkingView.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/FocusParkingView.java
@@ -190,6 +190,10 @@
     }
 
     private boolean restoreFocusInRoot() {
+        // Don't do anything in touch mode.
+        if (isInTouchMode()) {
+            return false;
+        }
         // The focused view was in a scrollable container and the Framework unfocused it because it
         // was scrolled off the screen. In this case focus on the scrollable container so that the
         // rotary controller can scroll the scrollable container.