Add BottomSheetBehavior for picker launch animation
* Add photopicker launch animation to transition from bottom screen to
top. This happens full screen for multiselect, and half screen for
single select.
* Swiping down the PhotoPicker activity closes the activity for
multi-select, and takes the screen back to partial screen for
single-select.
* Selecting an image in half screen opens full screen.
TODO: More transition effect CL to follow to match motion specs
Bug: 185800839
Test: Manual (video attached to the bug)
Change-Id: I33b41f06b674731c7e69218ec38f439788da86ff
Merged-In: I33b41f06b674731c7e69218ec38f439788da86ff
(cherry picked from commit fcd7132bf4fec4572df3aca76ff915a4ea710316)
diff --git a/res/layout/activity_photo_picker.xml b/res/layout/activity_photo_picker.xml
index 54ed321..ce9b7d0 100644
--- a/res/layout/activity_photo_picker.xml
+++ b/res/layout/activity_photo_picker.xml
@@ -15,46 +15,62 @@
~ limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".MainActivity">
+<!-- CoordinatorLayout is necessary for various components (e.g. Snackbars, and
+ BottomSheet) to operate correctly. -->
+<androidx.coordinatorlayout.widget.CoordinatorLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity">
- <com.google.android.material.appbar.AppBarLayout
+ <LinearLayout
+ android:orientation="vertical"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="match_parent"
+ android:id="@+id/bottom_sheet"
+ android:background="?android:attr/colorBackground"
+ android:clipToOutline="true"
+ app:behavior_hideable="true"
+ app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
- <androidx.appcompat.widget.Toolbar
- android:id="@+id/toolbar"
+ <com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="?android:attr/colorBackground">
+ android:layout_height="wrap_content">
- <LinearLayout
- android:id="@+id/chip_container"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:orientation="horizontal"/>
+ <androidx.appcompat.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="?android:attr/colorBackground">
- </androidx.appcompat.widget.Toolbar>
+ <LinearLayout
+ android:id="@+id/chip_container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:orientation="horizontal"/>
- </com.google.android.material.appbar.AppBarLayout>
+ </androidx.appcompat.widget.Toolbar>
- <Switch
- android:visibility="gone"
- android:text="Work Profile"
- android:id="@+id/workprofile"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
+ </com.google.android.material.appbar.AppBarLayout>
- <androidx.fragment.app.FragmentContainerView
- android:id="@+id/fragment_container"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"/>
+ <Switch
+ android:visibility="gone"
+ android:text="Work Profile"
+ android:id="@+id/workprofile"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
-</LinearLayout>
+ <androidx.fragment.app.FragmentContainerView
+ android:id="@+id/fragment_container"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+ </LinearLayout>
+
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
+
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 28332ce..c911972 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -21,6 +21,7 @@
<dimen name="dialog_space">20dp</dimen>
<!-- PhotoPicker -->
+ <dimen name="picker_top_corner_radius">16dp</dimen>
<dimen name="picker_photo_size">118dp</dimen>
<dimen name="picker_album_size">156dp</dimen>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 59886bd..60e9fae 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -56,9 +56,11 @@
<item name="android:colorBackground">@color/picker_background_color</item>
<!-- System | Widget section -->
- <item name="android:statusBarColor">?android:colorBackground</item>
+ <item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">?android:colorBackground</item>
- <item name="android:windowBackground">?android:colorBackground</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:backgroundDimEnabled">true</item>
</style>
</resources>
diff --git a/src/com/android/providers/media/photopicker/PhotoPickerActivity.java b/src/com/android/providers/media/photopicker/PhotoPickerActivity.java
index 260ab70..1f05c3f 100644
--- a/src/com/android/providers/media/photopicker/PhotoPickerActivity.java
+++ b/src/com/android/providers/media/photopicker/PhotoPickerActivity.java
@@ -22,8 +22,8 @@
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.content.res.Configuration;
import android.graphics.Color;
+import android.graphics.Outline;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -31,10 +31,11 @@
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
+import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.WindowInsetsController;
+import android.view.ViewOutlineProvider;
import android.widget.CompoundButton;
import android.widget.Switch;
import android.widget.Toast;
@@ -55,6 +56,8 @@
import com.android.providers.media.photopicker.util.CrossProfileUtils;
import com.android.providers.media.photopicker.viewmodel.PickerViewModel;
+import com.google.android.material.bottomsheet.BottomSheetBehavior;
+import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback;
import com.google.android.material.chip.Chip;
import java.lang.annotation.Retention;
@@ -87,6 +90,8 @@
private Chip mAlbumsTabChip;
@TabChipType
private int mSelectedTabChipType;
+ private BottomSheetBehavior mBottomSheetBehavior;
+ private View mBottomSheetView;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -115,6 +120,41 @@
profileSwitch.setVisibility(View.VISIBLE);
setUpWorkProfileToggleSwitch(profileSwitch);
}
+ mBottomSheetView = findViewById(R.id.bottom_sheet);
+ mBottomSheetBehavior = BottomSheetBehavior.from(mBottomSheetView);
+ if (mPickerViewModel.canSelectMultiple()) {
+ mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
+ mBottomSheetBehavior.setSkipCollapsed(true);
+ } else {
+ //TODO(b/185800839): Compute this dynamically such that 2 photos rows is shown
+ mBottomSheetBehavior.setPeekHeight(1200);
+ mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
+ }
+
+ mBottomSheetBehavior.addBottomSheetCallback(new BottomSheetCallback() {
+ @Override
+ public void onStateChanged(@NonNull View bottomSheet, int newState) {
+ if (newState == BottomSheetBehavior.STATE_HIDDEN) {
+ finish();
+ }
+ }
+
+ @Override
+ public void onSlide(@NonNull View bottomSheet, float slideOffset) {
+ }
+ });
+
+ final float cornerRadiusDP = getResources().getDimension(R.dimen.picker_top_corner_radius);
+ final float cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
+ cornerRadiusDP, getResources().getDisplayMetrics());
+ final ViewOutlineProvider viewOutlineProvider = new ViewOutlineProvider() {
+ @Override
+ public void getOutline(final View view, final Outline outline) {
+ outline.setRoundRect(0, 0, view.getWidth(),
+ (int)(view.getHeight() + cornerRadius), cornerRadius);
+ }
+ };
+ mBottomSheetView.setOutlineProvider(viewOutlineProvider);
}
@Override
@@ -334,24 +374,28 @@
}
private void updateStatusBarAndNavBar(boolean isLightBackgroundMode) {
- final int mask = WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
- | WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
final int backgroundColor;
+ final boolean isPreview = !isLightBackgroundMode;
if (isLightBackgroundMode) {
backgroundColor = getColor(R.color.picker_background_color);
-
- final int uiModeNight =
- getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
-
- // if the system is not in Dark theme, set the system bars to light mode.
- if (uiModeNight == Configuration.UI_MODE_NIGHT_NO) {
- getWindow().getInsetsController().setSystemBarsAppearance(mask, mask);
- }
} else {
backgroundColor = getColor(R.color.preview_default_black);
- getWindow().getInsetsController().setSystemBarsAppearance(/* appearance= */ 0, mask);
}
- getWindow().setStatusBarColor(backgroundColor);
getWindow().setNavigationBarColor(backgroundColor);
+ getWindow().setStatusBarColor(isPreview ? backgroundColor : android.R.color.transparent);
+ if (mBottomSheetView != null) {
+ mBottomSheetView.setClipToOutline(!isPreview);
+ // TODO(b/185800839): downward swipe for bottomsheet should go back to photos grid
+ mBottomSheetBehavior.setDraggable(!isPreview);
+ }
+ }
+
+ /**
+ * Set full screen if the state is not full screen
+ */
+ public void setFullScreen() {
+ if (mBottomSheetBehavior.getState() != BottomSheetBehavior.STATE_EXPANDED) {
+ mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
+ }
}
}
\ No newline at end of file
diff --git a/src/com/android/providers/media/photopicker/ui/PreviewFragment.java b/src/com/android/providers/media/photopicker/ui/PreviewFragment.java
index 661004d..7f8c569 100644
--- a/src/com/android/providers/media/photopicker/ui/PreviewFragment.java
+++ b/src/com/android/providers/media/photopicker/ui/PreviewFragment.java
@@ -63,6 +63,10 @@
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ // TODO(b/185800839): Add animation preview to full screen and back transition to partial
+ // screen
+ ((PhotoPickerActivity)getActivity()).setFullScreen();
+
// Warning: The below code assumes that getSelectedItems will never return null.
// We are creating a new ArrayList with selected items, this list used as data for the
// adapter. If activity gets killed and recreated, we will lose items that were deselected.