Add unit tests for FocusParkingView

Bug: 170344916
Test: atest CarUILibUnitTests
Change-Id: I73291cef8db415b5b1aa80b37f92b0824af0008a
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 9f24d6a..0183e5f 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
@@ -16,64 +16,135 @@
 
 package com.android.car.ui;
 
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_FOCUS;
+
+import static com.android.car.ui.utils.RotaryConstants.ACTION_RESTORE_DEFAULT_FOCUS;
+
 import static com.google.common.truth.Truth.assertThat;
 
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
 import androidx.test.rule.ActivityTestRule;
 
+import com.android.car.ui.recyclerview.TestContentLimitingAdapter;
 import com.android.car.ui.test.R;
 
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
 /** Unit test for {@link FocusParkingView}. */
 public class FocusParkingViewTest {
 
-    private static final long WAIT_TIME_MS = 3000;
-
     @Rule
     public ActivityTestRule<FocusParkingViewTestActivity> mActivityRule =
             new ActivityTestRule<>(FocusParkingViewTestActivity.class);
 
     private FocusParkingViewTestActivity mActivity;
+    private FocusParkingView mFpv;
+    private View mView1;
+    private View mFocusedByDefault;
+    private RecyclerView mList;
 
     @Before
     public void setUp() {
         mActivity = mActivityRule.getActivity();
+        mFpv = mActivity.findViewById(R.id.fpv);
+        mView1 = mActivity.findViewById(R.id.view1);
+        mFocusedByDefault = mActivity.findViewById(R.id.focused_by_default);
+        mList = mActivity.findViewById(R.id.list);
+
+        mList.post(() -> {
+            mList.setLayoutManager(new LinearLayoutManager(mActivity));
+            mList.setAdapter(new TestContentLimitingAdapter(/* numItems= */ 2));
+        });
     }
 
     @Test
-    public void testFocusParkingViewCannotTakeFocus() throws Exception {
-        FocusParkingView focusParkingView = mActivity.findViewById(R.id.focus_parking);
-
-        CountDownLatch latch = new CountDownLatch(1);
-        focusParkingView.post(() -> {
-            focusParkingView.requestFocus();
-            focusParkingView.post(() -> {
-                latch.countDown();
-            });
-        });
-        latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS);
-
-        assertThat(focusParkingView.isFocused()).isFalse();
+    public void testGetWidthAndHeight() {
+        assertThat(mFpv.getWidth()).isEqualTo(1);
+        assertThat(mFpv.getHeight()).isEqualTo(1);
     }
+
     @Test
-    public void testFocusParkingViewFocusedWhenWindowLostFocus() throws Exception {
-        FocusParkingView focusParkingView = mActivity.findViewById(R.id.focus_parking);
-        assertThat(focusParkingView.isFocused()).isFalse();
+    public void testRequestFocus_focusOnDefaultFocus() {
+        mFpv.post(() -> {
+            mView1.requestFocus();
+            assertThat(mView1.isFocused()).isTrue();
 
-        CountDownLatch latch = new CountDownLatch(1);
-        focusParkingView.post(() -> {
-            focusParkingView.onWindowFocusChanged(false);
-            focusParkingView.post(() -> {
-                latch.countDown();
-            });
+            mFpv.requestFocus();
+            assertThat(mFocusedByDefault.isFocused()).isTrue();
         });
-        latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS);
+    }
 
-        assertThat(focusParkingView.isFocused()).isTrue();
+    @Test
+    public void testRestoreDefaultFocus_focusOnDefaultFocus() {
+        mFpv.post(() -> {
+            mView1.requestFocus();
+            assertThat(mView1.isFocused()).isTrue();
+
+            mFpv.restoreDefaultFocus();
+            assertThat(mFocusedByDefault.isFocused()).isTrue();
+        });
+    }
+
+    @Test
+    public void testOnWindowFocusChanged_loseFocus() {
+        mFpv.post(() -> {
+            mView1.requestFocus();
+            assertThat(mView1.isFocused()).isTrue();
+
+            mFpv.onWindowFocusChanged(false);
+            assertThat(mFpv.isFocused()).isTrue();
+        });
+    }
+
+    @Test
+    public void testOnWindowFocusChanged_focusOnDefaultFocus() {
+        mFpv.post(() -> {
+            mFpv.performAccessibilityAction(ACTION_FOCUS, null);
+            assertThat(mFpv.isFocused()).isTrue();
+
+            mFpv.onWindowFocusChanged(true);
+            assertThat(mFocusedByDefault.isFocused()).isTrue();
+        });
+    }
+
+    @Test
+    public void testPerformAccessibilityAction_actionRestoreDefaultFocus() {
+        mFpv.post(() -> {
+            mView1.requestFocus();
+            assertThat(mView1.isFocused()).isTrue();
+
+            mFpv.performAccessibilityAction(ACTION_RESTORE_DEFAULT_FOCUS, null);
+            assertThat(mFocusedByDefault.isFocused()).isTrue();
+        });
+    }
+
+    @Test
+    public void testPerformAccessibilityAction_actionFocus() {
+        mFpv.post(() -> {
+            mView1.requestFocus();
+            assertThat(mView1.isFocused()).isTrue();
+
+            mFpv.performAccessibilityAction(ACTION_FOCUS, null);
+            assertThat(mFpv.isFocused()).isTrue();
+        });
+    }
+
+    @Test
+    public void testRestoreFocusInRoot_recyclerViewItemRemoved() {
+        mFpv.post(() -> {
+            View firstItem = mList.getLayoutManager().findViewByPosition(0);
+            firstItem.requestFocus();
+            assertThat(firstItem.isFocused()).isTrue();
+
+            ViewGroup parent = (ViewGroup) firstItem.getParent();
+            parent.removeView(firstItem);
+            assertThat(mList.isFocused()).isTrue();
+        });
     }
 }
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/recyclerview/TestContentLimitingAdapter.java b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/recyclerview/TestContentLimitingAdapter.java
index a65be43..1af9a70 100644
--- a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/recyclerview/TestContentLimitingAdapter.java
+++ b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/recyclerview/TestContentLimitingAdapter.java
@@ -31,7 +31,7 @@
 
     private final List<String> mItems;
 
-    TestContentLimitingAdapter(int numItems) {
+    public TestContentLimitingAdapter(int numItems) {
         mItems = new ArrayList<>();
         for (int i = 0; i < numItems; i++) {
             mItems.add("Item " + i);
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/utils/ViewUtilsTest.java b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/utils/ViewUtilsTest.java
index ccb9d08..44e3e43 100644
--- a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/utils/ViewUtilsTest.java
+++ b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/utils/ViewUtilsTest.java
@@ -28,29 +28,23 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
 import androidx.test.rule.ActivityTestRule;
 
 import com.android.car.ui.FocusArea;
 import com.android.car.ui.FocusParkingView;
 import com.android.car.ui.recyclerview.CarUiRecyclerView;
+import com.android.car.ui.recyclerview.TestContentLimitingAdapter;
 import com.android.car.ui.test.R;
 
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 
-import java.util.Arrays;
-import java.util.List;
-
 /** Unit tests for {@link ViewUtils}. */
 public class ViewUtilsTest {
 
@@ -428,42 +422,6 @@
 
     private void setUpRecyclerView(@NonNull CarUiRecyclerView list) {
         list.setLayoutManager(new LinearLayoutManager(mActivity));
-        list.setAdapter(new TestAdapter());
-    }
-
-    private static class TestAdapter extends RecyclerView.Adapter<TestViewHolder> {
-
-        private static final List<String> DATA = Arrays.asList("first", "second");
-
-        @NonNull
-        @Override
-        public TestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            View view = LayoutInflater.from(parent.getContext())
-                    .inflate(R.layout.test_list_item, parent, false);
-            return new TestViewHolder(view);
-        }
-
-        @Override
-        public void onBindViewHolder(@NonNull TestViewHolder holder, int position) {
-            holder.bind(DATA.get(position));
-        }
-
-        @Override
-        public int getItemCount() {
-            return DATA.size();
-        }
-    }
-
-    private static class TestViewHolder extends RecyclerView.ViewHolder {
-        private final TextView mTextView;
-
-        TestViewHolder(View view) {
-            super(view);
-            mTextView = view.findViewById(R.id.text);
-        }
-
-        void bind(String text) {
-            mTextView.setText(text);
-        }
+        list.setAdapter(new TestContentLimitingAdapter(/* numItems= */ 2));
     }
 }
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/res/layout/focus_parking_view_test_activity.xml b/car-ui-lib/car-ui-lib/src/androidTest/res/layout/focus_parking_view_test_activity.xml
index f3f623d..0ad8cd7 100644
--- a/car-ui-lib/car-ui-lib/src/androidTest/res/layout/focus_parking_view_test_activity.xml
+++ b/car-ui-lib/car-ui-lib/src/androidTest/res/layout/focus_parking_view_test_activity.xml
@@ -14,18 +14,27 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<FrameLayout
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-    <!-- In some cases Android will focus the first focusable view automatically. To prevent the
-         FocusParkingView getting focused unintentionally, we put a focusable Button above the
-         FocusParkingView. -->
-    <Button
-        android:layout_width="100dp"
-        android:layout_height="40dp"/>
     <com.android.car.ui.FocusParkingView
-        android:id="@+id/focus_parking"
+        android:id="@+id/fpv"
+        android:layout_width="10dp"
+        android:layout_height="10dp"/>
+    <View
+        android:id="@+id/view1"
+        android:layout_width="100dp"
+        android:layout_height="40dp"
+        android:focusable="true"/>
+    <View
+        android:id="@+id/focused_by_default"
+        android:layout_width="100dp"
+        android:layout_height="40dp"
+        android:focusable="true"
+        android:focusedByDefault="true"/>
+    <com.android.car.ui.recyclerview.CarUiRecyclerView
+        android:id="@+id/list"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"/>
-</FrameLayout>
+</LinearLayout>
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/res/layout/test_car_ui_recycler_view_list_item.xml b/car-ui-lib/car-ui-lib/src/androidTest/res/layout/test_car_ui_recycler_view_list_item.xml
index 7e8717e..8297f6b 100644
--- a/car-ui-lib/car-ui-lib/src/androidTest/res/layout/test_car_ui_recycler_view_list_item.xml
+++ b/car-ui-lib/car-ui-lib/src/androidTest/res/layout/test_car_ui_recycler_view_list_item.xml
@@ -18,7 +18,8 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:orientation="horizontal">
+    android:orientation="horizontal"
+    android:focusable="true">
 
     <TextView
         android:layout_width="wrap_content"