1e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal/* 2e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal * Copyright (C) 2017 The Android Open Source Project 3e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal * 4e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal * Licensed under the Apache License, Version 2.0 (the "License"); 5e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal * you may not use this file except in compliance with the License. 6e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal * You may obtain a copy of the License at 7e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal * 8e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal * http://www.apache.org/licenses/LICENSE-2.0 9e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal * 10e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal * Unless required by applicable law or agreed to in writing, software 11e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal * distributed under the License is distributed on an "AS IS" BASIS, 12e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal * See the License for the specific language governing permissions and 14e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal * limitations under the License. 15e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal */ 16e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 17e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalpackage android.widget; 18e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 19e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport static org.junit.Assert.assertEquals; 20e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport static org.junit.Assert.assertFalse; 21e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport static org.junit.Assert.assertNotNull; 22e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport static org.junit.Assert.assertTrue; 23e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport static org.mockito.Mockito.any; 24e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport static org.mockito.Mockito.anyInt; 25e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport static org.mockito.Mockito.mock; 26e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport static org.mockito.Mockito.never; 27e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport static org.mockito.Mockito.times; 28e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport static org.mockito.Mockito.verify; 29e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport static org.mockito.Mockito.when; 30e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 31e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport android.app.IServiceConnection; 32e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport android.appwidget.AppWidgetManager; 33e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport android.content.Context; 34e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport android.content.ContextWrapper; 35e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport android.content.Intent; 36e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport android.content.ServiceConnection; 37e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport android.database.DataSetObserver; 38e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport android.os.Handler; 39e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport android.os.Looper; 40e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport android.os.RemoteException; 41e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport android.support.test.InstrumentationRegistry; 42e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport android.support.test.filters.SmallTest; 43e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport android.support.test.runner.AndroidJUnit4; 44e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport android.view.View; 45e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 46e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport com.android.frameworks.coretests.R; 47e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport com.android.internal.widget.IRemoteViewsFactory; 48e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 49e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport org.junit.Before; 50e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport org.junit.Test; 51e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport org.junit.runner.RunWith; 52e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport org.mockito.Mock; 53e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport org.mockito.MockitoAnnotations; 54e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 55e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport java.util.ArrayList; 56e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport java.util.concurrent.CountDownLatch; 57e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport java.util.concurrent.TimeUnit; 58e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalimport java.util.function.Supplier; 59e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 60e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal/** 61e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal * Tests for RemoteViewsAdapter. 62e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal */ 63e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal@RunWith(AndroidJUnit4.class) 64e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal@SmallTest 65e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyalpublic class RemoteViewsAdapterTest { 66e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 67e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Mock AppWidgetManager mAppWidgetManager; 68e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Mock IServiceConnection mIServiceConnection; 69e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Mock RemoteViewsAdapter.RemoteAdapterConnectionCallback mCallback; 70e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 71e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal private Handler mMainHandler; 72e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal private TestContext mContext; 73e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 74e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Before 75e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public void setup() { 76e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal MockitoAnnotations.initMocks(this); 77e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal when(mAppWidgetManager 78e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal .bindRemoteViewsService(any(), anyInt(), any(), any(), anyInt())).thenReturn(true); 79e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal mContext = new TestContext(); 80e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal mMainHandler = new Handler(Looper.getMainLooper()); 81e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 82e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 83e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Test 84e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public void onRemoteAdapterConnected_after_metadata_loaded() throws Throwable { 85e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal RemoteViewsAdapter adapter = getOnUiThread( 86e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal () -> new RemoteViewsAdapter(mContext, new DistinctIntent(), mCallback, false)); 87e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal assertFalse(adapter.isDataReady()); 88e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 89e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal assertNotNull(mContext.conn.get()); 90e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 91e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal ViewsFactory factory = new ViewsFactory(1); 92e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal mContext.sendConnect(factory); 93e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 94e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal waitOnHandler(mMainHandler); 95e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal verify(mCallback, never()).onRemoteAdapterConnected(); 96e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 97e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal factory.loadingView.set(createViews("loading")); 98e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal waitOnHandler(mContext.handler.get()); 99e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal waitOnHandler(mMainHandler); 100e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal verify(mCallback, times(1)).onRemoteAdapterConnected(); 101e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 102e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal assertEquals((Integer) 1, getOnUiThread(adapter::getCount)); 103e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 104e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal // Service is unbound 105e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal assertTrue(isUnboundOrScheduled()); 106e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 107e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 108e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Test 109e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public void viewReplaced_after_mainView_loaded() throws Throwable { 110e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal RemoteViewsAdapter adapter = getOnUiThread( 111e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal () -> new RemoteViewsAdapter(mContext, new DistinctIntent(), mCallback, false)); 112e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 113e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal ViewsFactory factory = new ViewsFactory(1); 114e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal factory.loadingView.set(createViews("loading")); 115e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal mContext.sendConnect(factory); 116e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 117e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal waitOnHandler(mContext.handler.get()); 118e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal waitOnHandler(mMainHandler); 119e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 120e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal // Returned view contains the loading text 121e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal View view = getOnUiThread(() -> adapter.getView(0, null, new FrameLayout(mContext))); 122e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal ArrayList<View> search = new ArrayList<>(); 123e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal view.findViewsWithText(search, "loading", View.FIND_VIEWS_WITH_TEXT); 124e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal assertEquals(1, search.size()); 125e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 126e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal // Send the final remoteViews 127e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal factory.views[0].set(createViews("updated")); 128e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal waitOnHandler(mContext.handler.get()); 129e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal waitOnHandler(mMainHandler); 130e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 131e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal // Existing view got updated with new text 132e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal search.clear(); 133e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal view.findViewsWithText(search, "loading", View.FIND_VIEWS_WITH_TEXT); 134e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal assertTrue(search.isEmpty()); 135e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal view.findViewsWithText(search, "updated", View.FIND_VIEWS_WITH_TEXT); 136e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal assertEquals(1, search.size()); 137e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 138e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal // Service is unbound 139e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal assertTrue(isUnboundOrScheduled()); 140e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 141e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 142e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Test 143e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public void notifyDataSetChanged_deferred() throws Throwable { 144e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal RemoteViewsAdapter adapter = getOnUiThread( 145e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal () -> new RemoteViewsAdapter(mContext, new DistinctIntent(), mCallback, false)); 146e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 147e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal ViewsFactory factory = new ViewsFactory(1); 148e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal factory.loadingView.set(createViews("loading")); 149e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal mContext.sendConnect(factory); 150e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 151e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal waitOnHandler(mContext.handler.get()); 152e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal waitOnHandler(mMainHandler); 153e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal assertEquals((Integer) 1, getOnUiThread(adapter::getCount)); 154e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 155e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal // Reset the loading view so that next refresh is blocked 156e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal factory.loadingView = new LockedValue<>(); 157e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal factory.mCount = 3; 158e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal DataSetObserver observer = mock(DataSetObserver.class); 159e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal getOnUiThread(() -> { 160e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal adapter.registerDataSetObserver(observer); 161e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal adapter.notifyDataSetChanged(); 162e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return null; 163e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal }); 164e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 165e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal waitOnHandler(mMainHandler); 166e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal // Still giving the old values 167e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal verify(observer, never()).onChanged(); 168e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal assertEquals((Integer) 1, getOnUiThread(adapter::getCount)); 169e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 170e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal factory.loadingView.set(createViews("refreshed")); 171e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal waitOnHandler(mContext.handler.get()); 172e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal waitOnHandler(mMainHandler); 173e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 174e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal // When the service returns new data, UI is updated. 175e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal verify(observer, times(1)).onChanged(); 176e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal assertEquals((Integer) 3, getOnUiThread(adapter::getCount)); 177e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 178e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal // Service is unbound 179e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal assertTrue(isUnboundOrScheduled()); 180e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 181e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 182e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Test 183e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public void serviceDisconnected_before_getView() throws Throwable { 184e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal RemoteViewsAdapter adapter = getOnUiThread( 185e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal () -> new RemoteViewsAdapter(mContext, new DistinctIntent(), mCallback, false)); 186e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 187e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal ViewsFactory factory = new ViewsFactory(1); 188e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal factory.loadingView.set(createViews("loading")); 189e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal mContext.sendConnect(factory); 190e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 191e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal waitOnHandler(mContext.handler.get()); 192e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal waitOnHandler(mMainHandler); 193e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal verify(mCallback, times(1)).onRemoteAdapterConnected(); 194e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal assertEquals((Integer) 1, getOnUiThread(adapter::getCount)); 195e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 196e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal // Unbind the service 197e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal ServiceConnection conn = mContext.conn.get(); 198e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal getOnHandler(mContext.handler.get(), () -> { 199e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal conn.onServiceDisconnected(null); 200e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return null; 201e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal }); 202e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 203e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal // Returned view contains the loading text 204e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal View view = getOnUiThread(() -> adapter.getView(0, null, new FrameLayout(mContext))); 205e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal ArrayList<View> search = new ArrayList<>(); 206e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal view.findViewsWithText(search, "loading", View.FIND_VIEWS_WITH_TEXT); 207e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal assertEquals(1, search.size()); 208e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 209e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal // Unbind is not scheduled 210e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal assertFalse(isUnboundOrScheduled()); 211e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 212e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal mContext.sendConnect(factory); 213e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal waitOnHandler(mContext.handler.get()); 214e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal waitOnHandler(mMainHandler); 215e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal verify(mCallback, times(2)).onRemoteAdapterConnected(); 216e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 217e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 218e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal private RemoteViews createViews(String text) { 219e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal RemoteViews views = new RemoteViews(mContext.getPackageName(), R.layout.remote_views_text); 220e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal views.setTextViewText(R.id.text, text); 221e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return views; 222e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 223e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 224e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal private <T> T getOnUiThread(Supplier<T> supplier) throws Throwable { 225e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return getOnHandler(mMainHandler, supplier); 226e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 227e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 228e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal private boolean isUnboundOrScheduled() throws Throwable { 229e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal Handler handler = mContext.handler.get(); 230e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return getOnHandler(handler, () -> mContext.boundCount == 0 231e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal || handler.hasMessages(RemoteViewsAdapter.MSG_UNBIND_SERVICE)); 232e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 233e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 234e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal private static <T> T getOnHandler(Handler handler, Supplier<T> supplier) throws Throwable { 235e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal LockedValue<T> result = new LockedValue<>(); 236e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal handler.post(() -> result.set(supplier.get())); 237e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return result.get(); 238e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 239e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 240e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal private class TestContext extends ContextWrapper { 241e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 242e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public final LockedValue<ServiceConnection> conn = new LockedValue<>(); 243e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public final LockedValue<Handler> handler = new LockedValue<>(); 244e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public int boundCount; 245e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 246e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal TestContext() { 247e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal super(InstrumentationRegistry.getContext()); 248e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 249e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 250e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Override 251e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public void unbindService(ServiceConnection conn) { 252e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal boundCount--; 253e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 254e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 255e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Override 256e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public Object getSystemService(String name) { 257e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal if (Context.APPWIDGET_SERVICE.equals(name)) { 258e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return mAppWidgetManager; 259e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 260e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return super.getSystemService(name); 261e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 262e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 263e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Override 264e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public IServiceConnection getServiceDispatcher( 265e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal ServiceConnection conn, Handler handler, int flags) { 266e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal this.conn.set(conn); 267e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal this.handler.set(handler); 268e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal boundCount++; 269e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return mIServiceConnection; 270e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 271e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 272e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Override 273e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public Context getApplicationContext() { 274e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return this; 275e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 276e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 277e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public void sendConnect(ViewsFactory factory) throws Exception { 278e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal ServiceConnection connection = conn.get(); 279e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal handler.get().post(() -> connection.onServiceConnected(null, factory.asBinder())); 280e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 281e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 282e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 283e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal private static void waitOnHandler(Handler handler) throws Exception { 284e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal CountDownLatch latch = new CountDownLatch(1); 285e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal handler.post(() -> latch.countDown()); 286e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal latch.await(20, TimeUnit.SECONDS); 287e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 288e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 289e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal private static class ViewsFactory extends IRemoteViewsFactory.Stub { 290e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 291e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public LockedValue<RemoteViews> loadingView = new LockedValue<>(); 292e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public LockedValue<RemoteViews>[] views; 293e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 294e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal private int mCount; 295e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 296e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal ViewsFactory(int count) { 297e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal mCount = count; 298e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal views = new LockedValue[count]; 299e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal for (int i = 0; i < count; i++) { 300e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal views[i] = new LockedValue<>(); 301e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 302e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 303e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 304e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Override 305e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public void onDataSetChanged() {} 306e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 307e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Override 308e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public void onDataSetChangedAsync() { } 309e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 310e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Override 311e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public void onDestroy(Intent intent) { } 312e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 313e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Override 314e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public int getCount() throws RemoteException { 315e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return mCount; 316e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 317e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 318e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Override 319e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public RemoteViews getViewAt(int position) throws RemoteException { 320e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal try { 321e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return views[position].get(); 322e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } catch (Exception e) { 323e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal throw new RemoteException(e.getMessage()); 324e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 325e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 326e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 327e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Override 328e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public RemoteViews getLoadingView() throws RemoteException { 329e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal try { 330e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return loadingView.get(); 331e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } catch (Exception e) { 332e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal throw new RemoteException(e.getMessage()); 333e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 334e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 335e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 336e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Override 337e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public int getViewTypeCount() { 338e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return 1; 339e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 340e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 341e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Override 342e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public long getItemId(int position) { 343e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return position; 344e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 345e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 346e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Override 347e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public boolean hasStableIds() { 348e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return false; 349e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 350e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 351e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Override 352e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public boolean isCreated() { 353e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return false; 354e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 355e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 356e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 357e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal private static class DistinctIntent extends Intent { 358e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 359e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal @Override 360e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public boolean filterEquals(Intent other) { 361e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return false; 362e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 363e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 364e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 365e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal private static class LockedValue<T> { 366e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 367e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal private final CountDownLatch mLatch = new CountDownLatch(1); 368e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal private T mValue; 369e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 370e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public void set(T value) { 371e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal mValue = value; 372e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal mLatch.countDown(); 373e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 374e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal 375e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal public T get() throws Exception { 376e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal mLatch.await(10, TimeUnit.SECONDS); 377e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal return mValue; 378e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 379e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal } 380e1273ebbb7d0d208d0bb0304ccefc5659633068cSunny Goyal} 381