Add drag icon in PhotoPicker

The drag icon is not shown in Preview mode.

Bug: 200006023
Test: atest com.android.providers.media.photopicker.espresso
Change-Id: Id467b6c364b871cbb22112675bc111547acaac3c
diff --git a/res/drawable/ic_drag.xml b/res/drawable/ic_drag.xml
new file mode 100644
index 0000000..eec4156
--- /dev/null
+++ b/res/drawable/ic_drag.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle" >
+    <size android:width="32dp"
+          android:height="4dp" />
+    <solid android:color="@color/picker_drag_bar_color" />
+    <corners android:radius="2dp" />
+</shape>
\ No newline at end of file
diff --git a/res/layout/activity_photo_picker.xml b/res/layout/activity_photo_picker.xml
index 688b4ec..56a2920 100644
--- a/res/layout/activity_photo_picker.xml
+++ b/res/layout/activity_photo_picker.xml
@@ -35,6 +35,24 @@
         app:behavior_hideable="true"
         app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
 
+        <FrameLayout
+            android:id="@+id/drag_bar"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/picker_drag_bar_height"
+            android:background="?android:attr/colorBackground">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal"
+                android:layout_marginBottom="@dimen/picker_drag_margin_bottom"
+                android:layout_marginTop="@dimen/picker_drag_margin_top"
+                android:scaleType="fitCenter"
+                android:src="@drawable/ic_drag"
+                android:contentDescription="@null"/>
+
+        </FrameLayout>
+
         <androidx.fragment.app.FragmentContainerView
             android:id="@+id/fragment_container"
             android:layout_width="match_parent"
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
index 596dd5b..c675a5d 100644
--- a/res/values-night/colors.xml
+++ b/res/values-night/colors.xml
@@ -27,6 +27,7 @@
     <color name="picker_toolbar_icon_color">#E8EAED</color>
     <color name="picker_toolbar_chip_text_color">#E8EAED</color>
     <color name="picker_toolbar_title_color">#FFFFFF</color>
+    <color name="picker_drag_bar_color">#686868</color>
 
     <!-- PhotoPicker Profile Button -->
     <color name="picker_profile_button_content_color">#A8C7FA</color>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 1be725e..80772b3 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -20,6 +20,7 @@
 
     <!-- PhotoPicker -->
     <color name="picker_default_white">@android:color/white</color>
+    <color name="picker_drag_bar_color">#DADCE0</color>
 
     <!-- PhotoPicker photo grid -->
     <color name="picker_primary_color">#1A73E8</color>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index eb9d42c..ff2d197 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -56,6 +56,10 @@
     <dimen name="picker_chip_touch_size">48dp</dimen>
     <dimen name="picker_chip_radius">16dp</dimen>
 
+    <dimen name="picker_drag_bar_height">24dp</dimen>
+    <dimen name="picker_drag_margin_top">8dp</dimen>
+    <dimen name="picker_drag_margin_bottom">12dp</dimen>
+
     <!-- PhotoPicker Preview -->
     <dimen name="preview_buttons_padding_horizontal">16dp</dimen>
     <dimen name="preview_deselect_padding_start">2dp</dimen>
diff --git a/src/com/android/providers/media/photopicker/PhotoPickerActivity.java b/src/com/android/providers/media/photopicker/PhotoPickerActivity.java
index 885722e..a541480 100644
--- a/src/com/android/providers/media/photopicker/PhotoPickerActivity.java
+++ b/src/com/android/providers/media/photopicker/PhotoPickerActivity.java
@@ -53,6 +53,7 @@
 import com.android.providers.media.photopicker.util.LayoutModeUtils;
 import com.android.providers.media.photopicker.viewmodel.PickerViewModel;
 
+import com.google.android.material.appbar.AppBarLayout;
 import com.google.android.material.bottomsheet.BottomSheetBehavior;
 import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback;
 import com.google.android.material.chip.Chip;
@@ -70,7 +71,6 @@
     private static final String EXTRA_TAB_CHIP_TYPE = "tab_chip_type";
     private static final int TAB_CHIP_TYPE_PHOTOS = 0;
     private static final int TAB_CHIP_TYPE_ALBUMS = 1;
-    private int mToolbarHeight = 0;
 
     @IntDef(prefix = { "TAB_CHIP_TYPE" }, value = {
             TAB_CHIP_TYPE_PHOTOS,
@@ -84,19 +84,25 @@
     private ViewGroup mTabChipContainer;
     private Chip mPhotosTabChip;
     private Chip mAlbumsTabChip;
-    @TabChipType
-    private int mSelectedTabChipType;
     private BottomSheetBehavior mBottomSheetBehavior;
     private View mBottomSheetView;
     private View mFragmentContainerView;
+    private View mDragBar;
+    private Toolbar mToolbar;
+
+    @TabChipType
+    private int mSelectedTabChipType;
+
+    private int mToolbarHeight = 0;
+    private int mDragBarHeight = 0;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_photo_picker);
 
-        final Toolbar toolbar = findViewById(R.id.toolbar);
-        setSupportActionBar(toolbar);
+        mToolbar = findViewById(R.id.toolbar);
+        setSupportActionBar(mToolbar);
         getSupportActionBar().setDisplayHomeAsUpEnabled(true);
 
         final int[] attrs = new int[] {R.attr.actionBarSize};
@@ -115,6 +121,9 @@
             setCancelledResultAndFinishSelf();
         }
 
