Loading perf-tests/src/com/android/documentsui/FilesJankPerfTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -49,7 +49,7 @@ public class FilesJankPerfTest extends JankTestBase { final UiDevice device = UiDevice.getInstance(getInstrumentation()); final Context context = getInstrumentation().getTargetContext(); final UiAutomation automation = getInstrumentation().getUiAutomation(); mRootsListBot = new SidebarBot(device, context, BOT_TIMEOUT); mRootsListBot = new SidebarBot(device, automation, context, BOT_TIMEOUT); mDirListBot = new DirectoryListBot(device, automation, context, BOT_TIMEOUT); final Intent intent = new Intent(context, FilesActivity.class); Loading src/com/android/documentsui/clipping/RuntimeDocumentClipper.java +7 −2 Original line number Diff line number Diff line Loading @@ -31,7 +31,6 @@ import androidx.recyclerview.selection.Selection; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.Features; import com.android.documentsui.base.Shared; import com.android.documentsui.services.FileOperation; import com.android.documentsui.services.FileOperationService; Loading Loading @@ -240,7 +239,13 @@ final class RuntimeDocumentClipper implements DocumentClipper { @Nullable ClipData clipData, FileOperations.Callback callback) { DocumentStack dstStack = new DocumentStack(docStack, destination); // In the case where a destination is actually a root, the docStack contains a single value // of the root. We can avoid copying and recreating a new `DocumentStack` here as the // `docStack` is sufficiently describing the destination. DocumentStack dstStack = (docStack != null && docStack.size() == 1 && docStack.get(0).equals(destination)) ? docStack : new DocumentStack(docStack, destination); copyFromClipData(dstStack, clipData, callback); } Loading tests/common/com/android/documentsui/bots/Bots.java +53 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import static junit.framework.Assert.assertNotNull; import android.app.UiAutomation; import android.content.Context; import android.os.SystemClock; import android.view.MotionEvent; import androidx.test.InstrumentationRegistry; import androidx.test.uiautomator.By; Loading Loading @@ -53,7 +55,7 @@ public final class Bots { public Bots(UiDevice device, UiAutomation automation, Context context, int timeout) { main = new UiBot(device, context, TIMEOUT); breadcrumb = new BreadBot(device, context, TIMEOUT); roots = new SidebarBot(device, context, TIMEOUT); roots = new SidebarBot(device, automation, context, TIMEOUT); directory = new DirectoryListBot(device, automation, context, TIMEOUT); sort = new SortBot(device, context, TIMEOUT, main); keyboard = new KeyboardBot(device, context, TIMEOUT); Loading @@ -71,9 +73,9 @@ public final class Bots { */ public static abstract class BaseBot { public final UiDevice mDevice; public final String mTargetPackage; final Context mContext; final int mTimeout; public final String mTargetPackage; BaseBot(UiDevice device, Context context, int timeout) { mDevice = device; Loading @@ -84,6 +86,55 @@ public final class Bots { .getTargetContext().getPackageName(); } /** * Returns a `MotionEvent` that mocks a right click. * There are 2 ways right clicks are intercepted throughout DocumentsUI: * 1. Via an onClickListener and thus the actions can simply be one of ACTION_DOWN and * ACTION_UP. * 2. Via an onGenericMotionListener and therefore there needs to be 4 actions, * ACTION_DOWN, ACTION_BUTTON_PRESS, ACTION_BUTTON_RELEASE and ACTION_UP. */ protected static MotionEvent getTestRightClickMotionEvent(int action, int x, int y) { long eventTime = SystemClock.uptimeMillis(); MotionEvent.PointerProperties[] pp = {new MotionEvent.PointerProperties()}; pp[0].clear(); pp[0].id = 0; pp[0].toolType = MotionEvent.TOOL_TYPE_MOUSE; MotionEvent.PointerCoords[] pointerCoords = {new MotionEvent.PointerCoords()}; pointerCoords[0].clear(); pointerCoords[0].x = x; pointerCoords[0].y = y; pointerCoords[0].pressure = 0; pointerCoords[0].size = 1; MotionEvent event = MotionEvent.obtain( eventTime, eventTime, action, 1, // pointerCount. pp, pointerCoords, 0, // metaState. MotionEvent.BUTTON_SECONDARY, 1f, // xPrecision. 1f, // yPrecision. 0, // deviceId. 0, // edgeFlags. android.view.InputDevice.SOURCE_MOUSE, 0 // flags. ); if (action == MotionEvent.ACTION_BUTTON_PRESS || action == MotionEvent.ACTION_BUTTON_RELEASE) { event.setActionButton(MotionEvent.BUTTON_SECONDARY); } return event; } /** * Asserts that the specified view or one of its descendents has focus. */ Loading tests/common/com/android/documentsui/bots/DirectoryListBot.java +5 −49 Original line number Diff line number Diff line Loading @@ -29,7 +29,6 @@ import android.content.Context; import android.graphics.Point; import android.graphics.Rect; import android.os.SystemClock; import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; Loading Loading @@ -328,60 +327,17 @@ public class DirectoryListBot extends Bots.BaseBot { public void rightClickDocument(Point point) throws UiObjectNotFoundException { // TODO: Use Espresso instead of doing the events mock ourselves MotionEvent motionDown = getTestMotionEvent( MotionEvent.ACTION_DOWN, MotionEvent.BUTTON_SECONDARY, MotionEvent.TOOL_TYPE_MOUSE, InputDevice.SOURCE_MOUSE, point.x, point.y); MotionEvent motionDown = getTestRightClickMotionEvent(MotionEvent.ACTION_DOWN, point.x, point.y); mAutomation.injectInputEvent(motionDown, true); SystemClock.sleep(100); MotionEvent motionUp = getTestMotionEvent( MotionEvent.ACTION_UP, MotionEvent.BUTTON_SECONDARY, MotionEvent.TOOL_TYPE_MOUSE, InputDevice.SOURCE_MOUSE, point.x, point.y); MotionEvent motionUp = getTestRightClickMotionEvent(MotionEvent.ACTION_UP, point.x, point.y); mAutomation.injectInputEvent(motionUp, true); } private MotionEvent getTestMotionEvent( int action, int buttonState, int toolType, int source, int x, int y) { long eventTime = SystemClock.uptimeMillis(); MotionEvent.PointerProperties[] pp = {new MotionEvent.PointerProperties()}; pp[0].clear(); pp[0].id = 0; pp[0].toolType = toolType; MotionEvent.PointerCoords[] pointerCoords = {new MotionEvent.PointerCoords()}; pointerCoords[0].clear(); pointerCoords[0].x = x; pointerCoords[0].y = y; pointerCoords[0].pressure = 0; pointerCoords[0].size = 1; return MotionEvent.obtain( eventTime, eventTime, action, 1, pp, pointerCoords, 0, buttonState, 1f, 1f, 0, 0, source, 0); } private void assertOrder(String first, String second) throws UiObjectNotFoundException { final UiObject firstObj = findDocument(first); Loading tests/common/com/android/documentsui/bots/SidebarBot.java +38 −1 Original line number Diff line number Diff line Loading @@ -21,8 +21,12 @@ import static androidx.test.espresso.action.ViewActions.swipeLeft; import static androidx.test.espresso.action.ViewActions.swipeRight; import static androidx.test.espresso.matcher.ViewMatchers.withId; import android.app.UiAutomation; import android.content.Context; import android.graphics.Rect; import android.os.SystemClock; import android.util.Log; import android.view.MotionEvent; import android.view.View; import androidx.test.uiautomator.UiDevice; Loading @@ -47,9 +51,11 @@ public class SidebarBot extends Bots.BaseBot { private static final String TAG = "RootsListBot"; private final String mRootListId; private final UiAutomation mAutomation; public SidebarBot(UiDevice device, Context context, int timeout) { public SidebarBot(UiDevice device, UiAutomation automation, Context context, int timeout) { super(device, context, timeout); mAutomation = automation; mRootListId = mTargetPackage + ":id/roots_list"; } Loading Loading @@ -135,4 +141,35 @@ public class SidebarBot extends Bots.BaseBot { public void assertHasFocus() { assertHasFocus(mRootListId); } /** Right clicks a root with `label`. */ public void rightClickRoot(String label) throws UiObjectNotFoundException { Rect point = findRoot(label).getVisibleBounds(); // The RootsFragment listens to right clicks in the GenericMotionListener. This is to allow // for a left and right click to be used interchangeably. This means to mock this behaviour, // 4 input events needs to be synthesized. A down, button press, button release and an up. MotionEvent motionDown = getTestRightClickMotionEvent( MotionEvent.ACTION_DOWN, point.centerX(), point.centerY()); mAutomation.injectInputEvent(motionDown, true); SystemClock.sleep(25); MotionEvent motionButtonPress = getTestRightClickMotionEvent( MotionEvent.ACTION_BUTTON_PRESS, point.centerX(), point.centerY()); mAutomation.injectInputEvent(motionButtonPress, true); SystemClock.sleep(25); MotionEvent motionButtonRelease = getTestRightClickMotionEvent( MotionEvent.ACTION_BUTTON_RELEASE, point.centerX(), point.centerY()); mAutomation.injectInputEvent(motionButtonRelease, true); SystemClock.sleep(25); MotionEvent motionUp = getTestRightClickMotionEvent( MotionEvent.ACTION_UP, point.centerX(), point.centerY()); mAutomation.injectInputEvent(motionUp, true); } } Loading
perf-tests/src/com/android/documentsui/FilesJankPerfTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -49,7 +49,7 @@ public class FilesJankPerfTest extends JankTestBase { final UiDevice device = UiDevice.getInstance(getInstrumentation()); final Context context = getInstrumentation().getTargetContext(); final UiAutomation automation = getInstrumentation().getUiAutomation(); mRootsListBot = new SidebarBot(device, context, BOT_TIMEOUT); mRootsListBot = new SidebarBot(device, automation, context, BOT_TIMEOUT); mDirListBot = new DirectoryListBot(device, automation, context, BOT_TIMEOUT); final Intent intent = new Intent(context, FilesActivity.class); Loading
src/com/android/documentsui/clipping/RuntimeDocumentClipper.java +7 −2 Original line number Diff line number Diff line Loading @@ -31,7 +31,6 @@ import androidx.recyclerview.selection.Selection; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.Features; import com.android.documentsui.base.Shared; import com.android.documentsui.services.FileOperation; import com.android.documentsui.services.FileOperationService; Loading Loading @@ -240,7 +239,13 @@ final class RuntimeDocumentClipper implements DocumentClipper { @Nullable ClipData clipData, FileOperations.Callback callback) { DocumentStack dstStack = new DocumentStack(docStack, destination); // In the case where a destination is actually a root, the docStack contains a single value // of the root. We can avoid copying and recreating a new `DocumentStack` here as the // `docStack` is sufficiently describing the destination. DocumentStack dstStack = (docStack != null && docStack.size() == 1 && docStack.get(0).equals(destination)) ? docStack : new DocumentStack(docStack, destination); copyFromClipData(dstStack, clipData, callback); } Loading
tests/common/com/android/documentsui/bots/Bots.java +53 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import static junit.framework.Assert.assertNotNull; import android.app.UiAutomation; import android.content.Context; import android.os.SystemClock; import android.view.MotionEvent; import androidx.test.InstrumentationRegistry; import androidx.test.uiautomator.By; Loading Loading @@ -53,7 +55,7 @@ public final class Bots { public Bots(UiDevice device, UiAutomation automation, Context context, int timeout) { main = new UiBot(device, context, TIMEOUT); breadcrumb = new BreadBot(device, context, TIMEOUT); roots = new SidebarBot(device, context, TIMEOUT); roots = new SidebarBot(device, automation, context, TIMEOUT); directory = new DirectoryListBot(device, automation, context, TIMEOUT); sort = new SortBot(device, context, TIMEOUT, main); keyboard = new KeyboardBot(device, context, TIMEOUT); Loading @@ -71,9 +73,9 @@ public final class Bots { */ public static abstract class BaseBot { public final UiDevice mDevice; public final String mTargetPackage; final Context mContext; final int mTimeout; public final String mTargetPackage; BaseBot(UiDevice device, Context context, int timeout) { mDevice = device; Loading @@ -84,6 +86,55 @@ public final class Bots { .getTargetContext().getPackageName(); } /** * Returns a `MotionEvent` that mocks a right click. * There are 2 ways right clicks are intercepted throughout DocumentsUI: * 1. Via an onClickListener and thus the actions can simply be one of ACTION_DOWN and * ACTION_UP. * 2. Via an onGenericMotionListener and therefore there needs to be 4 actions, * ACTION_DOWN, ACTION_BUTTON_PRESS, ACTION_BUTTON_RELEASE and ACTION_UP. */ protected static MotionEvent getTestRightClickMotionEvent(int action, int x, int y) { long eventTime = SystemClock.uptimeMillis(); MotionEvent.PointerProperties[] pp = {new MotionEvent.PointerProperties()}; pp[0].clear(); pp[0].id = 0; pp[0].toolType = MotionEvent.TOOL_TYPE_MOUSE; MotionEvent.PointerCoords[] pointerCoords = {new MotionEvent.PointerCoords()}; pointerCoords[0].clear(); pointerCoords[0].x = x; pointerCoords[0].y = y; pointerCoords[0].pressure = 0; pointerCoords[0].size = 1; MotionEvent event = MotionEvent.obtain( eventTime, eventTime, action, 1, // pointerCount. pp, pointerCoords, 0, // metaState. MotionEvent.BUTTON_SECONDARY, 1f, // xPrecision. 1f, // yPrecision. 0, // deviceId. 0, // edgeFlags. android.view.InputDevice.SOURCE_MOUSE, 0 // flags. ); if (action == MotionEvent.ACTION_BUTTON_PRESS || action == MotionEvent.ACTION_BUTTON_RELEASE) { event.setActionButton(MotionEvent.BUTTON_SECONDARY); } return event; } /** * Asserts that the specified view or one of its descendents has focus. */ Loading
tests/common/com/android/documentsui/bots/DirectoryListBot.java +5 −49 Original line number Diff line number Diff line Loading @@ -29,7 +29,6 @@ import android.content.Context; import android.graphics.Point; import android.graphics.Rect; import android.os.SystemClock; import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; Loading Loading @@ -328,60 +327,17 @@ public class DirectoryListBot extends Bots.BaseBot { public void rightClickDocument(Point point) throws UiObjectNotFoundException { // TODO: Use Espresso instead of doing the events mock ourselves MotionEvent motionDown = getTestMotionEvent( MotionEvent.ACTION_DOWN, MotionEvent.BUTTON_SECONDARY, MotionEvent.TOOL_TYPE_MOUSE, InputDevice.SOURCE_MOUSE, point.x, point.y); MotionEvent motionDown = getTestRightClickMotionEvent(MotionEvent.ACTION_DOWN, point.x, point.y); mAutomation.injectInputEvent(motionDown, true); SystemClock.sleep(100); MotionEvent motionUp = getTestMotionEvent( MotionEvent.ACTION_UP, MotionEvent.BUTTON_SECONDARY, MotionEvent.TOOL_TYPE_MOUSE, InputDevice.SOURCE_MOUSE, point.x, point.y); MotionEvent motionUp = getTestRightClickMotionEvent(MotionEvent.ACTION_UP, point.x, point.y); mAutomation.injectInputEvent(motionUp, true); } private MotionEvent getTestMotionEvent( int action, int buttonState, int toolType, int source, int x, int y) { long eventTime = SystemClock.uptimeMillis(); MotionEvent.PointerProperties[] pp = {new MotionEvent.PointerProperties()}; pp[0].clear(); pp[0].id = 0; pp[0].toolType = toolType; MotionEvent.PointerCoords[] pointerCoords = {new MotionEvent.PointerCoords()}; pointerCoords[0].clear(); pointerCoords[0].x = x; pointerCoords[0].y = y; pointerCoords[0].pressure = 0; pointerCoords[0].size = 1; return MotionEvent.obtain( eventTime, eventTime, action, 1, pp, pointerCoords, 0, buttonState, 1f, 1f, 0, 0, source, 0); } private void assertOrder(String first, String second) throws UiObjectNotFoundException { final UiObject firstObj = findDocument(first); Loading
tests/common/com/android/documentsui/bots/SidebarBot.java +38 −1 Original line number Diff line number Diff line Loading @@ -21,8 +21,12 @@ import static androidx.test.espresso.action.ViewActions.swipeLeft; import static androidx.test.espresso.action.ViewActions.swipeRight; import static androidx.test.espresso.matcher.ViewMatchers.withId; import android.app.UiAutomation; import android.content.Context; import android.graphics.Rect; import android.os.SystemClock; import android.util.Log; import android.view.MotionEvent; import android.view.View; import androidx.test.uiautomator.UiDevice; Loading @@ -47,9 +51,11 @@ public class SidebarBot extends Bots.BaseBot { private static final String TAG = "RootsListBot"; private final String mRootListId; private final UiAutomation mAutomation; public SidebarBot(UiDevice device, Context context, int timeout) { public SidebarBot(UiDevice device, UiAutomation automation, Context context, int timeout) { super(device, context, timeout); mAutomation = automation; mRootListId = mTargetPackage + ":id/roots_list"; } Loading Loading @@ -135,4 +141,35 @@ public class SidebarBot extends Bots.BaseBot { public void assertHasFocus() { assertHasFocus(mRootListId); } /** Right clicks a root with `label`. */ public void rightClickRoot(String label) throws UiObjectNotFoundException { Rect point = findRoot(label).getVisibleBounds(); // The RootsFragment listens to right clicks in the GenericMotionListener. This is to allow // for a left and right click to be used interchangeably. This means to mock this behaviour, // 4 input events needs to be synthesized. A down, button press, button release and an up. MotionEvent motionDown = getTestRightClickMotionEvent( MotionEvent.ACTION_DOWN, point.centerX(), point.centerY()); mAutomation.injectInputEvent(motionDown, true); SystemClock.sleep(25); MotionEvent motionButtonPress = getTestRightClickMotionEvent( MotionEvent.ACTION_BUTTON_PRESS, point.centerX(), point.centerY()); mAutomation.injectInputEvent(motionButtonPress, true); SystemClock.sleep(25); MotionEvent motionButtonRelease = getTestRightClickMotionEvent( MotionEvent.ACTION_BUTTON_RELEASE, point.centerX(), point.centerY()); mAutomation.injectInputEvent(motionButtonRelease, true); SystemClock.sleep(25); MotionEvent motionUp = getTestRightClickMotionEvent( MotionEvent.ACTION_UP, point.centerX(), point.centerY()); mAutomation.injectInputEvent(motionUp, true); } }