Adding UI tests for various bind widget flows
am: 16466f1bbb
* commit '16466f1bbb935d56c01b10551ead416feb7fc943':
Adding UI tests for various bind widget flows
This commit is contained in:
@@ -363,7 +363,7 @@ public class AppWidgetResizeFrame extends FrameLayout implements View.OnKeyListe
|
||||
sTmpRect.right, sTmpRect.bottom);
|
||||
}
|
||||
|
||||
public static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) {
|
||||
public static Rect getWidgetSizeRanges(Context context, int spanX, int spanY, Rect rect) {
|
||||
if (sCellSize == null) {
|
||||
InvariantDeviceProfile inv = LauncherAppState.getInstance().getInvariantDeviceProfile();
|
||||
|
||||
@@ -376,7 +376,7 @@ public class AppWidgetResizeFrame extends FrameLayout implements View.OnKeyListe
|
||||
if (rect == null) {
|
||||
rect = new Rect();
|
||||
}
|
||||
final float density = launcher.getResources().getDisplayMetrics().density;
|
||||
final float density = context.getResources().getDisplayMetrics().density;
|
||||
|
||||
// Compute landscape size
|
||||
int landWidth = (int) ((spanX * sCellSize[0].x) / density);
|
||||
|
||||
@@ -4013,7 +4013,7 @@ public class Launcher extends Activity
|
||||
// Note: This assumes that the id remap broadcast is received before this step.
|
||||
// If that is not the case, the id remap will be ignored and user may see the
|
||||
// click to setup view.
|
||||
PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(this, appWidgetInfo, null);
|
||||
PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(this, appWidgetInfo);
|
||||
pendingInfo.spanX = item.spanX;
|
||||
pendingInfo.spanY = item.spanY;
|
||||
pendingInfo.minSpanX = item.minSpanX;
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewDebug;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
@@ -291,4 +292,10 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView implements Touc
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
|
||||
super.onInitializeAccessibilityNodeInfo(info);
|
||||
info.setClassName(getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.android.launcher3.widget;
|
||||
|
||||
import android.appwidget.AppWidgetHostView;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
|
||||
@@ -37,14 +38,14 @@ public class PendingAddWidgetInfo extends PendingAddItemInfo {
|
||||
public AppWidgetHostView boundWidget;
|
||||
public Bundle bindOptions = null;
|
||||
|
||||
public PendingAddWidgetInfo(Launcher launcher, LauncherAppWidgetProviderInfo i, Parcelable data) {
|
||||
public PendingAddWidgetInfo(Context context, LauncherAppWidgetProviderInfo i) {
|
||||
if (i.isCustomWidget) {
|
||||
itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
|
||||
} else {
|
||||
itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
|
||||
}
|
||||
this.info = i;
|
||||
user = AppWidgetManagerCompat.getInstance(launcher).getUser(i);
|
||||
user = AppWidgetManagerCompat.getInstance(context).getUser(i);
|
||||
componentName = i.provider;
|
||||
previewImage = i.previewImage;
|
||||
icon = i.icon;
|
||||
|
||||
@@ -151,15 +151,15 @@ public class WidgetHostViewLoader implements DragController.DragListener {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
|
||||
public static Bundle getDefaultOptionsForWidget(Context context, PendingAddWidgetInfo info) {
|
||||
Bundle options = null;
|
||||
Rect rect = new Rect();
|
||||
if (Utilities.ATLEAST_JB_MR1) {
|
||||
AppWidgetResizeFrame.getWidgetSizeRanges(launcher, info.spanX, info.spanY, rect);
|
||||
Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(launcher,
|
||||
Rect rect = new Rect();
|
||||
AppWidgetResizeFrame.getWidgetSizeRanges(context, info.spanX, info.spanY, rect);
|
||||
Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(context,
|
||||
info.componentName, null);
|
||||
|
||||
float density = launcher.getResources().getDisplayMetrics().density;
|
||||
float density = context.getResources().getDisplayMetrics().density;
|
||||
int xPaddingDips = (int) ((padding.left + padding.right) / density);
|
||||
int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> {
|
||||
WidgetCell widget = (WidgetCell) row.getChildAt(i);
|
||||
if (infoList.get(i) instanceof LauncherAppWidgetProviderInfo) {
|
||||
LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) infoList.get(i);
|
||||
PendingAddWidgetInfo pawi = new PendingAddWidgetInfo(mLauncher, info, null);
|
||||
PendingAddWidgetInfo pawi = new PendingAddWidgetInfo(mLauncher, info);
|
||||
widget.setTag(pawi);
|
||||
widget.applyFromAppWidgetProviderInfo(info, mWidgetPreviewLoader);
|
||||
} else if (infoList.get(i) instanceof ResolveInfo) {
|
||||
|
||||
@@ -0,0 +1,428 @@
|
||||
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 com.android.launcher3.compat.AppWidgetManagerCompat;
|
||||
import com.android.launcher3.compat.PackageInstallerCompat;
|
||||
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.
|
||||
*
|
||||
* Note running these tests will clear the workspace on the device.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public class BindWidgetTest extends InstrumentationTestCase {
|
||||
|
||||
private static final long DEFAULT_TIMEOUT = 6000;
|
||||
|
||||
private UiDevice mDevice;
|
||||
private Context mTargetContext;
|
||||
private ContentResolver mResolver;
|
||||
private AppWidgetManagerCompat mWidgetManager;
|
||||
|
||||
// Objects created during test, which should be cleaned up in the end.
|
||||
private Cursor mCursor;
|
||||
// App install session id.
|
||||
private int mSessionId = -1;
|
||||
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
|
||||
// Clear all existing data
|
||||
LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
|
||||
LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
if (mCursor != null) {
|
||||
mCursor.close();
|
||||
}
|
||||
|
||||
if (mSessionId > -1) {
|
||||
mTargetContext.getPackageManager().getPackageInstaller().abandonSession(mSessionId);
|
||||
}
|
||||
}
|
||||
|
||||
public void testBindNormalWidget_withConfig() {
|
||||
LauncherAppWidgetProviderInfo info = findWidgetProvider(true);
|
||||
LauncherAppWidgetInfo item = createWidgetInfo(info, true);
|
||||
|
||||
setupAndVerifyContents(item, LauncherAppWidgetHostView.class, info.label);
|
||||
}
|
||||
|
||||
public void testBindNormalWidget_withoutConfig() {
|
||||
LauncherAppWidgetProviderInfo info = findWidgetProvider(false);
|
||||
LauncherAppWidgetInfo item = createWidgetInfo(info, true);
|
||||
|
||||
setupAndVerifyContents(item, LauncherAppWidgetHostView.class, info.label);
|
||||
}
|
||||
|
||||
public void testUnboundWidget_removed() throws Exception {
|
||||
LauncherAppWidgetProviderInfo info = findWidgetProvider(false);
|
||||
LauncherAppWidgetInfo item = createWidgetInfo(info, false);
|
||||
item.appWidgetId = 33;
|
||||
|
||||
// Since there is no widget to verify, just wait until the workspace is ready.
|
||||
setupAndVerifyContents(item, Workspace.class, null);
|
||||
|
||||
waitUntilLoaderIdle();
|
||||
// Item deleted from db
|
||||
mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
|
||||
null, null, null, null, null);
|
||||
assertEquals(0, mCursor.getCount());
|
||||
|
||||
// The view does not exist
|
||||
assertFalse(mDevice.findObject(new UiSelector().description(info.label)).exists());
|
||||
}
|
||||
|
||||
public void testPendingWidget_autoRestored() {
|
||||
// A non-restored widget with no config screen gets restored automatically.
|
||||
LauncherAppWidgetProviderInfo info = findWidgetProvider(false);
|
||||
|
||||
// Do not bind the widget
|
||||
LauncherAppWidgetInfo item = createWidgetInfo(info, false);
|
||||
item.restoreStatus = LauncherAppWidgetInfo.FLAG_ID_NOT_VALID;
|
||||
|
||||
setupAndVerifyContents(item, LauncherAppWidgetHostView.class, info.label);
|
||||
}
|
||||
|
||||
public void testPendingWidget_withConfigScreen() throws Exception {
|
||||
// A non-restored widget with config screen get bound and shows a 'Click to setup' UI.
|
||||
LauncherAppWidgetProviderInfo info = findWidgetProvider(true);
|
||||
|
||||
// Do not bind the widget
|
||||
LauncherAppWidgetInfo item = createWidgetInfo(info, false);
|
||||
item.restoreStatus = LauncherAppWidgetInfo.FLAG_ID_NOT_VALID;
|
||||
|
||||
setupAndVerifyContents(item, PendingAppWidgetHostView.class, null);
|
||||
waitUntilLoaderIdle();
|
||||
// Item deleted from db
|
||||
mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
|
||||
null, null, null, null, null);
|
||||
mCursor.moveToNext();
|
||||
|
||||
// Widget has a valid Id now.
|
||||
assertEquals(0, mCursor.getInt(mCursor.getColumnIndex(LauncherSettings.Favorites.RESTORED))
|
||||
& LauncherAppWidgetInfo.FLAG_ID_NOT_VALID);
|
||||
assertNotNull(mWidgetManager.getAppWidgetInfo(mCursor.getInt(mCursor.getColumnIndex(
|
||||
LauncherSettings.Favorites.APPWIDGET_ID))));
|
||||
}
|
||||
|
||||
public void testPendingWidget_notRestored_removed() throws Exception {
|
||||
LauncherAppWidgetInfo item = getInvalidWidgetInfo();
|
||||
item.restoreStatus = LauncherAppWidgetInfo.FLAG_ID_NOT_VALID
|
||||
| LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
|
||||
|
||||
setupAndVerifyContents(item, Workspace.class, null);
|
||||
// The view does not exist
|
||||
assertFalse(mDevice.findObject(
|
||||
new UiSelector().className(PendingAppWidgetHostView.class)).exists());
|
||||
waitUntilLoaderIdle();
|
||||
// Item deleted from db
|
||||
mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
|
||||
null, null, null, null, null);
|
||||
assertEquals(0, mCursor.getCount());
|
||||
}
|
||||
|
||||
public void testPendingWidget_notRestored_brokenInstall() throws Exception {
|
||||
// A widget which is was being installed once, even if its not being
|
||||
// installed at the moment is not removed.
|
||||
LauncherAppWidgetInfo item = getInvalidWidgetInfo();
|
||||
item.restoreStatus = LauncherAppWidgetInfo.FLAG_ID_NOT_VALID
|
||||
| LauncherAppWidgetInfo.FLAG_RESTORE_STARTED
|
||||
| LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
|
||||
|
||||
setupAndVerifyContents(item, PendingAppWidgetHostView.class, null);
|
||||
// Verify item still exists in db
|
||||
waitUntilLoaderIdle();
|
||||
mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
|
||||
null, null, null, null, null);
|
||||
assertEquals(1, mCursor.getCount());
|
||||
|
||||
// Widget still has an invalid id.
|
||||
mCursor.moveToNext();
|
||||
assertEquals(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID,
|
||||
mCursor.getInt(mCursor.getColumnIndex(LauncherSettings.Favorites.RESTORED))
|
||||
& LauncherAppWidgetInfo.FLAG_ID_NOT_VALID);
|
||||
}
|
||||
|
||||
public void testPendingWidget_notRestored_activeInstall() throws Exception {
|
||||
// A widget which is being installed is not removed
|
||||
LauncherAppWidgetInfo item = getInvalidWidgetInfo();
|
||||
item.restoreStatus = LauncherAppWidgetInfo.FLAG_ID_NOT_VALID
|
||||
| LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
|
||||
|
||||
// Create an active installer session
|
||||
SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
|
||||
params.setAppPackageName(item.providerName.getPackageName());
|
||||
PackageInstaller installer = mTargetContext.getPackageManager().getPackageInstaller();
|
||||
mSessionId = installer.createSession(params);
|
||||
|
||||
setupAndVerifyContents(item, PendingAppWidgetHostView.class, null);
|
||||
// Verify item still exists in db
|
||||
waitUntilLoaderIdle();
|
||||
mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
|
||||
null, null, null, null, null);
|
||||
assertEquals(1, mCursor.getCount());
|
||||
|
||||
// Widget still has an invalid id.
|
||||
mCursor.moveToNext();
|
||||
assertEquals(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID,
|
||||
mCursor.getInt(mCursor.getColumnIndex(LauncherSettings.Favorites.RESTORED))
|
||||
& LauncherAppWidgetInfo.FLAG_ID_NOT_VALID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds {@param item} on the homescreen on the 0th screen at 0,0, and verifies that the
|
||||
* widget class is displayed on the homescreen.
|
||||
* @param widgetClass the View class which is displayed on the homescreen
|
||||
* @param desc the content description of the view or null.
|
||||
*/
|
||||
private void setupAndVerifyContents(
|
||||
LauncherAppWidgetInfo item, Class<?> widgetClass, String desc) {
|
||||
// Add new screen
|
||||
long screenId = LauncherSettings.Settings.call(
|
||||
mResolver, LauncherSettings.Settings.METHOD_NEW_SCREEN_ID)
|
||||
.getLong(LauncherSettings.Settings.EXTRA_VALUE);
|
||||
ContentValues v = new ContentValues();
|
||||
v.put(LauncherSettings.WorkspaceScreens._ID, screenId);
|
||||
v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, 0);
|
||||
mResolver.insert(LauncherSettings.WorkspaceScreens.CONTENT_URI, v);
|
||||
|
||||
// Insert the item
|
||||
v = new ContentValues();
|
||||
item.id = LauncherSettings.Settings.call(
|
||||
mResolver, LauncherSettings.Settings.METHOD_NEW_ITEM_ID)
|
||||
.getLong(LauncherSettings.Settings.EXTRA_VALUE);
|
||||
item.screenId = screenId;
|
||||
item.onAddToDatabase(mTargetContext, v);
|
||||
v.put(LauncherSettings.Favorites._ID, item.id);
|
||||
mResolver.insert(LauncherSettings.Favorites.CONTENT_URI, v);
|
||||
|
||||
// Reset loader
|
||||
try {
|
||||
runTestOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ManagedProfileHeuristic.markExistingUsersForNoFolderCreation(mTargetContext);
|
||||
LauncherAppState.getInstance().getModel().resetLoadedState(true, true);
|
||||
}
|
||||
});
|
||||
} catch (Throwable t) {
|
||||
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));
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a LauncherAppWidgetInfo corresponding to {@param info}
|
||||
* @param bindWidget if true the info is bound and a valid widgetId is assigned to
|
||||
* the LauncherAppWidgetInfo
|
||||
*/
|
||||
private LauncherAppWidgetInfo createWidgetInfo(
|
||||
LauncherAppWidgetProviderInfo info, boolean bindWidget) {
|
||||
LauncherAppWidgetInfo item = new LauncherAppWidgetInfo(
|
||||
LauncherAppWidgetInfo.NO_ID, info.provider);
|
||||
item.spanX = info.minSpanX;
|
||||
item.spanY = info.minSpanY;
|
||||
item.minSpanX = info.minSpanX;
|
||||
item.minSpanY = info.minSpanY;
|
||||
item.user = mWidgetManager.getUser(info);
|
||||
item.cellX = 0;
|
||||
item.cellY = 0;
|
||||
item.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
|
||||
|
||||
if (bindWidget) {
|
||||
PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(mTargetContext, info);
|
||||
pendingInfo.spanX = item.spanX;
|
||||
pendingInfo.spanY = item.spanY;
|
||||
pendingInfo.minSpanX = item.minSpanX;
|
||||
pendingInfo.minSpanY = item.minSpanY;
|
||||
Bundle options = WidgetHostViewLoader.getDefaultOptionsForWidget(mTargetContext, pendingInfo);
|
||||
|
||||
AppWidgetHost host = new AppWidgetHost(mTargetContext, Launcher.APPWIDGET_HOST_ID);
|
||||
int widgetId = host.allocateAppWidgetId();
|
||||
if (!mWidgetManager.bindAppWidgetIdIfAllowed(widgetId, info, options)) {
|
||||
host.deleteAppWidgetId(widgetId);
|
||||
throw new IllegalArgumentException("Unable to bind widget id");
|
||||
}
|
||||
item.appWidgetId = widgetId;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a LauncherAppWidgetInfo with package name which is not present on the device
|
||||
*/
|
||||
private LauncherAppWidgetInfo getInvalidWidgetInfo() {
|
||||
String invalidPackage = "com.invalidpackage";
|
||||
int count = 0;
|
||||
String pkg = invalidPackage;
|
||||
|
||||
Set<String> activePackage = getOnUiThread(new Callable<Set<String>>() {
|
||||
@Override
|
||||
public Set<String> call() throws Exception {
|
||||
return PackageInstallerCompat.getInstance(mTargetContext)
|
||||
.updateAndGetActiveSessionCache().keySet();
|
||||
}
|
||||
});
|
||||
while(true) {
|
||||
try {
|
||||
mTargetContext.getPackageManager().getPackageInfo(
|
||||
pkg, PackageManager.GET_UNINSTALLED_PACKAGES);
|
||||
} catch (Exception e) {
|
||||
if (!activePackage.contains(pkg)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
pkg = invalidPackage + count;
|
||||
count ++;
|
||||
}
|
||||
LauncherAppWidgetInfo item = new LauncherAppWidgetInfo(10,
|
||||
new ComponentName(pkg, "com.test.widgetprovider"));
|
||||
item.spanX = 2;
|
||||
item.spanY = 2;
|
||||
item.minSpanX = 2;
|
||||
item.minSpanY = 2;
|
||||
item.cellX = 0;
|
||||
item.cellY = 0;
|
||||
item.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
|
||||
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.
|
||||
*/
|
||||
private void waitUntilLoaderIdle() throws InterruptedException {
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
LauncherModel.sWorker.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user