Merge "Fixing scrolling up in App Apps." into ub-launcher3-master
This commit is contained in:
commit
e98aab058e
|
@ -602,4 +602,8 @@ public final class Utilities {
|
|||
msg.setAsynchronous(true);
|
||||
handler.sendMessage(msg);
|
||||
}
|
||||
|
||||
public interface Consumer<T> {
|
||||
void accept(T var1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import android.graphics.Canvas;
|
|||
import android.graphics.Paint;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.os.Process;
|
||||
import android.support.animation.DynamicAnimation;
|
||||
import android.support.annotation.NonNull;
|
||||
|
@ -48,6 +49,7 @@ import com.android.launcher3.ItemInfo;
|
|||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.keyboard.FocusedItemDecorator;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
|
||||
|
@ -549,4 +551,16 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
|||
&& verticalFadingEdge);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performAccessibilityAction(int action, Bundle arguments) {
|
||||
if (AccessibilityManagerCompat.processTestRequest(
|
||||
mLauncher, "TAPL_GET_SCROLL", action, arguments,
|
||||
response ->
|
||||
response.putInt("scrollY", getActiveRecyclerView().getCurrentScrollY()))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.performAccessibilityAction(action, arguments);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,11 @@ package com.android.launcher3.compat;
|
|||
|
||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
|
||||
|
@ -49,17 +51,60 @@ public class AccessibilityManagerCompat {
|
|||
}
|
||||
|
||||
public static void sendEventToTest(Context context, String eventTag) {
|
||||
if (!Utilities.IS_RUNNING_IN_TEST_HARNESS) return;
|
||||
final AccessibilityManager accessibilityManager = getAccessibilityManagerForTest(context);
|
||||
if (accessibilityManager == null) return;
|
||||
|
||||
sendEventToTest(accessibilityManager, eventTag, null);
|
||||
}
|
||||
|
||||
private static void sendEventToTest(
|
||||
AccessibilityManager accessibilityManager, String eventTag, Bundle data) {
|
||||
final AccessibilityEvent e = AccessibilityEvent.obtain(
|
||||
AccessibilityEvent.TYPE_ANNOUNCEMENT);
|
||||
e.setClassName(eventTag);
|
||||
e.setParcelableData(data);
|
||||
accessibilityManager.sendAccessibilityEvent(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns accessibility manager to be used for communication with UI Automation tests.
|
||||
* The tests may exchange custom accessibility messages with the launcher; the accessibility
|
||||
* manager is used in these communications.
|
||||
*
|
||||
* If the launcher runs not under a test, the return is null, and no attempt to process or send
|
||||
* custom accessibility messages should be made.
|
||||
*/
|
||||
private static AccessibilityManager getAccessibilityManagerForTest(Context context) {
|
||||
// If not running in a test harness, don't participate in test exchanges.
|
||||
if (!Utilities.IS_RUNNING_IN_TEST_HARNESS) return null;
|
||||
|
||||
// Additional safety check: when running under UI Automation, accessibility is enabled,
|
||||
// but the list of accessibility services is empty. Return null if this is not the case.
|
||||
final AccessibilityManager accessibilityManager = getManager(context);
|
||||
if (accessibilityManager.isEnabled() &&
|
||||
if (!accessibilityManager.isEnabled() ||
|
||||
accessibilityManager.getEnabledAccessibilityServiceList(
|
||||
AccessibilityServiceInfo.FEEDBACK_ALL_MASK).size() == 0) {
|
||||
|
||||
final AccessibilityEvent e = AccessibilityEvent.obtain(
|
||||
AccessibilityEvent.TYPE_ANNOUNCEMENT);
|
||||
e.setClassName(eventTag);
|
||||
accessibilityManager.sendAccessibilityEvent(e);
|
||||
AccessibilityServiceInfo.FEEDBACK_ALL_MASK).size() > 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return accessibilityManager;
|
||||
}
|
||||
|
||||
public static boolean processTestRequest(Context context, String eventTag, int action,
|
||||
Bundle request, Utilities.Consumer<Bundle> responseFiller) {
|
||||
final AccessibilityManager accessibilityManager = getAccessibilityManagerForTest(context);
|
||||
if (accessibilityManager == null) return false;
|
||||
|
||||
// The test sends a request via a ACTION_SET_TEXT.
|
||||
if (action == AccessibilityNodeInfo.ACTION_SET_TEXT &&
|
||||
eventTag.equals(request.getCharSequence(
|
||||
AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE))) {
|
||||
final Bundle response = new Bundle();
|
||||
responseFiller.accept(response);
|
||||
AccessibilityManagerCompat.sendEventToTest(
|
||||
accessibilityManager, eventTag + "_RESPONSE", response);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,28 +72,33 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer {
|
|||
return new AppIcon(mLauncher, appIcon);
|
||||
}
|
||||
|
||||
protected int getBottomMarginForSwipeUp() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
private void scrollBackToBeginning() {
|
||||
final UiObject2 allAppsContainer = verifyActiveContainer();
|
||||
final UiObject2 searchBox =
|
||||
mLauncher.waitForObjectInContainer(allAppsContainer, "search_container_all_apps");
|
||||
|
||||
int attempts = 0;
|
||||
allAppsContainer.setGestureMargins(5, 600, 5, getBottomMarginForSwipeUp());
|
||||
allAppsContainer.setGestureMargins(0, searchBox.getVisibleBounds().bottom + 1, 0, 5);
|
||||
|
||||
while (allAppsContainer.scroll(Direction.UP, 0.5f)) {
|
||||
mLauncher.waitForIdle();
|
||||
verifyActiveContainer();
|
||||
for (int scroll = getScroll(allAppsContainer);
|
||||
scroll != 0;
|
||||
scroll = getScroll(allAppsContainer)) {
|
||||
assertTrue("Negative scroll position", scroll > 0);
|
||||
|
||||
assertTrue("Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
|
||||
++attempts <= MAX_SCROLL_ATTEMPTS);
|
||||
|
||||
allAppsContainer.scroll(Direction.UP, 1);
|
||||
}
|
||||
|
||||
mLauncher.waitForIdle();
|
||||
verifyActiveContainer();
|
||||
}
|
||||
|
||||
private int getScroll(UiObject2 allAppsContainer) {
|
||||
return mLauncher.getAnswerFromLauncher(allAppsContainer, "TAPL_GET_SCROLL").
|
||||
getInt("scrollY", -1);
|
||||
}
|
||||
|
||||
private void ensureIconVisible(UiObject2 appIcon, UiObject2 allAppsContainer) {
|
||||
final int appHeight = appIcon.getVisibleBounds().height();
|
||||
if (appHeight < MIN_INTERACT_SIZE) {
|
||||
|
|
|
@ -30,11 +30,6 @@ public final class AllAppsFromOverview extends AllApps {
|
|||
verifyActiveContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getBottomMarginForSwipeUp() {
|
||||
return 600;
|
||||
}
|
||||
|
||||
/**
|
||||
* Swipes down to switch back to Overview whence we came from.
|
||||
*
|
||||
|
|
|
@ -23,6 +23,7 @@ import static org.junit.Assert.fail;
|
|||
import android.app.ActivityManager;
|
||||
import android.app.UiAutomation;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
@ -32,8 +33,7 @@ import android.support.test.uiautomator.BySelector;
|
|||
import android.support.test.uiautomator.UiDevice;
|
||||
import android.support.test.uiautomator.UiObject2;
|
||||
import android.support.test.uiautomator.Until;
|
||||
|
||||
import org.junit.Assert;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
@ -156,18 +156,30 @@ public final class LauncherInstrumentation {
|
|||
}
|
||||
}
|
||||
|
||||
private void executeAndWaitForEvent(Runnable command,
|
||||
private Bundle executeAndWaitForEvent(Runnable command,
|
||||
UiAutomation.AccessibilityEventFilter eventFilter, String message) {
|
||||
try {
|
||||
assertNotNull("executeAndWaitForEvent returned null (this can't happen)",
|
||||
final AccessibilityEvent event =
|
||||
InstrumentationRegistry.getInstrumentation().getUiAutomation()
|
||||
.executeAndWaitForEvent(
|
||||
command, eventFilter, WAIT_TIME_MS));
|
||||
command, eventFilter, WAIT_TIME_MS);
|
||||
assertNotNull("executeAndWaitForEvent returned null (this can't happen)", event);
|
||||
return (Bundle) event.getParcelableData();
|
||||
} catch (TimeoutException e) {
|
||||
fail(message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Bundle getAnswerFromLauncher(UiObject2 view, String requestTag) {
|
||||
// Send a fake set-text request to Launcher to initiate a response with requested data.
|
||||
final String responseTag = requestTag + "_RESPONSE";
|
||||
return executeAndWaitForEvent(
|
||||
() -> view.setText(requestTag),
|
||||
event -> responseTag.equals(event.getClassName()),
|
||||
"Launcher didn't respond to request: " + requestTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Presses nav bar home button.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue