summaryrefslogtreecommitdiff
path: root/src/com
diff options
context:
space:
mode:
author Wenbo Jie <wenbojie@google.com> 2025-03-10 06:28:53 +0000
committer Wenbo Jie <wenbojie@google.com> 2025-03-13 03:13:54 +0000
commit165058c81c7d402cf6580e57f5efb7dd009e941d (patch)
tree9ac17c67b71deeb95b5174a4e10760566a83908a /src/com
parent595ae7b5cb5550b63fa29d1a2e664e4ea8101ed2 (diff)
[DocsUI M3] Restyle drag drop badge for M3
* When there are multiple dragging files: * add an additional drag layer * add a file counter * Update drag show (radius/offset) to match the new M3 spec. * drag shadow view is an isolated view without the theme context, so M3 color attributes like "?attr/colorXXX" can't be used directly, instead, system color tokens are being used in light/dark mode. Since system color tokens are only available in SDK 31, fallback static colors are being used in the original colors.xml. Check the attached bug for demo. Bug: 377771158 Test: m DocumentsUIGoogle && manual inspection Flag: com.android.documentsui.flags.use_material3 Change-Id: Ia00bb0037a19813b4137d9d6cd7a42441b7f255e
Diffstat (limited to 'src/com')
-rw-r--r--src/com/android/documentsui/DragAndDropManager.java10
-rw-r--r--src/com/android/documentsui/DragShadowBuilder.java142
2 files changed, 138 insertions, 14 deletions
diff --git a/src/com/android/documentsui/DragAndDropManager.java b/src/com/android/documentsui/DragAndDropManager.java
index bed8764ae..158d43c95 100644
--- a/src/com/android/documentsui/DragAndDropManager.java
+++ b/src/com/android/documentsui/DragAndDropManager.java
@@ -16,6 +16,8 @@
package com.android.documentsui;
+import static com.android.documentsui.util.FlagUtils.isUseMaterial3FlagEnabled;
+
import android.content.ClipData;
import android.content.Context;
import android.graphics.drawable.Drawable;
@@ -277,7 +279,9 @@ public interface DragAndDropManager {
final Drawable icon;
final int size = srcs.size();
- if (size == 1) {
+ // If use_material3 flag is ON, we always show the icon/title for the first file even
+ // when we have multiple files.
+ if (size == 1 || isUseMaterial3FlagEnabled()) {
DocumentInfo doc = srcs.get(0);
title = doc.displayName;
icon = iconHelper.getDocumentIcon(mContext, doc);
@@ -287,6 +291,10 @@ public interface DragAndDropManager {
icon = mDefaultShadowIcon;
}
+ if (isUseMaterial3FlagEnabled()) {
+ mShadowBuilder.updateDragFileCount(size);
+ }
+
mShadowBuilder.updateTitle(title);
mShadowBuilder.updateIcon(icon);
diff --git a/src/com/android/documentsui/DragShadowBuilder.java b/src/com/android/documentsui/DragShadowBuilder.java
index 10a0106d5..be76302e8 100644
--- a/src/com/android/documentsui/DragShadowBuilder.java
+++ b/src/com/android/documentsui/DragShadowBuilder.java
@@ -16,7 +16,7 @@
package com.android.documentsui;
-import com.android.documentsui.DragAndDropManager.State;
+import static com.android.documentsui.util.FlagUtils.isUseMaterial3FlagEnabled;
import android.content.Context;
import android.graphics.Canvas;
@@ -29,6 +29,12 @@ import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
+import com.android.documentsui.DragAndDropManager.State;
+
+import java.text.NumberFormat;
+
class DragShadowBuilder extends View.DragShadowBuilder {
private final View mShadowView;
@@ -37,8 +43,18 @@ class DragShadowBuilder extends View.DragShadowBuilder {
private final int mWidth;
private final int mHeight;
private final int mShadowRadius;
- private int mPadding;
+ private final int mPadding;
private Paint paint;
+ // This will be null if use_material3 flag is OFF.
+ private final @Nullable View mAdditionalShadowView;
+ // This will always be 0 if the use_material3 flag is OFF.
+ private int mDragFileCount = 0;
+ // The following 5 dimensions will be 0 if the use_material3 flag is OFF.
+ private final int mDragContentRadius;
+ private final int mAdditionalLayerOffset;
+ private final int mDragFileCounterOffset;
+ private final int mShadow2Radius;
+ private final int mShadowYOffset;
DragShadowBuilder(Context context) {
mWidth = context.getResources().getDimensionPixelSize(R.dimen.drag_shadow_width);
@@ -49,6 +65,28 @@ class DragShadowBuilder extends View.DragShadowBuilder {
mShadowView = LayoutInflater.from(context).inflate(R.layout.drag_shadow_layout, null);
mTitle = (TextView) mShadowView.findViewById(android.R.id.title);
mIcon = (DropBadgeView) mShadowView.findViewById(android.R.id.icon);
+ if (isUseMaterial3FlagEnabled()) {
+ mAdditionalShadowView =
+ LayoutInflater.from(context).inflate(R.layout.additional_drag_shadow, null);
+ mDragContentRadius =
+ context.getResources().getDimensionPixelSize(R.dimen.drag_content_radius);
+ mAdditionalLayerOffset =
+ context.getResources()
+ .getDimensionPixelSize(R.dimen.drag_additional_layer_offset);
+ mDragFileCounterOffset =
+ context.getResources().getDimensionPixelSize(R.dimen.drag_file_counter_offset);
+ mShadow2Radius =
+ context.getResources().getDimensionPixelSize(R.dimen.drag_shadow_2_radius);
+ mShadowYOffset =
+ context.getResources().getDimensionPixelSize(R.dimen.drag_shadow_y_offset);
+ } else {
+ mAdditionalShadowView = null;
+ mDragContentRadius = 0;
+ mAdditionalLayerOffset = 0;
+ mDragFileCounterOffset = 0;
+ mShadow2Radius = 0;
+ mShadowYOffset = 0;
+ }
// Important for certain APIs
mShadowView.setLayerType(View.LAYER_TYPE_SOFTWARE, paint);
@@ -67,23 +105,86 @@ class DragShadowBuilder extends View.DragShadowBuilder {
Rect r = canvas.getClipBounds();
// Calling measure is necessary in order for all child views to get correctly laid out.
mShadowView.measure(
- View.MeasureSpec.makeMeasureSpec(r.right- r.left, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(r.right - r.left, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(r.bottom - r.top , View.MeasureSpec.EXACTLY));
mShadowView.layout(r.left, r.top, r.right, r.bottom);
// Since DragShadow is not an actual view drawn in hardware-accelerated window,
// android:elevation does not work; we need to draw the shadow ourselves manually.
paint.setColor(Color.TRANSPARENT);
- // Shadow 1
- int opacity = (int) (255 * 0.1);
- paint.setShadowLayer(mShadowRadius, 0, 0, Color.argb(opacity, 0, 0, 0));
- canvas.drawRect(r.left + mPadding, r.top + mPadding, r.right - mPadding,
- r.bottom - mPadding, paint);
- // Shadow 2
- opacity = (int) (255 * 0.24);
- paint.setShadowLayer(mShadowRadius, 0, mShadowRadius, Color.argb(opacity, 0, 0, 0));
- canvas.drawRect(r.left + mPadding, r.top + mPadding, r.right - mPadding,
- r.bottom - mPadding, paint);
+
+ // Layers on the canvas (from bottom to top):
+ // 1. Two shadows for the additional drag layer (if drag file count > 1)
+ // 2. The additional layer view itself (if drag file count > 1)
+ // 3. Two shadows for the drag content layer (icon, title)
+ // 4. The drag content layer itself
+ final int shadowOneOpacity = (int) (255 * 0.15);
+ final int shadowTwoOpacity = (int) (255 * 0.30);
+ if (mAdditionalShadowView != null && mDragFileCount > 1) {
+ mAdditionalShadowView.measure(
+ View.MeasureSpec.makeMeasureSpec(r.right - r.left, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(r.bottom - r.top , View.MeasureSpec.EXACTLY));
+ mAdditionalShadowView.layout(r.left, r.top, r.right, r.bottom);
+ // Shadow 1
+ paint.setShadowLayer(
+ mShadowRadius, 0, mShadowYOffset, Color.argb(shadowOneOpacity, 0, 0, 0));
+ canvas.drawRoundRect(
+ r.left + mShadowRadius,
+ r.top + mDragFileCounterOffset + mAdditionalLayerOffset,
+ r.right - mDragFileCounterOffset - mAdditionalLayerOffset,
+ r.bottom - mShadowRadius,
+ mDragContentRadius,
+ mDragContentRadius,
+ paint);
+ // Shadow 2
+ paint.setShadowLayer(
+ mShadow2Radius, 0, mShadowYOffset, Color.argb(shadowTwoOpacity, 0, 0, 0));
+ canvas.drawRoundRect(
+ r.left + mShadowRadius,
+ r.top + mDragFileCounterOffset + mAdditionalLayerOffset,
+ r.right - mDragFileCounterOffset - mAdditionalLayerOffset,
+ r.bottom - mShadowRadius,
+ mDragContentRadius,
+ mDragContentRadius,
+ paint);
+ mAdditionalShadowView.draw(canvas);
+ }
+
+ if (isUseMaterial3FlagEnabled()) {
+ // Shadow 1
+ paint.setShadowLayer(
+ mShadowRadius, 0, mShadowYOffset, Color.argb(shadowOneOpacity, 0, 0, 0));
+ canvas.drawRoundRect(
+ r.left + mShadowRadius + mAdditionalLayerOffset,
+ r.top + mDragFileCounterOffset,
+ r.right - mDragFileCounterOffset,
+ r.bottom - mShadowRadius - mAdditionalLayerOffset,
+ mDragContentRadius,
+ mDragContentRadius,
+ paint);
+ // Shadow 2
+ paint.setShadowLayer(
+ mShadow2Radius, 0, mShadowYOffset, Color.argb(shadowTwoOpacity, 0, 0, 0));
+ canvas.drawRoundRect(
+ r.left + mShadowRadius + mAdditionalLayerOffset,
+ r.top + mDragFileCounterOffset,
+ r.right - mDragFileCounterOffset,
+ r.bottom - mShadowRadius - mAdditionalLayerOffset,
+ mDragContentRadius,
+ mDragContentRadius,
+ paint);
+ } else {
+ // Shadow 1
+ int opacity = (int) (255 * 0.1);
+ paint.setShadowLayer(mShadowRadius, 0, 0, Color.argb(opacity, 0, 0, 0));
+ canvas.drawRect(r.left + mPadding, r.top + mPadding, r.right - mPadding,
+ r.bottom - mPadding, paint);
+ // Shadow 2
+ opacity = (int) (255 * 0.24);
+ paint.setShadowLayer(mShadowRadius, 0, mShadowRadius, Color.argb(opacity, 0, 0, 0));
+ canvas.drawRect(r.left + mPadding, r.top + mPadding, r.right - mPadding,
+ r.bottom - mPadding, paint);
+ }
mShadowView.draw(canvas);
}
@@ -98,4 +199,19 @@ class DragShadowBuilder extends View.DragShadowBuilder {
void onStateUpdated(@State int state) {
mIcon.updateState(state);
}
+
+ void updateDragFileCount(int count) {
+ if (!isUseMaterial3FlagEnabled()) {
+ return;
+ }
+ mDragFileCount = count;
+ TextView dragFileCountView = mShadowView.findViewById(R.id.drag_file_counter);
+ if (dragFileCountView != null) {
+ dragFileCountView.setVisibility(count > 1 ? View.VISIBLE : View.GONE);
+ if (count > 1) {
+ NumberFormat numberFormat = NumberFormat.getInstance();
+ dragFileCountView.setText(numberFormat.format(count));
+ }
+ }
+ }
}