mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-03-03 17:36:49 +00:00
267 lines
10 KiB
Java
267 lines
10 KiB
Java
|
|
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);
|
||
|
|
}
|
||
|
|
}
|