+        mDragBar = findViewById(R.id.drag_bar);
+        mDragBarHeight = getResources().getDimensionPixelSize(R.dimen.picker_drag_bar_height);
+
         mTabChipContainer = findViewById(R.id.chip_container);
         initTabChips();
         initBottomSheetBehavior();
@@ -221,11 +230,11 @@
         mBottomSheetBehavior = BottomSheetBehavior.from(mBottomSheetView);
         initStateForBottomSheet();
 
-        mBottomSheetBehavior.addBottomSheetCallback(bottomSheetCallBack());
+        mBottomSheetBehavior.addBottomSheetCallback(createBottomSheetCallBack());
         setRoundedCornersForBottomSheet();
     }
 
-    private BottomSheetCallback bottomSheetCallBack() {
+    private BottomSheetCallback createBottomSheetCallBack() {
         return new BottomSheetCallback() {
             @Override
             public void onStateChanged(@NonNull View bottomSheet, int newState) {
@@ -360,6 +369,7 @@
         updateStatusBarAndNavigationBar(mode);
         updateBottomSheetBehavior(mode);
         updateFragmentContainerViewPadding(mode);
+        updateDragBar(mode);
     }
 
     private void updateTitle(String title) {
@@ -402,6 +412,13 @@
             icon.setTint(isPreview ? Color.WHITE : getColor(R.color.picker_toolbar_icon_color));
         }
         getSupportActionBar().setHomeAsUpIndicator(icon);
+
+        // 4. Update the toolbar margin based on whether drag bar is visible or not
+        final int top = isPreview ? 0 : mDragBarHeight;
+        final AppBarLayout.LayoutParams layoutParams = new AppBarLayout.LayoutParams(
+                mToolbar.getLayoutParams());
+        layoutParams.setMargins(/* left */ 0, top, /* right */ 0, /* bottom */ 0);
+        mToolbar.setLayoutParams(layoutParams);
     }
 
     /**
@@ -464,20 +481,27 @@
      * Updates the FragmentContainerView padding.
      * <p>
      * For Preview mode, toolbar overlaps the Fragment content, hence the padding will be set to 0.
-     * For Non-Preview mode, toolbar doesn't overlap the contents of the fragment, hence we set the
-     * padding as the height of the toolbar.
+     * For Non-Preview mode, toolbar doesn't overlap the contents of the fragment and we have drag
+     * icon, hence we set the top padding as the sum of the height of the toolbar and the height of
+     * the drag bar.
      */
     private void updateFragmentContainerViewPadding(@NonNull LayoutModeUtils.Mode mode) {
         if (mFragmentContainerView == null) return;
 
+        final int topPadding;
         if (mode.isPreview) {
-            mFragmentContainerView.setPadding(mFragmentContainerView.getPaddingLeft(), 0,
-                    mFragmentContainerView.getPaddingRight(),
-                    mFragmentContainerView.getPaddingBottom());
+            topPadding = 0;
         } else {
-            mFragmentContainerView.setPadding(mFragmentContainerView.getPaddingLeft(),
-                    mToolbarHeight, mFragmentContainerView.getPaddingRight(),
-                    mFragmentContainerView.getPaddingBottom());
+            topPadding = mToolbarHeight + mDragBarHeight;
         }
+
+        mFragmentContainerView.setPadding(mFragmentContainerView.getPaddingLeft(),
+                topPadding, mFragmentContainerView.getPaddingRight(),
+                mFragmentContainerView.getPaddingBottom());
     }
-}
\ No newline at end of file
+
+    private void updateDragBar(@NonNull LayoutModeUtils.Mode mode) {
+        final boolean shouldShowDragBar = !mode.isPreview;
+        mDragBar.setVisibility(shouldShowDragBar ? View.VISIBLE : View.GONE);
+    }
+}
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/MultiSelectTest.java b/tests/src/com/android/providers/media/photopicker/espresso/MultiSelectTest.java
index 03bf933..27e1811 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/MultiSelectTest.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/MultiSelectTest.java
@@ -53,6 +53,11 @@
             = new ActivityScenarioRule<>(PhotoPickerBaseTest.getMultiSelectionIntent());
 
     @Test
