Merge "Adding some UI tests > Launcher app from all-apps > Drag icon to all-apps and launch it > Add widget from widget tray" into ub-launcher3-calgary

This commit is contained in:
Sunny Goyal
2016-05-27 19:00:44 +00:00
committed by Android (Google) Code Review
13 changed files with 543 additions and 207 deletions
@@ -72,7 +72,7 @@ public class LauncherAppWidgetInfo extends ItemInfo {
*/
int appWidgetId = NO_ID;
ComponentName providerName;
public ComponentName providerName;
/**
* Indicates the restore status of the widget.
@@ -38,7 +38,7 @@ import android.view.accessibility.AccessibilityManager;
import com.android.launcher3.util.Thunk;
class LauncherClings implements OnClickListener, OnKeyListener {
public class LauncherClings implements OnClickListener, OnKeyListener {
private static final String WORKSPACE_CLING_DISMISSED_KEY = "cling_gel.workspace.dismissed";
private static final String TAG_CROP_TOP_AND_SIDES = "crop_bg_top_and_sides";
+1 -1
View File
@@ -3938,7 +3938,7 @@ public class Workspace extends PagedView
});
}
private View getFirstMatch(final ItemOperator operator) {
public View getFirstMatch(final ItemOperator operator) {
final View[] value = new View[1];
mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
@Override
@@ -207,4 +207,9 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
}
return "";
}
@Override
public CharSequence getAccessibilityClassName() {
return WidgetCell.class.getName();
}
}
@@ -1,38 +1,30 @@
package com.android.launcher3;
import android.annotation.TargetApi;
import android.app.SearchManager;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Build;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiSelector;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.ui.LauncherInstrumentationTestCase;
import com.android.launcher3.util.ManagedProfileHeuristic;
import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.WidgetHostViewLoader;
import java.io.FileInputStream;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
* Tests for bind widget flow.
@@ -41,12 +33,8 @@ import java.util.concurrent.atomic.AtomicReference;
*/
@LargeTest
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class BindWidgetTest extends InstrumentationTestCase {
public class BindWidgetTest extends LauncherInstrumentationTestCase {
private static final long DEFAULT_TIMEOUT = 6000;
private UiDevice mDevice;
private Context mTargetContext;
private ContentResolver mResolver;
private AppWidgetManagerCompat mWidgetManager;
@@ -59,23 +47,9 @@ public class BindWidgetTest extends InstrumentationTestCase {
protected void setUp() throws Exception {
super.setUp();
mDevice = UiDevice.getInstance(getInstrumentation());
mTargetContext = getInstrumentation().getTargetContext();
mResolver = mTargetContext.getContentResolver();
mWidgetManager = AppWidgetManagerCompat.getInstance(mTargetContext);
// Check bind widget permission
String pkg = mTargetContext.getPackageName();
if (mTargetContext.getPackageManager().checkPermission(
pkg, android.Manifest.permission.BIND_APPWIDGET)
!= PackageManager.PERMISSION_GRANTED) {
ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation().executeShellCommand(
"appwidget grantbind --package " + pkg);
// Read the input stream fully.
FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
while (fis.read() != -1);
fis.close();
}
grantWidgetPermission();
// Clear all existing data
LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
@@ -264,61 +238,14 @@ public class BindWidgetTest extends InstrumentationTestCase {
throw new IllegalArgumentException(t);
}
// Launch the home activity
getInstrumentation().getContext().startActivity(new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
.setPackage(mTargetContext.getPackageName())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
startLauncher();
// Verify UI
UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
.className(widgetClass);
if (desc != null) {
selector = selector.description(desc);
}
assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_TIMEOUT));
}
/**
* Finds a widget provider which can fit on the home screen.
* @param hasConfigureScreen if true, a provider with a config screen is returned.
*/
private LauncherAppWidgetProviderInfo findWidgetProvider(final boolean hasConfigureScreen) {
LauncherAppWidgetProviderInfo info = getOnUiThread(new Callable<LauncherAppWidgetProviderInfo>() {
@Override
public LauncherAppWidgetProviderInfo call() throws Exception {
InvariantDeviceProfile idv =
LauncherAppState.getInstance().getInvariantDeviceProfile();
ComponentName searchComponent = ((SearchManager) mTargetContext
.getSystemService(Context.SEARCH_SERVICE)).getGlobalSearchActivity();
String searchPackage = searchComponent == null
? null : searchComponent.getPackageName();
for (AppWidgetProviderInfo info :
AppWidgetManagerCompat.getInstance(mTargetContext).getAllProviders()) {
if ((info.configure != null) ^ hasConfigureScreen) {
continue;
}
// Exclude the widgets in search package, as Launcher already binds them in
// QSB, so they can cause conflicts.
if (info.provider.getPackageName().equals(searchPackage)) {
continue;
}
LauncherAppWidgetProviderInfo widgetInfo = LauncherAppWidgetProviderInfo
.fromProviderInfo(mTargetContext, info);
if (widgetInfo.minSpanX >= idv.numColumns
|| widgetInfo.minSpanY >= idv.numRows) {
continue;
}
return widgetInfo;
}
return null;
}
});
if (info == null) {
throw new IllegalArgumentException("No valid widget provider");
}
return info;
assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_UI_TIMEOUT));
}
/**
@@ -397,24 +324,6 @@ public class BindWidgetTest extends InstrumentationTestCase {
return item;
}
/**
* Runs the callback on the UI thread and returns the result.
*/
private <T> T getOnUiThread(final Callable<T> callback) {
final AtomicReference<T> result = new AtomicReference<>(null);
try {
runTestOnUiThread(new Runnable() {
@Override
public void run() {
try {
result.set(callback.call());
} catch (Exception e) { }
}
});
} catch (Throwable t) { }
return result.get();
}
/**
* Blocks the current thread until all the jobs in the main worker thread are complete.
*/
@@ -1,88 +0,0 @@
package com.android.launcher3;
import android.content.Intent;
import android.graphics.Point;
import android.os.SystemClock;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.Direction;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import java.util.List;
/**
* Add an arbitrary widget from the widget picker very quickly to test potential race conditions.
*/
@LargeTest
public class QuickAddWidgetTest extends InstrumentationTestCase {
// Disabled because it's flaky and not particularly useful. But this class could still be useful
// as an example if we want other UI tests in the future.
private static final boolean DISABLED = true;
private UiDevice mDevice;
private String mTargetPackage;
@Override
protected void setUp() throws Exception {
super.setUp();
mDevice = UiDevice.getInstance(getInstrumentation());
// Set Launcher3 as home.
mTargetPackage = getInstrumentation().getTargetContext().getPackageName();
Intent homeIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
.setPackage(mTargetPackage)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getInstrumentation().getContext().startActivity(homeIntent);
mDevice.wait(Until.hasObject(By.pkg(mTargetPackage).depth(0)), 3000);
}
public void testAddWidgetQuickly() throws Exception {
if (DISABLED) return;
mDevice.pressMenu(); // Enter overview mode.
mDevice.wait(Until.findObject(By.text("Widgets")), 3000).click();
UiObject2 calendarWidget = getWidgetByName("Clock");
Point center = calendarWidget.getVisibleCenter();
// Touch widget just long enough to pick it up (longPressTimeout), then let go immediately.
getInstrumentation().sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, center.x, center.y, 0));
Thread.sleep(ViewConfiguration.getLongPressTimeout() + 50);
getInstrumentation().sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, center.x, center.y, 0));
assertTrue("Drag was never started", isOnHomescreen());
}
private UiObject2 getWidgetByName(String name) {
UiObject2 widgetsList = mDevice.wait(Until.findObject(By.res(mTargetPackage,
"widgets_list_view")), 3000);
do {
UiObject2 widget = getVisibleWidgetByName(name);
if (widget != null) {
return widget;
}
} while (widgetsList.scroll(Direction.DOWN, 1f));
return getVisibleWidgetByName(name);
}
private UiObject2 getVisibleWidgetByName(String name) {
List<UiObject2> visibleWidgets = mDevice.wait(Until.findObjects(By.clazz(
"android.widget.LinearLayout")), 3000);
for (UiObject2 widget : visibleWidgets) {
if (widget.hasObject(By.text(name))) {
return widget;
}
}
return null;
}
private boolean isOnHomescreen() {
return mDevice.wait(Until.hasObject(By.res(mTargetPackage, "hotseat")), 3000);
}
}
@@ -0,0 +1,64 @@
package com.android.launcher3.ui;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiObject2;
import android.test.suitebuilder.annotation.LargeTest;
import android.view.View;
import com.android.launcher3.CellLayout;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.Workspace.ItemOperator;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
import com.android.launcher3.widget.WidgetCell;
/**
* Test to add widget from widget tray
*/
@LargeTest
public class AddWidgetTest extends LauncherInstrumentationTestCase {
private LauncherAppWidgetProviderInfo widgetInfo;
@Override
protected void setUp() throws Exception {
super.setUp();
widgetInfo = findWidgetProvider(false /* hasConfigureScreen */);
}
public void testDragIcon_portrait() throws Throwable {
lockRotation(true);
performTest();
}
public void testDragIcon_landscape() throws Throwable {
lockRotation(false);
performTest();
}
private void performTest() throws Throwable {
clearHomescreen();
Launcher launcher = startLauncher();
// Open all apps and wait for load complete.
final UiObject2 widgetContainer = openWidgetsTray();
assertTrue(Wait.atMost(Condition.minChildCount(widgetContainer, 2), DEFAULT_UI_TIMEOUT));
// Drag widget to homescreen
UiObject2 widget = scrollAndFind(widgetContainer, By.clazz(WidgetCell.class)
.hasDescendant(By.text(widgetInfo.getLabel(mTargetContext.getPackageManager()))));
dragToWorkspace(widget);
assertNotNull(launcher.getWorkspace().getFirstMatch(new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View view) {
return info instanceof LauncherAppWidgetInfo &&
((LauncherAppWidgetInfo) info).providerName.equals(widgetInfo.provider);
}
}));
}
}
@@ -0,0 +1,52 @@
package com.android.launcher3.ui;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
import android.test.suitebuilder.annotation.LargeTest;
import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
/**
* Test for verifying apps is launched from all-apps
*/
@LargeTest
public class AllAppsAppLaunchTest extends LauncherInstrumentationTestCase {
private LauncherActivityInfoCompat mSettingsApp;
@Override
protected void setUp() throws Exception {
super.setUp();
mSettingsApp = LauncherAppsCompat.getInstance(mTargetContext)
.getActivityList("com.android.settings", UserHandleCompat.myUserHandle()).get(0);
}
public void testAppLauncher_portrait() throws Exception {
lockRotation(true);
performTest();
}
public void testAppLauncher_landscape() throws Exception {
lockRotation(false);
performTest();
}
private void performTest() throws Exception {
startLauncher();
// Open all apps and wait for load complete
final UiObject2 appsContainer = openAllApps();
assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
// Open settings app and verify app launched
scrollAndFind(appsContainer, By.text(mSettingsApp.getLabel().toString())).click();
assertTrue(mDevice.wait(Until.hasObject(By.pkg(
mSettingsApp.getComponentName().getPackageName()).depth(0)), DEFAULT_UI_TIMEOUT));
}
}
@@ -0,0 +1,57 @@
package com.android.launcher3.ui;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
import android.test.suitebuilder.annotation.LargeTest;
import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
/**
* Test for dragging an icon from all-apps to homescreen.
*/
@LargeTest
public class AllAppsIconToHomeTest extends LauncherInstrumentationTestCase {
private LauncherActivityInfoCompat mSettingsApp;
@Override
protected void setUp() throws Exception {
super.setUp();
mSettingsApp = LauncherAppsCompat.getInstance(mTargetContext)
.getActivityList("com.android.settings", UserHandleCompat.myUserHandle()).get(0);
}
public void testDragIcon_portrait() throws Throwable {
lockRotation(true);
performTest();
}
public void testDragIcon_landscape() throws Throwable {
lockRotation(false);
performTest();
}
private void performTest() throws Throwable {
clearHomescreen();
startLauncher();
// Open all apps and wait for load complete.
final UiObject2 appsContainer = openAllApps();
assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
// Drag icon to homescreen.
UiObject2 icon = scrollAndFind(appsContainer, By.text(mSettingsApp.getLabel().toString()));
dragToWorkspace(icon);
// Verify that the icon works on homescreen.
mDevice.findObject(By.text(mSettingsApp.getLabel().toString())).click();
assertTrue(mDevice.wait(Until.hasObject(By.pkg(
mSettingsApp.getComponentName().getPackageName()).depth(0)), DEFAULT_UI_TIMEOUT));
}
}
@@ -0,0 +1,266 @@
package com.android.launcher3.ui;
import android.app.SearchManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Point;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemClock;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.Direction;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
import android.test.InstrumentationTestCase;
import android.view.MotionEvent;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherClings;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.util.ManagedProfileHeuristic;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Locale;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicReference;
/**
* Base class for all instrumentation tests providing various utility methods.
*/
public class LauncherInstrumentationTestCase extends InstrumentationTestCase {
public static final long DEFAULT_UI_TIMEOUT = 3000;
protected UiDevice mDevice;
protected Context mTargetContext;
protected String mTargetPackage;
@Override
protected void setUp() throws Exception {
super.setUp();
mDevice = UiDevice.getInstance(getInstrumentation());
mTargetContext = getInstrumentation().getTargetContext();
mTargetPackage = mTargetContext.getPackageName();
}
protected void lockRotation(boolean naturalOrientation) throws RemoteException {
Utilities.getPrefs(mTargetContext)
.edit()
.putBoolean(Utilities.ALLOW_ROTATION_PREFERENCE_KEY, !naturalOrientation)
.commit();
if (naturalOrientation) {
mDevice.setOrientationNatural();
} else {
mDevice.setOrientationRight();
}
}
/**
* Starts the launcher activity in the target package and returns the Launcher instance.
*/
protected Launcher startLauncher() {
Intent homeIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
.setPackage(mTargetPackage)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
return (Launcher) getInstrumentation().startActivitySync(homeIntent);
}
/**
* Grants the launcher permission to bind widgets.
*/
protected void grantWidgetPermission() throws IOException {
// Check bind widget permission
if (mTargetContext.getPackageManager().checkPermission(
mTargetPackage, android.Manifest.permission.BIND_APPWIDGET)
!= PackageManager.PERMISSION_GRANTED) {
ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation().executeShellCommand(
"appwidget grantbind --package " + mTargetPackage);
// Read the input stream fully.
FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
while (fis.read() != -1);
fis.close();
}
}
/**
* Opens all apps and returns the recycler view
*/
protected UiObject2 openAllApps() {
mDevice.wait(Until.findObject(
By.desc(mTargetContext.getString(R.string.all_apps_button_label))), DEFAULT_UI_TIMEOUT).click();
return findViewById(R.id.apps_list_view);
}
/**
* Opens widget tray and returns the recycler view.
*/
protected UiObject2 openWidgetsTray() {
mDevice.pressMenu(); // Enter overview mode.
mDevice.wait(Until.findObject(
By.text(mTargetContext.getString(R.string.widget_button_text)
.toUpperCase(Locale.getDefault()))), DEFAULT_UI_TIMEOUT).click();
return findViewById(R.id.widgets_list_view);
}
/**
* Scrolls the {@param container} until it finds an object matching {@param condition}.
* @return the matching object.
*/
protected UiObject2 scrollAndFind(UiObject2 container, BySelector condition) {
do {
UiObject2 widget = container.findObject(condition);
if (widget != null) {
return widget;
}
} while (container.scroll(Direction.DOWN, 1f));
return container.findObject(condition);
}
/**
* Drags an icon to the center of homescreen.
*/
protected void dragToWorkspace(UiObject2 icon) {
Point center = icon.getVisibleCenter();
// Action Down
sendPointer(MotionEvent.ACTION_DOWN, center);
// Wait until "Remove/Delete target is visible
assertNotNull(findViewById(R.id.delete_target_text));
Point moveLocation = findViewById(R.id.drag_layer).getVisibleCenter();
// Move to center
while(!moveLocation.equals(center)) {
center.x = getNextMoveValue(moveLocation.x, center.x);
center.y = getNextMoveValue(moveLocation.y, center.y);
sendPointer(MotionEvent.ACTION_MOVE, center);
}
sendPointer(MotionEvent.ACTION_UP, center);
// Wait until remove target is gone.
mDevice.wait(Until.gone(getSelectorForId(R.id.delete_target_text)), DEFAULT_UI_TIMEOUT);
}
private int getNextMoveValue(int targetValue, int oldValue) {
if (targetValue - oldValue > 10) {
return oldValue + 10;
} else if (targetValue - oldValue < -10) {
return oldValue - 10;
} else {
return targetValue;
}
}
private void sendPointer(int action, Point point) {
MotionEvent event = MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(), action, point.x, point.y, 0);
getInstrumentation().sendPointerSync(event);
event.recycle();
}
/**
* Removes all icons from homescreen and hotseat.
*/
public void clearHomescreen() throws Throwable {
LauncherSettings.Settings.call(mTargetContext.getContentResolver(),
LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
LauncherSettings.Settings.call(mTargetContext.getContentResolver(),
LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG);
LauncherClings.markFirstRunClingDismissed(mTargetContext);
ManagedProfileHeuristic.markExistingUsersForNoFolderCreation(mTargetContext);
runTestOnUiThread(new Runnable() {
@Override
public void run() {
// Reset the loader state
LauncherAppState.getInstance().getModel().resetLoadedState(true, true);
}
});
}
/**
* Runs the callback on the UI thread and returns the result.
*/
protected <T> T getOnUiThread(final Callable<T> callback) {
final AtomicReference<T> result = new AtomicReference<>(null);
try {
runTestOnUiThread(new Runnable() {
@Override
public void run() {
try {
result.set(callback.call());
} catch (Exception e) { }
}
});
} catch (Throwable t) { }
return result.get();
}
/**
* Finds a widget provider which can fit on the home screen.
* @param hasConfigureScreen if true, a provider with a config screen is returned.
*/
protected LauncherAppWidgetProviderInfo findWidgetProvider(final boolean hasConfigureScreen) {
LauncherAppWidgetProviderInfo info = getOnUiThread(new Callable<LauncherAppWidgetProviderInfo>() {
@Override
public LauncherAppWidgetProviderInfo call() throws Exception {
InvariantDeviceProfile idv =
LauncherAppState.getInstance().getInvariantDeviceProfile();
ComponentName searchComponent = ((SearchManager) mTargetContext
.getSystemService(Context.SEARCH_SERVICE)).getGlobalSearchActivity();
String searchPackage = searchComponent == null
? null : searchComponent.getPackageName();
for (AppWidgetProviderInfo info :
AppWidgetManagerCompat.getInstance(mTargetContext).getAllProviders()) {
if ((info.configure != null) ^ hasConfigureScreen) {
continue;
}
// Exclude the widgets in search package, as Launcher already binds them in
// QSB, so they can cause conflicts.
if (info.provider.getPackageName().equals(searchPackage)) {
continue;
}
LauncherAppWidgetProviderInfo widgetInfo = LauncherAppWidgetProviderInfo
.fromProviderInfo(mTargetContext, info);
if (widgetInfo.minSpanX >= idv.numColumns
|| widgetInfo.minSpanY >= idv.numRows) {
continue;
}
return widgetInfo;
}
return null;
}
});
if (info == null) {
throw new IllegalArgumentException("No valid widget provider");
}
return info;
}
protected UiObject2 findViewById(int id) {
return mDevice.wait(Until.findObject(getSelectorForId(id)), DEFAULT_UI_TIMEOUT);
}
protected BySelector getSelectorForId(int id) {
String name = mTargetContext.getResources().getResourceEntryName(id);
return By.res(mTargetPackage, name);
}
}
@@ -1,24 +1,20 @@
package com.android.launcher3;
package com.android.launcher3.ui;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Rect;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiSelector;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.MediumTest;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
/**
* Test for auto rotate preference.
*/
@MediumTest
public class RotationPreferenceTest extends InstrumentationTestCase {
private UiDevice mDevice;
private Context mTargetContext;
private String mTargetPackage;
public class RotationPreferenceTest extends LauncherInstrumentationTestCase {
private SharedPreferences mPrefs;
private boolean mOriginalRotationValue;
@@ -48,7 +44,7 @@ public class RotationPreferenceTest extends InstrumentationTestCase {
setRotationEnabled(false);
mDevice.setOrientationRight();
goToLauncher();
startLauncher();
Rect hotseat = getHotseatBounds();
assertTrue(hotseat.width() > hotseat.height());
@@ -62,21 +58,12 @@ public class RotationPreferenceTest extends InstrumentationTestCase {
setRotationEnabled(true);
mDevice.setOrientationRight();
goToLauncher();
startLauncher();
Rect hotseat = getHotseatBounds();
assertTrue(hotseat.width() < hotseat.height());
}
private void goToLauncher() {
Intent homeIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
.setPackage(mTargetPackage)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getInstrumentation().getContext().startActivity(homeIntent);
mDevice.findObject(new UiSelector().packageName(mTargetPackage)).waitForExists(6000);
}
private void setRotationEnabled(boolean enabled) {
mPrefs.edit().putBoolean(Utilities.ALLOW_ROTATION_PREFERENCE_KEY, enabled).commit();
}
@@ -0,0 +1,54 @@
package com.android.launcher3.util;
import android.support.test.uiautomator.UiObject2;
import com.android.launcher3.MainThreadExecutor;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
public abstract class Condition {
public abstract boolean isTrue() throws Throwable;
/**
* Converts the condition to be run on UI thread.
*/
public static Condition runOnUiThread(final Condition condition) {
final MainThreadExecutor executor = new MainThreadExecutor();
return new Condition() {
@Override
public boolean isTrue() throws Throwable {
final AtomicBoolean value = new AtomicBoolean(false);
final Throwable[] exceptions = new Throwable[1];
final CountDownLatch latch = new CountDownLatch(1);
executor.execute(new Runnable() {
@Override
public void run() {
try {
value.set(condition.isTrue());
} catch (Throwable e) {
exceptions[0] = e;
}
}
});
latch.await(1, TimeUnit.SECONDS);
if (exceptions[0] != null) {
throw exceptions[0];
}
return value.get();
}
};
}
public static Condition minChildCount(final UiObject2 obj, final int childCount) {
return new Condition() {
@Override
public boolean isTrue() {
return obj.getChildCount() >= childCount;
}
};
}
}
@@ -0,0 +1,30 @@
package com.android.launcher3.util;
import android.os.SystemClock;
/**
* A utility class for waiting for a condition to be true.
*/
public class Wait {
private static final long DEFAULT_SLEEP_MS = 200;
public static boolean atMost(Condition condition, long timeout) {
return atMost(condition, timeout, DEFAULT_SLEEP_MS);
}
public static boolean atMost(Condition condition, long timeout, long sleepMillis) {
long endTime = SystemClock.uptimeMillis() + timeout;
while (SystemClock.uptimeMillis() < endTime) {
try {
if (condition.isTrue()) {
return true;
}
} catch (Throwable t) {
// Ignore
}
SystemClock.sleep(sleepMillis);
}
return false;
}
}