diff options
author | 2025-03-10 06:28:53 +0000 | |
---|---|---|
committer | 2025-03-13 03:13:54 +0000 | |
commit | 165058c81c7d402cf6580e57f5efb7dd009e941d (patch) | |
tree | 9ac17c67b71deeb95b5174a4e10760566a83908a /src | |
parent | 595ae7b5cb5550b63fa29d1a2e664e4ea8101ed2 (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')
-rw-r--r-- | src/com/android/documentsui/DragAndDropManager.java | 10 | ||||
-rw-r--r-- | src/com/android/documentsui/DragShadowBuilder.java | 142 |
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)); + } + } + } } |