+    public void testMultiselect_showDragBar() {
+        onView(withId(DRAG_BAR_ID)).check(matches(isDisplayed()));
+    }
+
+    @Test
     public void testMultiselect_selectIcon() {
         onView(withId(PICKER_TAB_RECYCLERVIEW_ID)).check(matches(isDisplayed()));
 
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerActivityTest.java b/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerActivityTest.java
index 0a13a5f..cd6a6f1 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerActivityTest.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerActivityTest.java
@@ -60,6 +60,7 @@
     public void testActivityLayout_Simple() {
         onView(withId(R.id.toolbar)).check(matches(isDisplayed()));
         onView(withId(R.id.fragment_container)).check(matches(isDisplayed()));
+        onView(withId(DRAG_BAR_ID)).check(matches(isDisplayed()));
         onView(withContentDescription("Navigate up")).perform(click());
         assertThat(mRule.getScenario().getResult().getResultCode()).isEqualTo(
                 Activity.RESULT_CANCELED);
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerBaseTest.java b/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerBaseTest.java
index a516d30..ad95ac3 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerBaseTest.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerBaseTest.java
@@ -62,6 +62,7 @@
     protected static final int ICON_THUMBNAIL_ID = R.id.icon_thumbnail;
     protected static final int VIEW_SELECTED_BUTTON_ID = R.id.button_view_selected;
     protected static final int PREVIEW_IMAGE_VIEW_ID = R.id.preview_imageView;
+    protected static final int DRAG_BAR_ID = R.id.drag_bar;
 
     /**
      * The position of the image item in the grid on the Photos tab
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/PreviewMultiSelectLongPressTest.java b/tests/src/com/android/providers/media/photopicker/espresso/PreviewMultiSelectLongPressTest.java
index bd4be08..c409f9c 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/PreviewMultiSelectLongPressTest.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/PreviewMultiSelectLongPressTest.java
@@ -65,6 +65,9 @@
 
         registerIdlingResourceAndWaitForIdle();
 
+        // No dragBar in preview
+        onView(withId(DRAG_BAR_ID)).check(matches(not(isDisplayed())));
+
         // Verify image is previewed
         assertMultiSelectLongPressCommonLayoutMatches();
         onView(withId(R.id.preview_imageView)).check(matches(isDisplayed()));
@@ -73,6 +76,8 @@
         onView(withContentDescription("Navigate up")).perform(click());
 
         onView(withId(PICKER_TAB_RECYCLERVIEW_ID)).check(matches(isDisplayed()));
+        // Shows dragBar after we are back to Photos tab
+        onView(withId(DRAG_BAR_ID)).check(matches(isDisplayed()));
     }
 
     @Test
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/PreviewMultiSelectTest.java b/tests/src/com/android/providers/media/photopicker/espresso/PreviewMultiSelectTest.java
index f614ac3..27a05ac 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/PreviewMultiSelectTest.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/PreviewMultiSelectTest.java
@@ -40,6 +40,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.not;
 
 import android.view.View;
 
@@ -80,6 +81,9 @@
 
         registerIdlingResourceAndWaitForIdle();
 
+        // No dragBar in preview
+        onView(withId(DRAG_BAR_ID)).check(matches(not(isDisplayed())));
+
         assertMultiSelectPreviewCommonLayoutDisplayed();
         // Verify ImageView is displayed
         onView(withId(PREVIEW_IMAGE_VIEW_ID)).check(matches(isCompletelyDisplayed()));
@@ -87,6 +91,9 @@
         // Click back button and verify we are back to photos tab
         onView(withContentDescription("Navigate up")).perform(click());
         onView(withId(PICKER_TAB_RECYCLERVIEW_ID)).check(matches(isDisplayed()));
+
+        // Shows dragBar after we are back to Photos tab
+        onView(withId(DRAG_BAR_ID)).check(matches(isDisplayed()));
     }
 
     @Test
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/PreviewSingleSelectTest.java b/tests/src/com/android/providers/media/photopicker/espresso/PreviewSingleSelectTest.java
index bee2414..819b6d6 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/PreviewSingleSelectTest.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/PreviewSingleSelectTest.java
@@ -69,6 +69,9 @@
 
         registerIdlingResourceAndWaitForIdle();
 
+        // No dragBar in preview
+        onView(withId(DRAG_BAR_ID)).check(matches(not(isDisplayed())));
+
         // Verify image is previewed
         assertSingleSelectCommonLayoutMatches();
         onView(withId(R.id.preview_imageView)).check(matches(isDisplayed()));
@@ -77,6 +80,8 @@
         onView(withContentDescription("Navigate up")).perform(click());
 
         onView(withId(PICKER_TAB_RECYCLERVIEW_ID)).check(matches(isDisplayed()));
+        // Shows dragBar after we are back to Photos tab
+        onView(withId(DRAG_BAR_ID)).check(matches(isDisplayed()));
     }
 
     @Test