Loading res/values/strings.xml +4 −0 Original line number Original line Diff line number Diff line Loading @@ -534,4 +534,8 @@ <!-- Accessibility label to indicate the subject(e.g. file/folder) is from work profile --> <!-- Accessibility label to indicate the subject(e.g. file/folder) is from work profile --> <string name="a11y_work">Work</string> <string name="a11y_work">Work</string> <!-- Snackbar shown when users drag and drop files from another app to DocumentsUI. [CHAR_LIMIT=100] --> <string name="drag_from_another_app">Drag from another app not allowed.</string> </resources> </resources> src/com/android/documentsui/DragAndDropManager.java +18 −3 Original line number Original line Diff line number Diff line Loading @@ -16,18 +16,19 @@ package com.android.documentsui; package com.android.documentsui; import androidx.annotation.IntDef; import androidx.annotation.Nullable; import android.content.ClipData; import android.content.ClipData; import android.content.Context; import android.content.Context; import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.net.Uri; import android.provider.DocumentsContract; import android.provider.DocumentsContract; import androidx.annotation.VisibleForTesting; import android.view.DragEvent; import android.view.DragEvent; import android.view.KeyEvent; import android.view.KeyEvent; import android.view.View; import android.view.View; import androidx.annotation.IntDef; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.documentsui.MenuManager.SelectionDetails; import com.android.documentsui.MenuManager.SelectionDetails; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.DocumentStack; Loading Loading @@ -118,6 +119,12 @@ public interface DragAndDropManager { */ */ void resetState(View v); void resetState(View v); /** * Checks whether the drag was initiated from FilesApp. * @return true if initiated from Files app. */ boolean isDragFromSameApp(); /** /** * Drops items onto the a root. * Drops items onto the a root. * * Loading Loading @@ -165,6 +172,7 @@ public interface DragAndDropManager { private final Drawable mDefaultShadowIcon; private final Drawable mDefaultShadowIcon; private @State int mState = STATE_UNKNOWN; private @State int mState = STATE_UNKNOWN; private boolean mDragInitiated = false; // Key events info. This is used to derive state when user drags items into a view to derive // Key events info. This is used to derive state when user drags items into a view to derive // type of file operations. // type of file operations. Loading Loading @@ -233,6 +241,7 @@ public interface DragAndDropManager { IconHelper iconHelper, IconHelper iconHelper, @Nullable DocumentInfo parent) { @Nullable DocumentInfo parent) { mDragInitiated = true; mView = v; mView = v; mInvalidDest = invalidDest; mInvalidDest = invalidDest; mMustBeCopied = !selectionDetails.canDelete(); mMustBeCopied = !selectionDetails.canDelete(); Loading Loading @@ -355,6 +364,11 @@ public interface DragAndDropManager { updateState(STATE_UNKNOWN); updateState(STATE_UNKNOWN); } } @Override public boolean isDragFromSameApp() { return mDragInitiated; } private void updateState(@State int state) { private void updateState(@State int state) { mState = state; mState = state; Loading Loading @@ -461,6 +475,7 @@ public interface DragAndDropManager { mDestDoc = null; mDestDoc = null; mDestRoot = null; mDestRoot = null; mMustBeCopied = false; mMustBeCopied = false; mDragInitiated = false; } } private @OpType int calculateOpType(ClipData clipData, RootInfo destRoot) { private @OpType int calculateOpType(ClipData clipData, RootInfo destRoot) { Loading src/com/android/documentsui/ItemDragListener.java +3 −6 Original line number Original line Diff line number Diff line Loading @@ -23,9 +23,10 @@ import android.view.DragEvent; import android.view.View; import android.view.View; import android.view.View.OnDragListener; import android.view.View.OnDragListener; import com.android.documentsui.ItemDragListener.DragHost; import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting; import com.android.documentsui.ItemDragListener.DragHost; import java.util.Timer; import java.util.Timer; import java.util.TimerTask; import java.util.TimerTask; Loading Loading @@ -63,13 +64,9 @@ public class ItemDragListener<H extends DragHost> implements OnDragListener { @Override @Override public boolean onDrag(final View v, DragEvent event) { public boolean onDrag(final View v, DragEvent event) { if (!mDragHost.canHandleDragEvent(v)) { return false; } switch (event.getAction()) { switch (event.getAction()) { case DragEvent.ACTION_DRAG_STARTED: case DragEvent.ACTION_DRAG_STARTED: return true; return mDragHost.canHandleDragEvent(v); case DragEvent.ACTION_DRAG_ENTERED: case DragEvent.ACTION_DRAG_ENTERED: handleEnteredEvent(v, event); handleEnteredEvent(v, event); return true; return true; Loading src/com/android/documentsui/dirlist/DragHost.java +13 −0 Original line number Original line Diff line number Diff line Loading @@ -30,12 +30,15 @@ import com.android.documentsui.AbstractActionHandler; import com.android.documentsui.AbstractDragHost; import com.android.documentsui.AbstractDragHost; import com.android.documentsui.ActionHandler; import com.android.documentsui.ActionHandler; import com.android.documentsui.DragAndDropManager; import com.android.documentsui.DragAndDropManager; import com.android.documentsui.R; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.Lookup; import com.android.documentsui.base.Lookup; import com.android.documentsui.base.State; import com.android.documentsui.base.State; import com.android.documentsui.ui.DialogController; import com.android.documentsui.ui.DialogController; import com.google.android.material.snackbar.Snackbar; import java.util.function.Predicate; import java.util.function.Predicate; /** /** Loading Loading @@ -105,6 +108,16 @@ class DragHost<T extends Activity & AbstractActionHandler.CommonAddons> extends mDragAndDropManager.updateState(v, mState.stack.getRoot(), mDestinationLookup.lookup(v)); mDragAndDropManager.updateState(v, mState.stack.getRoot(), mDestinationLookup.lookup(v)); } } @Override public boolean canHandleDragEvent(View v) { if (!mDragAndDropManager.isDragFromSameApp()) { Snackbar.make( v, R.string.drag_from_another_app, Snackbar.LENGTH_SHORT).show(); return false; } return true; } boolean canSpringOpen(View v) { boolean canSpringOpen(View v) { DocumentInfo doc = mDestinationLookup.lookup(v); DocumentInfo doc = mDestinationLookup.lookup(v); return (doc != null) && mDragAndDropManager.canSpringOpen(mState.stack.getRoot(), doc); return (doc != null) && mDragAndDropManager.canSpringOpen(mState.stack.getRoot(), doc); Loading tests/common/com/android/documentsui/testing/TestDragAndDropManager.java +7 −2 Original line number Original line Diff line number Diff line Loading @@ -16,16 +16,16 @@ package com.android.documentsui.testing; package com.android.documentsui.testing; import androidx.annotation.Nullable; import android.content.ClipData; import android.content.ClipData; import android.net.Uri; import android.net.Uri; import android.util.Pair; import android.util.Pair; import android.view.KeyEvent; import android.view.KeyEvent; import android.view.View; import android.view.View; import androidx.annotation.Nullable; import com.android.documentsui.ActionHandler; import com.android.documentsui.ActionHandler; import com.android.documentsui.DragAndDropManager; import com.android.documentsui.DragAndDropManager; import com.android.documentsui.MenuManager; import com.android.documentsui.MenuManager.SelectionDetails; import com.android.documentsui.MenuManager.SelectionDetails; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.DocumentStack; Loading Loading @@ -68,6 +68,11 @@ public class TestDragAndDropManager implements DragAndDropManager { @Override @Override public void resetState(View v) {} public void resetState(View v) {} @Override public boolean isDragFromSameApp() { return true; } @Override @Override public boolean drop(ClipData clipData, Object localState, RootInfo root, ActionHandler actions, public boolean drop(ClipData clipData, Object localState, RootInfo root, ActionHandler actions, FileOperations.Callback callback) { FileOperations.Callback callback) { Loading Loading
res/values/strings.xml +4 −0 Original line number Original line Diff line number Diff line Loading @@ -534,4 +534,8 @@ <!-- Accessibility label to indicate the subject(e.g. file/folder) is from work profile --> <!-- Accessibility label to indicate the subject(e.g. file/folder) is from work profile --> <string name="a11y_work">Work</string> <string name="a11y_work">Work</string> <!-- Snackbar shown when users drag and drop files from another app to DocumentsUI. [CHAR_LIMIT=100] --> <string name="drag_from_another_app">Drag from another app not allowed.</string> </resources> </resources>
src/com/android/documentsui/DragAndDropManager.java +18 −3 Original line number Original line Diff line number Diff line Loading @@ -16,18 +16,19 @@ package com.android.documentsui; package com.android.documentsui; import androidx.annotation.IntDef; import androidx.annotation.Nullable; import android.content.ClipData; import android.content.ClipData; import android.content.Context; import android.content.Context; import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.net.Uri; import android.provider.DocumentsContract; import android.provider.DocumentsContract; import androidx.annotation.VisibleForTesting; import android.view.DragEvent; import android.view.DragEvent; import android.view.KeyEvent; import android.view.KeyEvent; import android.view.View; import android.view.View; import androidx.annotation.IntDef; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.documentsui.MenuManager.SelectionDetails; import com.android.documentsui.MenuManager.SelectionDetails; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.DocumentStack; Loading Loading @@ -118,6 +119,12 @@ public interface DragAndDropManager { */ */ void resetState(View v); void resetState(View v); /** * Checks whether the drag was initiated from FilesApp. * @return true if initiated from Files app. */ boolean isDragFromSameApp(); /** /** * Drops items onto the a root. * Drops items onto the a root. * * Loading Loading @@ -165,6 +172,7 @@ public interface DragAndDropManager { private final Drawable mDefaultShadowIcon; private final Drawable mDefaultShadowIcon; private @State int mState = STATE_UNKNOWN; private @State int mState = STATE_UNKNOWN; private boolean mDragInitiated = false; // Key events info. This is used to derive state when user drags items into a view to derive // Key events info. This is used to derive state when user drags items into a view to derive // type of file operations. // type of file operations. Loading Loading @@ -233,6 +241,7 @@ public interface DragAndDropManager { IconHelper iconHelper, IconHelper iconHelper, @Nullable DocumentInfo parent) { @Nullable DocumentInfo parent) { mDragInitiated = true; mView = v; mView = v; mInvalidDest = invalidDest; mInvalidDest = invalidDest; mMustBeCopied = !selectionDetails.canDelete(); mMustBeCopied = !selectionDetails.canDelete(); Loading Loading @@ -355,6 +364,11 @@ public interface DragAndDropManager { updateState(STATE_UNKNOWN); updateState(STATE_UNKNOWN); } } @Override public boolean isDragFromSameApp() { return mDragInitiated; } private void updateState(@State int state) { private void updateState(@State int state) { mState = state; mState = state; Loading Loading @@ -461,6 +475,7 @@ public interface DragAndDropManager { mDestDoc = null; mDestDoc = null; mDestRoot = null; mDestRoot = null; mMustBeCopied = false; mMustBeCopied = false; mDragInitiated = false; } } private @OpType int calculateOpType(ClipData clipData, RootInfo destRoot) { private @OpType int calculateOpType(ClipData clipData, RootInfo destRoot) { Loading
src/com/android/documentsui/ItemDragListener.java +3 −6 Original line number Original line Diff line number Diff line Loading @@ -23,9 +23,10 @@ import android.view.DragEvent; import android.view.View; import android.view.View; import android.view.View.OnDragListener; import android.view.View.OnDragListener; import com.android.documentsui.ItemDragListener.DragHost; import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting; import com.android.documentsui.ItemDragListener.DragHost; import java.util.Timer; import java.util.Timer; import java.util.TimerTask; import java.util.TimerTask; Loading Loading @@ -63,13 +64,9 @@ public class ItemDragListener<H extends DragHost> implements OnDragListener { @Override @Override public boolean onDrag(final View v, DragEvent event) { public boolean onDrag(final View v, DragEvent event) { if (!mDragHost.canHandleDragEvent(v)) { return false; } switch (event.getAction()) { switch (event.getAction()) { case DragEvent.ACTION_DRAG_STARTED: case DragEvent.ACTION_DRAG_STARTED: return true; return mDragHost.canHandleDragEvent(v); case DragEvent.ACTION_DRAG_ENTERED: case DragEvent.ACTION_DRAG_ENTERED: handleEnteredEvent(v, event); handleEnteredEvent(v, event); return true; return true; Loading
src/com/android/documentsui/dirlist/DragHost.java +13 −0 Original line number Original line Diff line number Diff line Loading @@ -30,12 +30,15 @@ import com.android.documentsui.AbstractActionHandler; import com.android.documentsui.AbstractDragHost; import com.android.documentsui.AbstractDragHost; import com.android.documentsui.ActionHandler; import com.android.documentsui.ActionHandler; import com.android.documentsui.DragAndDropManager; import com.android.documentsui.DragAndDropManager; import com.android.documentsui.R; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.Lookup; import com.android.documentsui.base.Lookup; import com.android.documentsui.base.State; import com.android.documentsui.base.State; import com.android.documentsui.ui.DialogController; import com.android.documentsui.ui.DialogController; import com.google.android.material.snackbar.Snackbar; import java.util.function.Predicate; import java.util.function.Predicate; /** /** Loading Loading @@ -105,6 +108,16 @@ class DragHost<T extends Activity & AbstractActionHandler.CommonAddons> extends mDragAndDropManager.updateState(v, mState.stack.getRoot(), mDestinationLookup.lookup(v)); mDragAndDropManager.updateState(v, mState.stack.getRoot(), mDestinationLookup.lookup(v)); } } @Override public boolean canHandleDragEvent(View v) { if (!mDragAndDropManager.isDragFromSameApp()) { Snackbar.make( v, R.string.drag_from_another_app, Snackbar.LENGTH_SHORT).show(); return false; } return true; } boolean canSpringOpen(View v) { boolean canSpringOpen(View v) { DocumentInfo doc = mDestinationLookup.lookup(v); DocumentInfo doc = mDestinationLookup.lookup(v); return (doc != null) && mDragAndDropManager.canSpringOpen(mState.stack.getRoot(), doc); return (doc != null) && mDragAndDropManager.canSpringOpen(mState.stack.getRoot(), doc); Loading
tests/common/com/android/documentsui/testing/TestDragAndDropManager.java +7 −2 Original line number Original line Diff line number Diff line Loading @@ -16,16 +16,16 @@ package com.android.documentsui.testing; package com.android.documentsui.testing; import androidx.annotation.Nullable; import android.content.ClipData; import android.content.ClipData; import android.net.Uri; import android.net.Uri; import android.util.Pair; import android.util.Pair; import android.view.KeyEvent; import android.view.KeyEvent; import android.view.View; import android.view.View; import androidx.annotation.Nullable; import com.android.documentsui.ActionHandler; import com.android.documentsui.ActionHandler; import com.android.documentsui.DragAndDropManager; import com.android.documentsui.DragAndDropManager; import com.android.documentsui.MenuManager; import com.android.documentsui.MenuManager.SelectionDetails; import com.android.documentsui.MenuManager.SelectionDetails; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.DocumentStack; Loading Loading @@ -68,6 +68,11 @@ public class TestDragAndDropManager implements DragAndDropManager { @Override @Override public void resetState(View v) {} public void resetState(View v) {} @Override public boolean isDragFromSameApp() { return true; } @Override @Override public boolean drop(ClipData clipData, Object localState, RootInfo root, ActionHandler actions, public boolean drop(ClipData clipData, Object localState, RootInfo root, ActionHandler actions, FileOperations.Callback callback) { FileOperations.Callback callback) { Loading