| /* |
| * 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.isNull; |
| 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.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.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.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 grant_bind_permission --package android.cts.appwidget --user 0"; |
| |
| private static final String REVOKE_BIND_APP_WIDGET_PERMISSION_COMMAND = |
| "appwidget revoke_bind_permission --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().getInstalledProviders( |
| new UserHandle[] {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<UserHandle> profilesList = userManager.getUserProfiles(); |
| UserHandle[] profilesArray = new UserHandle[profilesList.size()]; |
| profilesList.toArray(profilesArray); |
| |
| List<AppWidgetProviderInfo> providers = getAppWidgetManager().getInstalledProviders( |
| profilesArray); |
| |
| // Make sure we have our two providers in the list. |
| assertExpectedInstalledProviders(providers); |
| } |
| |
| public void testBindAppWidget() throws Exception { |
| // Create a host and start listening. |
| AppWidgetHost host = new AppWidgetHost(getInstrumentation().getTargetContext(), 0); |
| 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 pretent 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.deleteHost(); |
| revokeBindAppWidgetPermission(); |
| } |
| } |
| |
| public void testAppWidgetProviderCallbacks() throws Exception { |
| final AtomicInteger disabledCallCounter = new AtomicInteger(); |
| |
| // Set a mock to intercept provider callbacks. |
| AppWidgetProviderCallbacks callbacks = mock(AppWidgetProviderCallbacks.class); |
| doAnswer(new Answer<Void>() { |
| @Override |
| public Void answer(InvocationOnMock invocation) throws Throwable { |
| synchronized (mLock) { |
| disabledCallCounter.incrementAndGet(); |
| mLock.notifyAll(); |
| } |
| return null; |
| } |
| }).when(callbacks).onDeleted(any(Context.class), any(int[].class)); |
| FirstAppWidgetProvider.setCallbacks(callbacks); |
| |
| final int firstAppWidgetId; |
| final int secondAppWidgetId; |
| |
| final Bundle firstOptions; |
| final Bundle secondOptions; |
| |
| // Create a host and start listening. |
| AppWidgetHost host = spy(new AppWidgetHost(getInstrumentation().getTargetContext(), 0)); |
| 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); |
| |
| // 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); |
| |
| // Allocate the second app widget id to bind. |
| secondAppWidgetId = host.allocateAppWidgetId(); |
| |
| // Bind the second widget. |
| getAppWidgetManager().bindAppWidgetIdIfAllowed(secondAppWidgetId, |
| provider.getProfile(), provider.provider, null); |
| |
| // 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); |
| |
| // Delete the first widget. |
| host.deleteAppWidgetId(firstAppWidgetId); |
| |
| // Delete the second widget. |
| host.deleteAppWidgetId(secondAppWidgetId); |
| |
| waitForCallCount(disabledCallCounter, 1); |
| |
| // 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. |
| revokeBindAppWidgetPermission(); |
| } |
| } |
| |
| public void testTwoAppWidgetProviderCallbacks() throws Exception { |
| final AtomicInteger disabledCallCounter = new AtomicInteger(); |
| |
| // Set a mock to intercept first provider callbacks. |
| AppWidgetProviderCallbacks firstCallbacks = mock(AppWidgetProviderCallbacks.class); |
| FirstAppWidgetProvider.setCallbacks(firstCallbacks); |
| |
| // Set a mock to intercept second provider callbacks. |
| AppWidgetProviderCallbacks secondCallbacks = mock(AppWidgetProviderCallbacks.class); |
| doAnswer(new Answer<Void>() { |
| @Override |
| public Void answer(InvocationOnMock invocation) throws Throwable { |
| synchronized (mLock) { |
| disabledCallCounter.incrementAndGet(); |
| mLock.notifyAll(); |
| } |
| return null; |
| } |
| }).when(firstCallbacks).onDisabled(any(Context.class)); |
| SecondAppWidgetProvider.setCallbacks(secondCallbacks); |
| |
| final int firstAppWidgetId; |
| final int secondAppWidgetId; |
| |
| // Create a host and start listening. |
| AppWidgetHost host = spy(new AppWidgetHost( |
| getInstrumentation().getTargetContext(), 0)); |
| 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); |
| |
| // Grab the second provider we defined to be bound. |
| AppWidgetProviderInfo secondProvider = getSecondAppWidgetProviderInfo(); |
| |
| // Bind the second widget. |
| getAppWidgetManager().bindAppWidgetIdIfAllowed(secondAppWidgetId, |
| secondProvider.getProfile(), secondProvider.provider, null); |
| |
| // Delete the first widget. |
| host.deleteAppWidgetId(firstAppWidgetId); |
| |
| // Delete the second widget. |
| host.deleteAppWidgetId(secondAppWidgetId); |
| |
| // Wait for all callbacks to settle. |
| waitForCallCount(disabledCallCounter, 1); |
| |
| // 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. |
| 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.startListening(); |
| |
| 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. |
| final int firstAppWidgetId = host.allocateAppWidgetId(); |
| |
| // Bind the first widget. |
| getAppWidgetManager().bindAppWidgetIdIfAllowed(firstAppWidgetId, |
| provider.getProfile(), provider.provider, null); |
| |
| // Allocate the second widget id to bind. |
| final int 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.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.startListening(); |
| |
| try { |
| // Allocate an widget id to bind. |
| final int 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()); |
| } finally { |
| // Clean up. |
| 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.startListening(); |
| |
| try { |
| // Grab the provider we defined to be bound. |
| AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo(); |
| |
| // Allocate an widget id to bind. |
| final int 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.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.startListening(); |
| |
| try { |
| // Allocate an widget id to bind. |
| final int 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. |
| 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.startListening(); |
| |
| // Create the second host and start listening. |
| AppWidgetHost secondHost = new AppWidgetHost( |
| getInstrumentation().getTargetContext(), 1); |
| secondHost.startListening(); |
| |
| try { |
| // Grab the provider we defined to be bound. |
| AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo(); |
| |
| // Allocate the first widget id to bind. |
| final int firstAppWidgetId = firstHost.allocateAppWidgetId(); |
| |
| // Bind the first app widget. |
| getAppWidgetManager().bindAppWidgetIdIfAllowed(firstAppWidgetId, |
| provider.getProfile(), provider.provider, null); |
| |
| // Allocate the second widget id to bind. |
| final int 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. |
| 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.startListening(); |
| |
| try { |
| // Grab the provider we defined to be bound. |
| AppWidgetProviderInfo firstLookupProvider = getFirstAppWidgetProviderInfo(); |
| |
| // Allocate a widget id to bind. |
| final int 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 disbaled. |
| 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.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.startListening(); |
| |
| try { |
| // Grab the provider to be bound. |
| AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo(); |
| |
| // Allocate the first widget id to bind. |
| final int 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. |
| final int 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, 2); |
| |
| // Verify the expected callbacks. |
| InOrder firstInOrder = inOrder(firstAppHostViewListener); |
| firstInOrder.verify(firstAppHostViewListener).onUpdateAppWidget( |
| isNull(RemoteViews.class)); |
| firstInOrder.verify(firstAppHostViewListener).onUpdateAppWidget(argThat( |
| new RemoteViewsMatcher(content.getLayoutId(), |
| provider.provider.getPackageName()))); |
| |
| InOrder secondInOrder = inOrder(secondAppHostViewListener); |
| secondInOrder.verify(secondAppHostViewListener).onUpdateAppWidget( |
| isNull(RemoteViews.class)); |
| secondInOrder.verify(secondAppHostViewListener).onUpdateAppWidget(argThat( |
| new RemoteViewsMatcher(content.getLayoutId(), |
| provider.provider.getPackageName()))); |
| } finally { |
| // Clean up. |
| 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.startListening(); |
| |
| try { |
| // Grab the provider to be bound. |
| AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo(); |
| |
| // Allocate the first widget id to bind. |
| final int 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, 2); |
| |
| // Verify the expected callbacks. |
| InOrder inOrder = inOrder(appHostViewListener); |
| inOrder.verify(appHostViewListener).onUpdateAppWidget( |
| isNull(RemoteViews.class)); |
| inOrder.verify(appHostViewListener).onUpdateAppWidget(argThat( |
| new RemoteViewsMatcher(content.getLayoutId(), |
| provider.provider.getPackageName()))); |
| } finally { |
| // Clean up. |
| 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.startListening(); |
| |
| try { |
| // Grab the provider to be bound. |
| AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo(); |
| |
| // Allocate the first widget id to bind. |
| final int 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. |
| final int 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, 2); |
| |
| // Verify the expected callbacks. |
| InOrder firstInOrder = inOrder(firstAppHostViewListener); |
| firstInOrder.verify(firstAppHostViewListener).onUpdateAppWidget( |
| isNull(RemoteViews.class)); |
| firstInOrder.verify(firstAppHostViewListener).onUpdateAppWidget( |
| argThat(new RemoteViewsMatcher(content.getLayoutId(), |
| provider.provider.getPackageName()))); |
| |
| InOrder secondInOrder = inOrder(secondAppHostViewListener); |
| secondInOrder.verify(secondAppHostViewListener).onUpdateAppWidget( |
| isNull(RemoteViews.class)); |
| secondInOrder.verify(secondAppHostViewListener).onUpdateAppWidget( |
| argThat(new RemoteViewsMatcher(content.getLayoutId(), |
| provider.provider.getPackageName()))); |
| } finally { |
| // Clean up. |
| 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.startListening(); |
| |
| try { |
| // Grab the provider to be bound. |
| AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo(); |
| |
| // Allocate the first widget id to bind. |
| final int 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, 2); |
| |
| // Partially update the content for all app widgets (pretent we changed somehting). |
| getAppWidgetManager().partiallyUpdateAppWidget(firstAppWidgetId, content); |
| |
| waitForCallCount(updateAppWidgetCallCount, 3); |
| |
| // Verify the expected callbacks. |
| InOrder inOrder = inOrder(appHostViewListener); |
| inOrder.verify(appHostViewListener).onUpdateAppWidget( |
| isNull(RemoteViews.class)); |
| inOrder.verify(appHostViewListener, times(2)).onUpdateAppWidget( |
| argThat(new RemoteViewsMatcher(content.getLayoutId(), |
| provider.provider.getPackageName()))); |
| } finally { |
| // Clean up. |
| host.deleteHost(); |
| revokeBindAppWidgetPermission(); |
| } |
| } |
| |
| public void testPartiallyUpdateAppWidgetViaWidgetIds() throws Exception { |
| // We want to bind widgets. |
| grantBindAppWidgetPermission(); |
| |
| final AtomicInteger updateAppWidgetCallCounter = 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.startListening(); |
| |
| try { |
| // Grab the provider to be bound. |
| AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo(); |
| |
| // Allocate the first widget id to bind. |
| final int 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. |
| final int 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) { |
| updateAppWidgetCallCounter.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(updateAppWidgetCallCounter, 2); |
| |
| // Partially update the content for all app widgets (pretent we changed somehting). |
| getAppWidgetManager().partiallyUpdateAppWidget(new int[] {firstAppWidgetId, |
| secondAppWidgetId}, content); |
| |
| waitForCallCount(updateAppWidgetCallCounter, 3); |
| |
| // Verify the expected callbacks. |
| InOrder firstInOrder = inOrder(firstAppHostViewListener); |
| firstInOrder.verify(firstAppHostViewListener).onUpdateAppWidget( |
| isNull(RemoteViews.class)); |
| firstInOrder.verify(firstAppHostViewListener, times(2)).onUpdateAppWidget( |
| argThat(new RemoteViewsMatcher(content.getLayoutId(), |
| provider.provider.getPackageName()))); |
| |
| InOrder secondInOrder = inOrder(secondAppHostViewListener); |
| secondInOrder.verify(secondAppHostViewListener).onUpdateAppWidget( |
| isNull(RemoteViews.class)); |
| secondInOrder.verify(secondAppHostViewListener, times(2)).onUpdateAppWidget( |
| argThat(new RemoteViewsMatcher(content.getLayoutId(), |
| provider.provider.getPackageName()))); |
| } finally { |
| // Clean up. |
| host.deleteHost(); |
| revokeBindAppWidgetPermission(); |
| } |
| } |
| |
| public void testCollectionWidgets() throws Exception { |
| // We want to bind widgets. |
| grantBindAppWidgetPermission(); |
| |
| final AtomicInteger getViewCounter = new AtomicInteger(); |
| final Context context = getInstrumentation().getTargetContext(); |
| |
| // Create a host and start listening. |
| AppWidgetHost host = new AppWidgetHost(context, 0); |
| host.startListening(); |
| |
| try { |
| // Configure the provider behavior. |
| AppWidgetProviderCallbacks callbacks = mock(AppWidgetProviderCallbacks.class); |
| 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); |
| |
| return null; |
| } |
| }).when(callbacks).onUpdate(any(Context.class), any(AppWidgetManager.class), |
| any(int[].class)); |
| FirstAppWidgetProvider.setCallbacks(callbacks); |
| |
| // Grab the provider to be bound. |
| AppWidgetProviderInfo provider = getFirstAppWidgetProviderInfo(); |
| |
| // Allocate a widget id to bind. |
| final int appWidgetId = host.allocateAppWidgetId(); |
| |
| // Bind the app widget. |
| getAppWidgetManager().bindAppWidgetIdIfAllowed(appWidgetId, |
| provider.getProfile(), provider.provider, null); |
| |
| // 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) { |
| getViewCounter.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); |
| |
| host.createView(context, appWidgetId, provider); |
| |
| // Wait for the interactions to occur. |
| waitForCallCount(getViewCounter, 1); |
| |
| // 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. |
| 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 to onUpdateAppWidget"); |
| } |
| 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)) { |
| assertEquals(android.os.Process.myUserHandle(), |
| 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)) { |
| assertEquals(android.os.Process.myUserHandle(), |
| 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 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; |
| |
| // This is somehow gross but we cannot set the listener in the |
| // constructor since this means returning different instance |
| // for different widget id from the host factory method but the |
| // widget ids are not created at this point. |
| private boolean mInitiallCallWithNullViewsReceived; |
| |
| public interface OnUpdateAppWidgetListener { |
| public void onUpdateAppWidget(RemoteViews remoteViews); |
| } |
| |
| private MyAppWidgetHostView(Context context) { |
| super(context); |
| } |
| |
| public void setOnUpdateAppWidgetListener(OnUpdateAppWidgetListener listener) { |
| mOnUpdateAppWidgetListener = listener; |
| if (mInitiallCallWithNullViewsReceived) { |
| mOnUpdateAppWidgetListener.onUpdateAppWidget(null); |
| } |
| } |
| |
| @Override |
| public void updateAppWidget(RemoteViews remoteViews) { |
| super.updateAppWidget(remoteViews); |
| if (mOnUpdateAppWidgetListener != null) { |
| mOnUpdateAppWidgetListener.onUpdateAppWidget(remoteViews); |
| } else if (remoteViews == null) { |
| mInitiallCallWithNullViewsReceived = true; |
| } |
| } |
| } |
| } |