blob: 5e72a787407aa6c83c5e1d43ddabf1ac60a5cf9c [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.appwidget.cts;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.same;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.appwidget.cts.provider.AppWidgetProviderCallbacks;
import android.appwidget.cts.provider.FirstAppWidgetProvider;
import android.appwidget.cts.provider.SecondAppWidgetProvider;
import android.appwidget.cts.service.MyAppWidgetService;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.cts.appwidget.R;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.test.InstrumentationTestCase;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.widget.RemoteViews;
import android.widget.RemoteViewsService.RemoteViewsFactory;
import libcore.io.IoUtils;
import libcore.io.Streams;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.mockito.InOrder;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class AppWidgetTest extends InstrumentationTestCase {
private static final long OPERATION_TIMEOUT = 20 * 1000; // 20 sec
private static final String FIRST_APP_WIDGET_CONFIGURE_ACTIVITY =
"android.appwidget.cts.provider.FirstAppWidgetConfigureActivity";
private static final String SECOND_APP_WIDGET_CONFIGURE_ACTIVITY =
"android.appwidget.cts.provider.SecondAppWidgetConfigureActivity";
private final Object mLock = new Object();
@Override
public void setUp() throws Exception {
// Workaround for dexmaker bug: https://code.google.com/p/dexmaker/issues/detail?id=2
// Dexmaker is used by mockito.
System.setProperty("dexmaker.dexcache", getInstrumentation()
.getTargetContext().getCacheDir().getPath());
}
private static final String GRANT_BIND_APP_WIDGET_PERMISSION_COMMAND =
"appwidget grantbind --package android.cts.appwidget --user 0";
private static final String REVOKE_BIND_APP_WIDGET_PERMISSION_COMMAND =
"appwidget revokebind --package android.cts.appwidget --user 0";
public void testGetAppInstalledProvidersForCurrentUserLegacy() throws Exception {
// By default we should get only providers for the current user.
List<AppWidgetProviderInfo> providers = getAppWidgetManager().getInstalledProviders();
// Make sure we have our two providers in the list.
assertExpectedInstalledProviders(providers);
}
public void testGetAppInstalledProvidersForCurrentUserNewCurrentProfile() throws Exception {
// We ask only for providers for the current user.
List<AppWidgetProviderInfo> providers = getAppWidgetManager()
.getInstalledProvidersForProfile(Process.myUserHandle());
// Make sure we have our two providers in the list.
assertExpectedInstalledProviders(providers);
}
public void testGetAppInstalledProvidersForCurrentUserNewAllProfiles() throws Exception {
// We ask only for providers for all current user's profiles
UserManager userManager = (UserManager) getInstrumentation()
.getTargetContext().getSystemService(Context.USER_SERVICE);
List<AppWidgetProviderInfo> allProviders = new ArrayList<>();
List<UserHandle> profiles = userManager.getUserProfiles();
final int profileCount = profiles.size();
for (int i = 0; i < profileCount; i++) {
UserHandle profile = profiles.get(i);
List<AppWidgetProviderInfo> providers = getAppWidgetManager()
.getInstalledProvidersForProfile(profile);
allProviders.addAll(providers);
}
// Make sure we have our two providers in the list.
assertExpectedInstalledProviders(allProviders);
}
public void testBindAppWidget() throws Exception {
// Create a host and start listening.
AppWidgetHost host = new AppWidgetHost(getInstrumentation().getTargetContext(), 0);
host.deleteHost();
host.startListening();
// Allocate an app widget id to bind.
final int appWidgetId = host.allocateAppWidgetId();
// Grab a provider we defined to be bound.
AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo();
// Bind the widget.
boolean widgetBound = getAppWidgetManager().bindAppWidgetIdIfAllowed(appWidgetId,
provider.getProfile(), provider.provider, null);
assertFalse(widgetBound);
// Well, app do not have this permission unless explicitly granted
// by the user. Now we will pretend for the user and grant it.
grantBindAppWidgetPermission();
try {
// Bind the widget as we have a permission for that.
widgetBound = getAppWidgetManager().bindAppWidgetIdIfAllowed(
appWidgetId, provider.getProfile(), provider.provider, null);
assertTrue(widgetBound);
// Deallocate the app widget id.
host.deleteAppWidgetId(appWidgetId);
} finally {
// Clean up.
host.deleteAppWidgetId(appWidgetId);
host.deleteHost();
revokeBindAppWidgetPermission();
}
}
public void testAppWidgetProviderCallbacks() throws Exception {
AtomicInteger invocationCounter = new AtomicInteger();
// Set a mock to intercept provider callbacks.
AppWidgetProviderCallbacks callbacks = createAppWidgetProviderCallbacks(invocationCounter);
FirstAppWidgetProvider.setCallbacks(callbacks);
int firstAppWidgetId = 0;
int secondAppWidgetId = 0;
final Bundle firstOptions;
final Bundle secondOptions;
// Create a host and start listening.
AppWidgetHost host = spy(new AppWidgetHost(getInstrumentation().getTargetContext(), 0));
host.deleteHost();
host.startListening();
// We want to bind a widget.
grantBindAppWidgetPermission();
try {
// Allocate the first widget id to bind.
firstAppWidgetId = host.allocateAppWidgetId();
// Grab a provider we defined to be bound.
AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo();
// Bind the first widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(firstAppWidgetId,
provider.getProfile(), provider.provider, null);
// Wait for onEnabled and onUpdate
waitForCallCount(invocationCounter, 2);
// Update the first widget options.
firstOptions = new Bundle();
firstOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, 1);
firstOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, 2);
firstOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, 3);
firstOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, 4);
getAppWidgetManager().updateAppWidgetOptions(firstAppWidgetId, firstOptions);
// Wait for onAppWidgetOptionsChanged
waitForCallCount(invocationCounter, 3);
// Allocate the second app widget id to bind.
secondAppWidgetId = host.allocateAppWidgetId();
// Bind the second widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(secondAppWidgetId,
provider.getProfile(), provider.provider, null);
// Wait for onUpdate
waitForCallCount(invocationCounter, 4);
// Update the second widget options.
secondOptions = new Bundle();
secondOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, 5);
secondOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, 6);
secondOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, 7);
secondOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, 8);
getAppWidgetManager().updateAppWidgetOptions(secondAppWidgetId, secondOptions);
// Wait for onAppWidgetOptionsChanged
waitForCallCount(invocationCounter, 5);
// Delete the first widget.
host.deleteAppWidgetId(firstAppWidgetId);
// Wait for onDeleted
waitForCallCount(invocationCounter, 6);
// Delete the second widget.
host.deleteAppWidgetId(secondAppWidgetId);
// Wait for onDeleted and onDisabled
waitForCallCount(invocationCounter, 8);
// Make sure the provider callbacks are correct.
InOrder inOrder = inOrder(callbacks);
inOrder.verify(callbacks).onEnabled(any(Context.class));
inOrder.verify(callbacks).onUpdate(any(Context.class),
any(AppWidgetManager.class), eq(new int[] {firstAppWidgetId}));
inOrder.verify(callbacks).onAppWidgetOptionsChanged(any(Context.class),
any(AppWidgetManager.class), same(firstAppWidgetId), argThat(
new OptionsMatcher(firstOptions)));
inOrder.verify(callbacks).onUpdate(any(Context.class),
any(AppWidgetManager.class), eq(new int[] {secondAppWidgetId}));
inOrder.verify(callbacks).onAppWidgetOptionsChanged(any(Context.class),
any(AppWidgetManager.class), same(secondAppWidgetId), argThat(
new OptionsMatcher(secondOptions)));
inOrder.verify(callbacks).onDeleted(any(Context.class),
argThat(new WidgetIdsMatcher(new int[]{firstAppWidgetId})));
inOrder.verify(callbacks).onDeleted(any(Context.class),
argThat(new WidgetIdsMatcher(new int[]{secondAppWidgetId})));
inOrder.verify(callbacks).onDisabled(any(Context.class));
} finally {
// Clean up.
host.deleteAppWidgetId(firstAppWidgetId);
host.deleteAppWidgetId(secondAppWidgetId);
host.deleteHost();
FirstAppWidgetProvider.setCallbacks(null);
revokeBindAppWidgetPermission();
}
}
public void testTwoAppWidgetProviderCallbacks() throws Exception {
AtomicInteger invocationCounter = new AtomicInteger();
// Set a mock to intercept first provider callbacks.
AppWidgetProviderCallbacks firstCallbacks = createAppWidgetProviderCallbacks(
invocationCounter);
FirstAppWidgetProvider.setCallbacks(firstCallbacks);
// Set a mock to intercept second provider callbacks.
AppWidgetProviderCallbacks secondCallbacks = createAppWidgetProviderCallbacks(
invocationCounter);
SecondAppWidgetProvider.setCallbacks(secondCallbacks);
int firstAppWidgetId = 0;
int secondAppWidgetId = 0;
// Create a host and start listening.
AppWidgetHost host = spy(new AppWidgetHost(
getInstrumentation().getTargetContext(), 0));
host.deleteHost();
host.startListening();
// We want to bind widgets.
grantBindAppWidgetPermission();
try {
// Allocate the first widget id to bind.
firstAppWidgetId = host.allocateAppWidgetId();
// Allocate the second widget id to bind.
secondAppWidgetId = host.allocateAppWidgetId();
// Grab the first provider we defined to be bound.
AppWidgetProviderInfo firstProvider = getFirstAppWidgetProviderInfo();
// Bind the first widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(firstAppWidgetId,
firstProvider.getProfile(), firstProvider.provider, null);
// Wait for onEnabled and onUpdate
waitForCallCount(invocationCounter, 2);
// Grab the second provider we defined to be bound.
AppWidgetProviderInfo secondProvider = getSecondAppWidgetProviderInfo();
// Bind the second widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(secondAppWidgetId,
secondProvider.getProfile(), secondProvider.provider, null);
// Wait for onEnabled and onUpdate
waitForCallCount(invocationCounter, 4);
// Delete the first widget.
host.deleteAppWidgetId(firstAppWidgetId);
// Wait for onDeleted and onDisabled
waitForCallCount(invocationCounter, 6);
// Delete the second widget.
host.deleteAppWidgetId(secondAppWidgetId);
// Wait for onDeleted and onDisabled
waitForCallCount(invocationCounter, 8);
// Make sure the first provider callbacks are correct.
InOrder firstInOrder = inOrder(firstCallbacks);
firstInOrder.verify(firstCallbacks).onEnabled(any(Context.class));
firstInOrder.verify(firstCallbacks).onUpdate(any(Context.class),
any(AppWidgetManager.class), eq(new int[]{firstAppWidgetId}));
firstInOrder.verify(firstCallbacks).onDeleted(any(Context.class),
argThat(new WidgetIdsMatcher(new int[]{firstAppWidgetId})));
firstInOrder.verify(firstCallbacks).onDisabled(any(Context.class));
// Make sure the second provider callbacks are correct.
InOrder secondInOrder = inOrder(secondCallbacks);
secondInOrder.verify(secondCallbacks).onEnabled(any(Context.class));
secondInOrder.verify(secondCallbacks).onUpdate(any(Context.class),
any(AppWidgetManager.class), eq(new int[]{secondAppWidgetId}));
secondInOrder.verify(secondCallbacks).onDeleted(any(Context.class),
argThat(new WidgetIdsMatcher(new int[] {secondAppWidgetId})));
secondInOrder.verify(secondCallbacks).onDisabled(any(Context.class));
} finally {
// Clean up.
host.deleteAppWidgetId(firstAppWidgetId);
host.deleteAppWidgetId(secondAppWidgetId);
host.deleteHost();
FirstAppWidgetProvider.setCallbacks(null);
SecondAppWidgetProvider.setCallbacks(null);
revokeBindAppWidgetPermission();
}
}
public void testGetAppWidgetIds() throws Exception {
// We want to bind widgets.
grantBindAppWidgetPermission();
// Create a host and start listening.
AppWidgetHost host = new AppWidgetHost(
getInstrumentation().getTargetContext(), 0);
host.deleteHost();
host.startListening();
int firstAppWidgetId = 0;
int secondAppWidgetId = 0;
try {
// Grab the provider we defined to be bound.
AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo();
// Initially we have no widgets.
int[] widgetsIds = getAppWidgetManager().getAppWidgetIds(provider.provider);
assertTrue(widgetsIds.length == 0);
// Allocate the first widget id to bind.
firstAppWidgetId = host.allocateAppWidgetId();
// Bind the first widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(firstAppWidgetId,
provider.getProfile(), provider.provider, null);
// Allocate the second widget id to bind.
secondAppWidgetId = host.allocateAppWidgetId();
// Bind the second widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(secondAppWidgetId,
provider.getProfile(), provider.provider, null);
// Now we have two widgets,
widgetsIds = getAppWidgetManager().getAppWidgetIds(provider.provider);
assertTrue(Arrays.equals(widgetsIds, new int[]{firstAppWidgetId, secondAppWidgetId}));
} finally {
// Clean up.
host.deleteAppWidgetId(firstAppWidgetId);
host.deleteAppWidgetId(secondAppWidgetId);
host.deleteHost();
revokeBindAppWidgetPermission();
}
}
public void testGetAppWidgetInfo() throws Exception {
// We want to bind widgets.
grantBindAppWidgetPermission();
// Create a host and start listening.
AppWidgetHost host = new AppWidgetHost(
getInstrumentation().getTargetContext(), 0);
host.deleteHost();
host.startListening();
int appWidgetId = 0;
try {
// Allocate an widget id to bind.
appWidgetId = host.allocateAppWidgetId();
// The widget is not bound, so no info.
AppWidgetProviderInfo foundProvider = getAppWidgetManager()
.getAppWidgetInfo(appWidgetId);
assertNull(foundProvider);
// Grab the provider we defined to be bound.
AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo();
// Bind the app widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(appWidgetId,
provider.getProfile(), provider.provider, null);
// The widget is bound, so the provider info should be there.
foundProvider = getAppWidgetManager().getAppWidgetInfo(appWidgetId);
assertEquals(provider.provider, foundProvider.provider);
assertEquals(provider.getProfile(), foundProvider.getProfile());
Context context = getInstrumentation().getTargetContext();
// Let us make sure the provider info is sane.
String label = foundProvider.loadLabel(context.getPackageManager());
assertTrue(!TextUtils.isEmpty(label));
Drawable icon = foundProvider.loadIcon(context, DisplayMetrics.DENSITY_DEFAULT);
assertNotNull(icon);
Drawable previewImage = foundProvider.loadPreviewImage(context, 0);
assertNotNull(previewImage);
} finally {
// Clean up.
host.deleteAppWidgetId(appWidgetId);
host.deleteHost();
revokeBindAppWidgetPermission();
}
}
public void testGetAppWidgetOptions() throws Exception {
// We want to bind widgets.
grantBindAppWidgetPermission();
// Create a host and start listening.
AppWidgetHost host = new AppWidgetHost(
getInstrumentation().getTargetContext(), 0);
host.deleteHost();
host.startListening();
int appWidgetId = 0;
try {
// Grab the provider we defined to be bound.
AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo();
// Allocate an widget id to bind.
appWidgetId = host.allocateAppWidgetId();
// Initially we have no options.
Bundle foundOptions = getAppWidgetManager().getAppWidgetOptions(appWidgetId);
assertTrue(foundOptions.isEmpty());
// We want to set the options when binding.
Bundle setOptions = new Bundle();
setOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, 1);
setOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, 2);
setOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, 3);
setOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, 4);
// Bind the app widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(appWidgetId,
provider.getProfile(), provider.provider, setOptions);
// Make sure we get the options used when binding.
foundOptions = getAppWidgetManager().getAppWidgetOptions(appWidgetId);
assertTrue(equalOptions(setOptions, foundOptions));
} finally {
// Clean up.
host.deleteAppWidgetId(appWidgetId);
host.deleteHost();
revokeBindAppWidgetPermission();
}
}
public void testDeleteHost() throws Exception {
// We want to bind widgets.
grantBindAppWidgetPermission();
// Create a host and start listening.
AppWidgetHost host = new AppWidgetHost(
getInstrumentation().getTargetContext(), 0);
host.deleteHost();
host.startListening();
int appWidgetId = 0;
try {
// Allocate an widget id to bind.
appWidgetId = host.allocateAppWidgetId();
// Grab the provider we defined to be bound.
AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo();
// Bind the app widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(appWidgetId,
provider.getProfile(), provider.provider, null);
// The widget should be there.
int[] widgetIds = getAppWidgetManager().getAppWidgetIds(provider.provider);
assertTrue(Arrays.equals(widgetIds, new int[]{appWidgetId}));
// Delete the host.
host.deleteHost();
// The host is gone and with it the widgets.
widgetIds = getAppWidgetManager().getAppWidgetIds(provider.provider);
assertTrue(widgetIds.length == 0);
} finally {
// Clean up.
host.deleteAppWidgetId(appWidgetId);
host.deleteHost();
revokeBindAppWidgetPermission();
}
}
public void testDeleteHosts() throws Exception {
// We want to bind widgets.
grantBindAppWidgetPermission();
// Create the first host and start listening.
AppWidgetHost firstHost = new AppWidgetHost(
getInstrumentation().getTargetContext(), 0);
firstHost.deleteHost();
firstHost.startListening();
// Create the second host and start listening.
AppWidgetHost secondHost = new AppWidgetHost(
getInstrumentation().getTargetContext(), 1);
secondHost.deleteHost();
secondHost.startListening();
int firstAppWidgetId = 0;
int secondAppWidgetId = 0;
try {
// Grab the provider we defined to be bound.
AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo();
// Allocate the first widget id to bind.
firstAppWidgetId = firstHost.allocateAppWidgetId();
// Bind the first app widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(firstAppWidgetId,
provider.getProfile(), provider.provider, null);
// Allocate the second widget id to bind.
secondAppWidgetId = secondHost.allocateAppWidgetId();
// Bind the second app widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(secondAppWidgetId,
provider.getProfile(), provider.provider, null);
// The widgets should be there.
int[] widgetIds = getAppWidgetManager().getAppWidgetIds(provider.provider);
assertTrue(Arrays.equals(widgetIds, new int[]{firstAppWidgetId, secondAppWidgetId}));
// Delete all hosts.
AppWidgetHost.deleteAllHosts();
// The hosts are gone and with it the widgets.
widgetIds = getAppWidgetManager().getAppWidgetIds(provider.provider);
assertTrue(widgetIds.length == 0);
} finally {
// Clean up.
firstHost.deleteAppWidgetId(firstAppWidgetId);
secondHost.deleteAppWidgetId(secondAppWidgetId);
AppWidgetHost.deleteAllHosts();
revokeBindAppWidgetPermission();
}
}
public void testOnProvidersChanged() throws Exception {
// We want to bind widgets.
grantBindAppWidgetPermission();
final AtomicInteger onProvidersChangedCallCounter = new AtomicInteger();
// Create a host and start listening.
AppWidgetHost host = new AppWidgetHost(
getInstrumentation().getTargetContext(), 0) {
@Override
public void onProvidersChanged() {
synchronized (mLock) {
onProvidersChangedCallCounter.incrementAndGet();
mLock.notifyAll();
}
}
};
host.deleteHost();
host.startListening();
int appWidgetId = 0;
try {
// Grab the provider we defined to be bound.
AppWidgetProviderInfo firstLookupProvider = getFirstAppWidgetProviderInfo();
// Allocate a widget id to bind.
appWidgetId = host.allocateAppWidgetId();
// Bind the first app widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(appWidgetId,
firstLookupProvider.getProfile(), firstLookupProvider.provider, null);
// Disable the provider we just bound to.
PackageManager packageManager = getInstrumentation().getTargetContext()
.getApplicationContext().getPackageManager();
packageManager.setComponentEnabledSetting(firstLookupProvider.provider,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
// Wait for the package change to propagate.
waitForCallCount(onProvidersChangedCallCounter, 1);
// The provider should not be present anymore.
AppWidgetProviderInfo secondLookupProvider = getFirstAppWidgetProviderInfo();
assertNull(secondLookupProvider);
// Enable the provider we disabled.
packageManager.setComponentEnabledSetting(firstLookupProvider.provider,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
// Wait for the package change to propagate.
waitForCallCount(onProvidersChangedCallCounter, 2);
} finally {
// Clean up.
host.deleteAppWidgetId(appWidgetId);
host.deleteHost();
revokeBindAppWidgetPermission();
}
}
public void testUpdateAppWidgetViaComponentName() throws Exception {
// We want to bind widgets.
grantBindAppWidgetPermission();
final AtomicInteger updateAppWidgetCallCount = new AtomicInteger();
// Create a host and start listening.
AppWidgetHost host = new AppWidgetHost(
getInstrumentation().getTargetContext(), 0) {
@Override
protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
AppWidgetProviderInfo appWidget) {
return new MyAppWidgetHostView(context);
}
};
host.deleteHost();
host.startListening();
int firstAppWidgetId = 0;
int secondAppWidgetId = 0;
try {
// Grab the provider to be bound.
AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo();
// Allocate the first widget id to bind.
firstAppWidgetId = host.allocateAppWidgetId();
// Bind the first app widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(firstAppWidgetId,
provider.getProfile(), provider.provider, null);
// Create the first host view.
MyAppWidgetHostView firstHostView = (MyAppWidgetHostView) host.createView(
getInstrumentation().getContext(), firstAppWidgetId, provider);
MyAppWidgetHostView.OnUpdateAppWidgetListener firstAppHostViewListener =
mock(MyAppWidgetHostView.OnUpdateAppWidgetListener.class);
firstHostView.setOnUpdateAppWidgetListener(firstAppHostViewListener);
// Allocate the second widget id to bind.
secondAppWidgetId = host.allocateAppWidgetId();
// Bind the second app widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(secondAppWidgetId,
provider.getProfile(), provider.provider, null);
// Create the second host view.
MyAppWidgetHostView secondHostView = (MyAppWidgetHostView) host.createView(
getInstrumentation().getContext(), secondAppWidgetId, provider);
MyAppWidgetHostView.OnUpdateAppWidgetListener secondAppHostViewListener =
mock(MyAppWidgetHostView.OnUpdateAppWidgetListener.class);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
synchronized (mLock) {
updateAppWidgetCallCount.incrementAndGet();
mLock.notifyAll();
}
return null;
}
}).when(secondAppHostViewListener).onUpdateAppWidget(any(RemoteViews.class));
secondHostView.setOnUpdateAppWidgetListener(secondAppHostViewListener);
// Update all app widgets.
final RemoteViews content = new RemoteViews(
getInstrumentation().getContext().getPackageName(),
R.layout.second_initial_layout);
getAppWidgetManager().updateAppWidget(provider.provider, content);
waitForCallCount(updateAppWidgetCallCount, 1);
// Verify the expected callbacks.
InOrder firstInOrder = inOrder(firstAppHostViewListener);
firstInOrder.verify(firstAppHostViewListener).onUpdateAppWidget(argThat(
new RemoteViewsMatcher(content.getLayoutId(),
provider.provider.getPackageName())));
InOrder secondInOrder = inOrder(secondAppHostViewListener);
secondInOrder.verify(secondAppHostViewListener).onUpdateAppWidget(argThat(
new RemoteViewsMatcher(content.getLayoutId(),
provider.provider.getPackageName())));
} finally {
// Clean up.
host.deleteAppWidgetId(firstAppWidgetId);
host.deleteAppWidgetId(secondAppWidgetId);
host.deleteHost();
revokeBindAppWidgetPermission();
}
}
public void testUpdateAppWidgetViaWidgetId() throws Exception {
// We want to bind widgets.
grantBindAppWidgetPermission();
final AtomicInteger updateAppWidgetCallCount = new AtomicInteger();
// Create a host and start listening.
AppWidgetHost host = new AppWidgetHost(
getInstrumentation().getTargetContext(), 0) {
@Override
protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
AppWidgetProviderInfo appWidget) {
return new MyAppWidgetHostView(context);
}
};
host.deleteHost();
host.startListening();
int firstAppWidgetId = 0;
try {
// Grab the provider to be bound.
AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo();
// Allocate the first widget id to bind.
firstAppWidgetId = host.allocateAppWidgetId();
// Bind the first app widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(firstAppWidgetId,
provider.getProfile(), provider.provider, null);
// Create the first host view.
MyAppWidgetHostView hostView = (MyAppWidgetHostView) host.createView(
getInstrumentation().getContext(), firstAppWidgetId, provider);
MyAppWidgetHostView.OnUpdateAppWidgetListener appHostViewListener =
mock(MyAppWidgetHostView.OnUpdateAppWidgetListener.class);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
synchronized (mLock) {
updateAppWidgetCallCount.incrementAndGet();
mLock.notifyAll();
}
return null;
}
}).when(appHostViewListener).onUpdateAppWidget(any(RemoteViews.class));
hostView.setOnUpdateAppWidgetListener(appHostViewListener);
// Update all app widgets.
RemoteViews content = new RemoteViews(
getInstrumentation().getContext().getPackageName(),
R.layout.second_initial_layout);
getAppWidgetManager().updateAppWidget(firstAppWidgetId, content);
waitForCallCount(updateAppWidgetCallCount, 1);
// Verify the expected callbacks.
InOrder inOrder = inOrder(appHostViewListener);
inOrder.verify(appHostViewListener).onUpdateAppWidget(argThat(
new RemoteViewsMatcher(content.getLayoutId(),
provider.provider.getPackageName())
));
} finally {
// Clean up.
host.deleteAppWidgetId(firstAppWidgetId);
host.deleteHost();
revokeBindAppWidgetPermission();
}
}
public void testUpdateAppWidgetViaWidgetIds() throws Exception {
// We want to bind widgets.
grantBindAppWidgetPermission();
final AtomicInteger onUpdateAppWidgetCallCount = new AtomicInteger();
// Create a host and start listening.
AppWidgetHost host = new AppWidgetHost(
getInstrumentation().getTargetContext(), 0) {
@Override
protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
AppWidgetProviderInfo appWidget) {
return new MyAppWidgetHostView(context);
}
};
host.deleteHost();
host.startListening();
int firstAppWidgetId = 0;
int secondAppWidgetId = 0;
try {
// Grab the provider to be bound.
AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo();
// Allocate the first widget id to bind.
firstAppWidgetId = host.allocateAppWidgetId();
// Bind the first app widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(firstAppWidgetId,
provider.getProfile(), provider.provider, null);
// Create the first host view.
MyAppWidgetHostView firstHostView = (MyAppWidgetHostView) host.createView(
getInstrumentation().getContext(), firstAppWidgetId, provider);
MyAppWidgetHostView.OnUpdateAppWidgetListener firstAppHostViewListener =
mock(MyAppWidgetHostView.OnUpdateAppWidgetListener.class);
firstHostView.setOnUpdateAppWidgetListener(firstAppHostViewListener);
// Allocate the second widget id to bind.
secondAppWidgetId = host.allocateAppWidgetId();
// Bind the second app widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(secondAppWidgetId,
provider.getProfile(), provider.provider, null);
// Create the second host view.
MyAppWidgetHostView secondHostView = (MyAppWidgetHostView) host.createView(
getInstrumentation().getContext(), secondAppWidgetId, provider);
MyAppWidgetHostView.OnUpdateAppWidgetListener secondAppHostViewListener =
mock(MyAppWidgetHostView.OnUpdateAppWidgetListener.class);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
synchronized (mLock) {
onUpdateAppWidgetCallCount.incrementAndGet();
mLock.notifyAll();
}
return null;
}
}).when(secondAppHostViewListener).onUpdateAppWidget(any(RemoteViews.class));
secondHostView.setOnUpdateAppWidgetListener(secondAppHostViewListener);
// Update all app widgets.
RemoteViews content = new RemoteViews(
getInstrumentation().getContext().getPackageName(),
R.layout.second_initial_layout);
getAppWidgetManager().updateAppWidget(new int[] {firstAppWidgetId,
secondAppWidgetId}, content);
waitForCallCount(onUpdateAppWidgetCallCount, 1);
// Verify the expected callbacks.
InOrder firstInOrder = inOrder(firstAppHostViewListener);
firstInOrder.verify(firstAppHostViewListener).onUpdateAppWidget(
argThat(new RemoteViewsMatcher(content.getLayoutId(),
provider.provider.getPackageName())));
InOrder secondInOrder = inOrder(secondAppHostViewListener);
secondInOrder.verify(secondAppHostViewListener).onUpdateAppWidget(
argThat(new RemoteViewsMatcher(content.getLayoutId(),
provider.provider.getPackageName()))
);
} finally {
// Clean up.
host.deleteAppWidgetId(firstAppWidgetId);
host.deleteAppWidgetId(secondAppWidgetId);
host.deleteHost();
revokeBindAppWidgetPermission();
}
}
public void testPartiallyUpdateAppWidgetViaWidgetId() throws Exception {
// We want to bind widgets.
grantBindAppWidgetPermission();
final AtomicInteger updateAppWidgetCallCount = new AtomicInteger();
// Create a host and start listening.
AppWidgetHost host = new AppWidgetHost(
getInstrumentation().getTargetContext(), 0) {
@Override
protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
AppWidgetProviderInfo appWidget) {
return new MyAppWidgetHostView(context);
}
};
host.deleteHost();
host.startListening();
int firstAppWidgetId = 0;
try {
// Grab the provider to be bound.
AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo();
// Allocate the first widget id to bind.
firstAppWidgetId = host.allocateAppWidgetId();
// Bind the first app widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(firstAppWidgetId,
provider.getProfile(), provider.provider, null);
// Create the first host view.
MyAppWidgetHostView hostView = (MyAppWidgetHostView) host.createView(
getInstrumentation().getContext(), firstAppWidgetId, provider);
MyAppWidgetHostView.OnUpdateAppWidgetListener appHostViewListener =
mock(MyAppWidgetHostView.OnUpdateAppWidgetListener.class);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
synchronized (mLock) {
updateAppWidgetCallCount.incrementAndGet();
mLock.notifyAll();
}
return null;
}
}).when(appHostViewListener).onUpdateAppWidget(any(RemoteViews.class));
hostView.setOnUpdateAppWidgetListener(appHostViewListener);
// Set the content for all app widgets.
RemoteViews content = new RemoteViews(
getInstrumentation().getContext().getPackageName(),
R.layout.first_initial_layout);
getAppWidgetManager().updateAppWidget(firstAppWidgetId, content);
waitForCallCount(updateAppWidgetCallCount, 1);
// Partially update the content for all app widgets (pretend we changed something).
getAppWidgetManager().partiallyUpdateAppWidget(firstAppWidgetId, content);
waitForCallCount(updateAppWidgetCallCount, 2);
// Verify the expected callbacks.
InOrder inOrder = inOrder(appHostViewListener);
inOrder.verify(appHostViewListener, times(2)).onUpdateAppWidget(
argThat(new RemoteViewsMatcher(content.getLayoutId(),
provider.provider.getPackageName())));
} finally {
// Clean up.
host.deleteAppWidgetId(firstAppWidgetId);
host.deleteHost();
revokeBindAppWidgetPermission();
}
}
public void testPartiallyUpdateAppWidgetViaWidgetIds() throws Exception {
// We want to bind widgets.
grantBindAppWidgetPermission();
final AtomicInteger firstAppWidgetCallCounter = new AtomicInteger();
final AtomicInteger secondAppWidgetCallCounter = new AtomicInteger();
// Create a host and start listening.
AppWidgetHost host = new AppWidgetHost(
getInstrumentation().getTargetContext(), 0) {
@Override
protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
AppWidgetProviderInfo appWidget) {
return new MyAppWidgetHostView(context);
}
};
host.deleteHost();
host.startListening();
int firstAppWidgetId = 0;
int secondAppWidgetId = 0;
try {
// Grab the provider to be bound.
AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo();
// Allocate the first widget id to bind.
firstAppWidgetId = host.allocateAppWidgetId();
// Bind the first app widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(firstAppWidgetId,
provider.getProfile(), provider.provider, null);
// Create the first host view.
MyAppWidgetHostView firstHostView = (MyAppWidgetHostView) host.createView(
getInstrumentation().getContext(), firstAppWidgetId, provider);
MyAppWidgetHostView.OnUpdateAppWidgetListener firstAppHostViewListener =
mock(MyAppWidgetHostView.OnUpdateAppWidgetListener.class);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
synchronized (mLock) {
firstAppWidgetCallCounter.incrementAndGet();
mLock.notifyAll();
}
return null;
}
}).when(firstAppHostViewListener).onUpdateAppWidget(any(RemoteViews.class));
firstHostView.setOnUpdateAppWidgetListener(firstAppHostViewListener);
// Allocate the second widget id to bind.
secondAppWidgetId = host.allocateAppWidgetId();
// Bind the second app widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(secondAppWidgetId,
provider.getProfile(), provider.provider, null);
// Create the second host view.
MyAppWidgetHostView secondHostView = (MyAppWidgetHostView) host.createView(
getInstrumentation().getContext(), secondAppWidgetId, provider);
MyAppWidgetHostView.OnUpdateAppWidgetListener secondAppHostViewListener =
mock(MyAppWidgetHostView.OnUpdateAppWidgetListener.class);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
synchronized (mLock) {
secondAppWidgetCallCounter.incrementAndGet();
mLock.notifyAll();
}
return null;
}
}).when(secondAppHostViewListener).onUpdateAppWidget(any(RemoteViews.class));
secondHostView.setOnUpdateAppWidgetListener(secondAppHostViewListener);
// Set the content for all app widgets.
RemoteViews content = new RemoteViews(
getInstrumentation().getContext().getPackageName(),
R.layout.first_initial_layout);
getAppWidgetManager().updateAppWidget(new int[]{firstAppWidgetId,
secondAppWidgetId}, content);
waitForCallCount(firstAppWidgetCallCounter, 1);
waitForCallCount(secondAppWidgetCallCounter, 1);
// Partially update the content for all app widgets (pretend we changed something).
getAppWidgetManager().partiallyUpdateAppWidget(new int[] {firstAppWidgetId,
secondAppWidgetId}, content);
waitForCallCount(firstAppWidgetCallCounter, 2);
waitForCallCount(secondAppWidgetCallCounter, 2);
// Verify the expected callbacks.
InOrder firstInOrder = inOrder(firstAppHostViewListener);
firstInOrder.verify(firstAppHostViewListener, times(2)).onUpdateAppWidget(
argThat(new RemoteViewsMatcher(content.getLayoutId(),
provider.provider.getPackageName())));
InOrder secondInOrder = inOrder(secondAppHostViewListener);
secondInOrder.verify(secondAppHostViewListener, times(2)).onUpdateAppWidget(
argThat(new RemoteViewsMatcher(content.getLayoutId(),
provider.provider.getPackageName())));
} finally {
// Clean up.
host.deleteAppWidgetId(firstAppWidgetId);
host.deleteAppWidgetId(secondAppWidgetId);
host.deleteHost();
revokeBindAppWidgetPermission();
}
}
public void testCollectionWidgets() throws Exception {
// We want to bind widgets.
grantBindAppWidgetPermission();
final AtomicInteger invocationCounter = new AtomicInteger();
final Context context = getInstrumentation().getTargetContext();
// Create a host and start listening.
final AppWidgetHost host = new AppWidgetHost(context, 0);
host.deleteHost();
host.startListening();
final int appWidgetId;
try {
// Configure the provider behavior.
AppWidgetProviderCallbacks callbacks = createAppWidgetProviderCallbacks(
invocationCounter);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
final int appWidgetId = ((int[]) invocation.getArguments()[2])[0];
Intent intent = new Intent(context, MyAppWidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
RemoteViews removeViews = new RemoteViews(context.getPackageName(),
R.layout.collection_widget_layout);
removeViews.setRemoteAdapter(R.id.stack_view, intent);
getAppWidgetManager().updateAppWidget(appWidgetId, removeViews);
synchronized (mLock) {
invocationCounter.incrementAndGet();
mLock.notifyAll();
}
return null;
}
}).when(callbacks).onUpdate(any(Context.class), any(AppWidgetManager.class),
any(int[].class));
FirstAppWidgetProvider.setCallbacks(callbacks);
// Grab the provider to be bound.
final AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo();
// Allocate a widget id to bind.
appWidgetId = host.allocateAppWidgetId();
// Bind the app widget.
getAppWidgetManager().bindAppWidgetIdIfAllowed(appWidgetId,
provider.getProfile(), provider.provider, null);
// Wait for onEnabled and onUpdate
waitForCallCount(invocationCounter, 2);
// Configure the app widget service behavior.
RemoteViewsFactory factory = mock(RemoteViewsFactory.class);
doAnswer(new Answer<Integer>() {
@Override
public Integer answer(InvocationOnMock invocation) throws Throwable {
return 1;
}
}).when(factory).getCount();
doAnswer(new Answer<RemoteViews>() {
@Override
public RemoteViews answer(InvocationOnMock invocation) throws Throwable {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.collection_widget_item_layout);
remoteViews.setTextViewText(R.id.text_view, context.getText(R.string.foo));
synchronized (mLock) {
invocationCounter.incrementAndGet();
}
return remoteViews;
}
}).when(factory).getViewAt(any(int.class));
doAnswer(new Answer<Integer>() {
@Override
public Integer answer(InvocationOnMock invocation) throws Throwable {
return 1;
}
}).when(factory).getViewTypeCount();
MyAppWidgetService.setFactory(factory);
getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
host.createView(context, appWidgetId, provider);
}
});
// Wait for the interactions to occur.
waitForCallCount(invocationCounter, 3);
// Verify the interactions.
verify(factory, atLeastOnce()).hasStableIds();
verify(factory, atLeastOnce()).getViewTypeCount();
verify(factory, atLeastOnce()).getCount();
verify(factory, atLeastOnce()).getLoadingView();
verify(factory, atLeastOnce()).getViewAt(same(0));
} finally {
// Clean up.
FirstAppWidgetProvider.setCallbacks(null);
host.deleteHost();
revokeBindAppWidgetPermission();
}
}
private void waitForCallCount(AtomicInteger counter, int expectedCount) {
synchronized (mLock) {
final long startTimeMillis = SystemClock.uptimeMillis();
while (counter.get() < expectedCount) {
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
final long remainingTimeMillis = OPERATION_TIMEOUT - elapsedTimeMillis;
if (remainingTimeMillis <= 0) {
fail("Did not get expected call");
}
try {
mLock.wait(remainingTimeMillis);
} catch (InterruptedException ie) {
/* ignore */
}
}
}
}
@SuppressWarnings("deprecation")
private void assertExpectedInstalledProviders(List<AppWidgetProviderInfo> providers) {
boolean firstProviderVerified = false;
boolean secondProviderVerified = false;
ComponentName firstComponentName = new ComponentName(
getInstrumentation().getTargetContext().getPackageName(),
FirstAppWidgetProvider.class.getName());
ComponentName secondComponentName = new ComponentName(
getInstrumentation().getTargetContext().getPackageName(),
SecondAppWidgetProvider.class.getName());
final int providerCount = providers.size();
for (int i = 0; i < providerCount; i++) {
AppWidgetProviderInfo provider = providers.get(i);
if (firstComponentName.equals(provider.provider)
&& android.os.Process.myUserHandle().equals(provider.getProfile())) {
assertEquals(getNormalizedDimensionResource(R.dimen.first_min_appwidget_size),
provider.minWidth);
assertEquals(getNormalizedDimensionResource(R.dimen.first_min_appwidget_size),
provider.minHeight);
assertEquals(getNormalizedDimensionResource(
R.dimen.first_min_resize_appwidget_size), provider.minResizeWidth);
assertEquals(getNormalizedDimensionResource(
R.dimen.first_min_resize_appwidget_size), provider.minResizeHeight);
assertEquals(getIntResource(R.integer.first_update_period_millis),
provider.updatePeriodMillis);
assertEquals(getInstrumentation().getTargetContext().getPackageName(),
provider.configure.getPackageName());
assertEquals(FIRST_APP_WIDGET_CONFIGURE_ACTIVITY,
provider.configure.getClassName());
assertEquals(getIntResource(R.integer.first_resize_mode),
provider.resizeMode);
assertEquals(getIntResource(R.integer.first_widget_category),
provider.widgetCategory);
assertEquals(R.layout.first_initial_layout,
provider.initialLayout);
assertEquals(R.layout.first_initial_keyguard_layout,
provider.initialKeyguardLayout);
assertEquals(R.drawable.first_android_icon,
provider.previewImage);
assertEquals(R.id.first_auto_advance_view_id,
provider.autoAdvanceViewId);
firstProviderVerified = true;
} else if (secondComponentName.equals(provider.provider)
&& android.os.Process.myUserHandle().equals(provider.getProfile())) {
assertEquals(getNormalizedDimensionResource(R.dimen.second_min_appwidget_size),
provider.minWidth);
assertEquals(getNormalizedDimensionResource(R.dimen.second_min_appwidget_size),
provider.minHeight);
assertEquals(getNormalizedDimensionResource(
R.dimen.second_min_resize_appwidget_size), provider.minResizeWidth);
assertEquals(getNormalizedDimensionResource(
R.dimen.second_min_resize_appwidget_size), provider.minResizeHeight);
assertEquals(getIntResource(R.integer.second_update_period_millis),
provider.updatePeriodMillis);
assertEquals(getInstrumentation().getTargetContext().getPackageName(),
provider.configure.getPackageName());
assertEquals(SECOND_APP_WIDGET_CONFIGURE_ACTIVITY,
provider.configure.getClassName());
assertEquals(getIntResource(R.integer.second_resize_mode),
provider.resizeMode);
assertEquals(getIntResource(R.integer.second_widget_category),
provider.widgetCategory);
assertEquals(R.layout.second_initial_layout,
provider.initialLayout);
assertEquals(R.layout.second_initial_keyguard_layout,
provider.initialKeyguardLayout);
assertEquals(R.drawable.second_android_icon,
provider.previewImage);
assertEquals(R.id.second_auto_advance_view_id,
provider.autoAdvanceViewId);
secondProviderVerified = true;
}
}
assertTrue(firstProviderVerified && secondProviderVerified);
}
private void grantBindAppWidgetPermission() {
executeShellCommandIgnoreOutput(GRANT_BIND_APP_WIDGET_PERMISSION_COMMAND);
}
private void revokeBindAppWidgetPermission() {
executeShellCommandIgnoreOutput(REVOKE_BIND_APP_WIDGET_PERMISSION_COMMAND);
}
private void executeShellCommandIgnoreOutput(String command) {
ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation()
.executeShellCommand(command);
try {
Streams.readFully(new FileInputStream(pfd.getFileDescriptor()));
} catch (IOException ioe) {
IoUtils.closeQuietly(pfd);
}
}
private AppWidgetProviderInfo getFirstAppWidgetProviderInfo() {
ComponentName firstComponentName = new ComponentName(
getInstrumentation().getTargetContext().getPackageName(),
FirstAppWidgetProvider.class.getName());
return getProviderInfo(firstComponentName);
}
private AppWidgetProviderInfo getSecondAppWidgetProviderInfo() {
ComponentName secondComponentName = new ComponentName(
getInstrumentation().getTargetContext().getPackageName(),
SecondAppWidgetProvider.class.getName());
return getProviderInfo(secondComponentName);
}
private AppWidgetProviderInfo getProviderInfo(ComponentName componentName) {
List<AppWidgetProviderInfo> providers = getAppWidgetManager().getInstalledProviders();
final int providerCount = providers.size();
for (int i = 0; i < providerCount; i++) {
AppWidgetProviderInfo provider = providers.get(i);
if (componentName.equals(provider.provider)
&& Process.myUserHandle().equals(provider.getProfile())) {
return provider;
}
}
return null;
}
private int getNormalizedDimensionResource(int resId) {
return getInstrumentation().getTargetContext().getResources()
.getDimensionPixelSize(resId);
}
private int getIntResource(int resId) {
return getInstrumentation().getTargetContext().getResources().getInteger(resId);
}
private AppWidgetManager getAppWidgetManager() {
return (AppWidgetManager) getInstrumentation().getTargetContext()
.getSystemService(Context.APPWIDGET_SERVICE);
}
private AppWidgetProviderCallbacks createAppWidgetProviderCallbacks(
final AtomicInteger callCounter) {
// Set a mock to intercept provider callbacks.
AppWidgetProviderCallbacks callbacks = mock(AppWidgetProviderCallbacks.class);
// onEnabled
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
synchronized (mLock) {
callCounter.incrementAndGet();
mLock.notifyAll();
}
return null;
}
}).when(callbacks).onEnabled(any(Context.class));
// onUpdate
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
synchronized (mLock) {
callCounter.incrementAndGet();
mLock.notifyAll();
}
return null;
}
}).when(callbacks).onUpdate(any(Context.class), any(AppWidgetManager.class),
any(int[].class));
// onAppWidgetOptionsChanged
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
synchronized (mLock) {
callCounter.incrementAndGet();
mLock.notifyAll();
}
return null;
}
}).when(callbacks).onAppWidgetOptionsChanged(any(Context.class),
any(AppWidgetManager.class), any(int.class), any(Bundle.class));
// onDeleted
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
synchronized (mLock) {
callCounter.incrementAndGet();
mLock.notifyAll();
}
return null;
}
}).when(callbacks).onDeleted(any(Context.class), any(int[].class));
// onDisabled
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
synchronized (mLock) {
callCounter.incrementAndGet();
mLock.notifyAll();
}
return null;
}
}).when(callbacks).onDisabled(any(Context.class));
// onRestored
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
synchronized (mLock) {
callCounter.incrementAndGet();
mLock.notifyAll();
}
return null;
}
}).when(callbacks).onRestored(any(Context.class), any(int[].class),
any(int[].class));
return callbacks;
}
private static boolean equalOptions(Bundle first, Bundle second) {
return first.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH)
== second.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH)
&& first.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT)
== second.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT)
&& first.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH)
== second.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH)
&& first.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT)
== second.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT);
}
private static final class OptionsMatcher extends BaseMatcher<Bundle> {
private Bundle mOptions;
public OptionsMatcher(Bundle options) {
mOptions = options;
}
@Override
public boolean matches(Object item) {
Bundle options = (Bundle) item;
return equalOptions(mOptions, options);
}
@Override
public void describeTo(Description description) {
/* do nothing */
}
}
private static final class WidgetIdsMatcher extends BaseMatcher<int[]> {
private final int[] mWidgetIds;
public WidgetIdsMatcher(int[] widgetIds) {
mWidgetIds = widgetIds;
}
@Override
public boolean matches(Object item) {
final int[] widgetIds = (int[]) item;
return Arrays.equals(widgetIds, mWidgetIds);
}
@Override
public void describeTo(Description description) {
/* do nothing */
}
}
private static final class RemoteViewsMatcher extends BaseMatcher<RemoteViews> {
private final int mLayoutId;
private final String mPackageName;
public RemoteViewsMatcher(int layoutId, String packageName) {
mLayoutId = layoutId;
mPackageName = packageName;
}
@Override
public boolean matches(Object item) {
final RemoteViews remoteViews = (RemoteViews) item;
return remoteViews != null && remoteViews.getLayoutId() == mLayoutId
&& remoteViews.getPackage().equals(mPackageName);
}
@Override
public void describeTo(Description description) {
/* do nothing */
}
}
private static class MyAppWidgetHostView extends AppWidgetHostView {
private OnUpdateAppWidgetListener mOnUpdateAppWidgetListener;
public interface OnUpdateAppWidgetListener {
public void onUpdateAppWidget(RemoteViews remoteViews);
}
private MyAppWidgetHostView(Context context) {
super(context);
}
public void setOnUpdateAppWidgetListener(OnUpdateAppWidgetListener listener) {
mOnUpdateAppWidgetListener = listener;
}
@Override
public void updateAppWidget(RemoteViews remoteViews) {
super.updateAppWidget(remoteViews);
if (mOnUpdateAppWidgetListener != null) {
mOnUpdateAppWidgetListener.onUpdateAppWidget(remoteViews);
}
}
}
}