mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-27 23:36:47 +00:00
Merge "Removing test class TaplViewInflationDuringSwipeUp" into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
d37d4d8b7d
@@ -1,288 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 com.android.quickstep;
|
||||
|
||||
import static androidx.test.InstrumentationRegistry.getContext;
|
||||
import static androidx.test.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID;
|
||||
import static com.android.launcher3.testcomponent.TestCommandReceiver.EXTRA_VALUE;
|
||||
import static com.android.launcher3.testcomponent.TestCommandReceiver.SET_LIST_VIEW_SERVICE_BINDER;
|
||||
import static com.android.launcher3.util.WidgetUtils.createWidgetInfo;
|
||||
import static com.android.quickstep.NavigationModeSwitchRule.Mode.ZERO_BUTTON;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.filters.Suppress;
|
||||
import androidx.test.uiautomator.By;
|
||||
import androidx.test.uiautomator.UiDevice;
|
||||
import androidx.test.uiautomator.Until;
|
||||
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherModel;
|
||||
import com.android.launcher3.celllayout.FavoriteItemsTransaction;
|
||||
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
|
||||
import com.android.launcher3.tapl.LaunchedAppState;
|
||||
import com.android.launcher3.testcomponent.ListViewService;
|
||||
import com.android.launcher3.testcomponent.ListViewService.SimpleViewsFactory;
|
||||
import com.android.launcher3.testcomponent.TestCommandReceiver;
|
||||
import com.android.launcher3.ui.TestViewHelpers;
|
||||
import com.android.launcher3.util.Executors;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
|
||||
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.IntConsumer;
|
||||
|
||||
/**
|
||||
* Test to verify view inflation does not happen during swipe up.
|
||||
* To verify view inflation, we setup a stub ViewConfiguration and check if any call to that class
|
||||
* does from a View.init method or not.
|
||||
*
|
||||
* Alternative approaches considered:
|
||||
* Overriding LayoutInflater: This does not cover views initialized
|
||||
* directly (ex: new LinearLayout)
|
||||
* Using ExtendedMockito: Mocking static methods from platform classes (loaded in zygote) makes
|
||||
* the main thread extremely slow and untestable
|
||||
*/
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class TaplViewInflationDuringSwipeUp extends AbstractQuickStepTest {
|
||||
|
||||
private SparseArray<ViewConfiguration> mConfigMap;
|
||||
private InitTracker mInitTracker;
|
||||
private LauncherModel mModel;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
// Workaround for b/142351228, when there are no activities, the system may not destroy the
|
||||
// activity correctly for activities under instrumentation, which can leave two concurrent
|
||||
// activities, which changes the order in which the activities are cleaned up (overlapping
|
||||
// stop and start) leading to all sort of issues. To workaround this, ensure that the test
|
||||
// is started only after starting another app.
|
||||
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
|
||||
|
||||
super.setUp();
|
||||
|
||||
mModel = LauncherAppState.getInstance(mTargetContext).getModel();
|
||||
Executors.MODEL_EXECUTOR.submit(mModel.getModelDbController()::createEmptyDB).get();
|
||||
|
||||
// Get static configuration map
|
||||
Field field = ViewConfiguration.class.getDeclaredField("sConfigurations");
|
||||
field.setAccessible(true);
|
||||
mConfigMap = (SparseArray<ViewConfiguration>) field.get(null);
|
||||
|
||||
mInitTracker = new InitTracker();
|
||||
}
|
||||
|
||||
@Test
|
||||
@NavigationModeSwitch(mode = ZERO_BUTTON)
|
||||
@Suppress // until b/190618549 is fixed
|
||||
public void testSwipeUpFromApp() throws Exception {
|
||||
try {
|
||||
// Go to overview once so that all views are initialized and cached
|
||||
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
|
||||
mLauncher.getLaunchedAppState().switchToOverview().dismissAllTasks();
|
||||
|
||||
// Track view creations
|
||||
mInitTracker.startTracking();
|
||||
|
||||
startTestActivity(2);
|
||||
mLauncher.getLaunchedAppState().switchToOverview();
|
||||
|
||||
assertEquals("Views inflated during swipe up", 0, mInitTracker.viewInitCount);
|
||||
} finally {
|
||||
mConfigMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@NavigationModeSwitch(mode = ZERO_BUTTON)
|
||||
@Suppress // until b/190729479 is fixed
|
||||
public void testSwipeUpFromApp_widget_update() {
|
||||
String stubText = "Some random stub text";
|
||||
|
||||
executeSwipeUpTestWithWidget(
|
||||
widgetId -> { },
|
||||
widgetId -> AppWidgetManager.getInstance(getContext())
|
||||
.updateAppWidget(widgetId, createMainWidgetViews(stubText)),
|
||||
stubText);
|
||||
}
|
||||
|
||||
@Test
|
||||
@NavigationModeSwitch(mode = ZERO_BUTTON)
|
||||
@Suppress // until b/190729479 is fixed
|
||||
public void testSwipeUp_with_list_widgets() {
|
||||
SimpleViewsFactory viewFactory = new SimpleViewsFactory();
|
||||
viewFactory.viewCount = 1;
|
||||
Bundle args = new Bundle();
|
||||
args.putBinder(EXTRA_VALUE, viewFactory.toBinder());
|
||||
TestCommandReceiver.callCommand(SET_LIST_VIEW_SERVICE_BINDER, null, args);
|
||||
|
||||
try {
|
||||
executeSwipeUpTestWithWidget(
|
||||
widgetId -> {
|
||||
// Initialize widget
|
||||
RemoteViews views = createMainWidgetViews("List widget title");
|
||||
views.setRemoteAdapter(android.R.id.list,
|
||||
new Intent(getContext(), ListViewService.class));
|
||||
AppWidgetManager.getInstance(getContext()).updateAppWidget(widgetId, views);
|
||||
verifyWidget(viewFactory.getLabel(0));
|
||||
},
|
||||
widgetId -> {
|
||||
// Update widget
|
||||
viewFactory.viewCount = 2;
|
||||
AppWidgetManager.getInstance(getContext())
|
||||
.notifyAppWidgetViewDataChanged(widgetId, android.R.id.list);
|
||||
},
|
||||
viewFactory.getLabel(1)
|
||||
);
|
||||
} finally {
|
||||
TestCommandReceiver.callCommand(SET_LIST_VIEW_SERVICE_BINDER, null, new Bundle());
|
||||
}
|
||||
}
|
||||
|
||||
private void executeSwipeUpTestWithWidget(IntConsumer widgetIdCreationCallback,
|
||||
IntConsumer updateBeforeSwipeUp, String finalWidgetText) {
|
||||
try {
|
||||
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(false);
|
||||
|
||||
// Make sure the widget is big enough to show a list of items
|
||||
info.minSpanX = 2;
|
||||
info.minSpanY = 2;
|
||||
info.spanX = 2;
|
||||
info.spanY = 2;
|
||||
AtomicInteger widgetId = new AtomicInteger();
|
||||
|
||||
commitTransactionAndLoadHome(new FavoriteItemsTransaction(mTargetContext)
|
||||
.addItem(() -> {
|
||||
LauncherAppWidgetInfo item = createWidgetInfo(info, mTargetContext, true);
|
||||
item.screenId = FIRST_SCREEN_ID;
|
||||
widgetId.set(item.appWidgetId);
|
||||
return item;
|
||||
}));
|
||||
|
||||
assertTrue("Widget is not present",
|
||||
mLauncher.goHome().tryGetWidget(info.label, DEFAULT_UI_TIMEOUT) != null);
|
||||
|
||||
// Verify widget id
|
||||
widgetIdCreationCallback.accept(widgetId.get());
|
||||
|
||||
// Go to overview once so that all views are initialized and cached
|
||||
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
|
||||
mLauncher.getLaunchedAppState().switchToOverview().dismissAllTasks();
|
||||
|
||||
// Track view creations
|
||||
mInitTracker.startTracking();
|
||||
|
||||
startTestActivity(2);
|
||||
LaunchedAppState launchedAppState = mLauncher.getLaunchedAppState();
|
||||
|
||||
// Update widget
|
||||
updateBeforeSwipeUp.accept(widgetId.get());
|
||||
|
||||
launchedAppState.switchToOverview();
|
||||
assertEquals("Views inflated during swipe up", 0, mInitTracker.viewInitCount);
|
||||
|
||||
// Widget is updated when going home
|
||||
mInitTracker.disableLog();
|
||||
mLauncher.goHome();
|
||||
verifyWidget(finalWidgetText);
|
||||
assertNotEquals(1, mInitTracker.viewInitCount);
|
||||
} finally {
|
||||
mConfigMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyWidget(String text) {
|
||||
assertNotNull("Widget not updated",
|
||||
UiDevice.getInstance(getInstrumentation())
|
||||
.wait(Until.findObject(By.text(text)), DEFAULT_UI_TIMEOUT));
|
||||
}
|
||||
|
||||
private RemoteViews createMainWidgetViews(String title) {
|
||||
Context c = getContext();
|
||||
int layoutId = c.getResources().getIdentifier(
|
||||
"test_layout_widget_list", "layout", c.getPackageName());
|
||||
RemoteViews views = new RemoteViews(c.getPackageName(), layoutId);
|
||||
views.setTextViewText(android.R.id.text1, title);
|
||||
return views;
|
||||
}
|
||||
|
||||
private class InitTracker implements Answer {
|
||||
|
||||
public int viewInitCount = 0;
|
||||
|
||||
public boolean log = true;
|
||||
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||
Exception ex = new Exception();
|
||||
|
||||
boolean found = false;
|
||||
for (StackTraceElement ste : ex.getStackTrace()) {
|
||||
if ("<init>".equals(ste.getMethodName())
|
||||
&& View.class.getName().equals(ste.getClassName())) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
viewInitCount++;
|
||||
if (log) {
|
||||
Log.d("InitTracker", "New view inflated", ex);
|
||||
}
|
||||
|
||||
}
|
||||
return invocation.callRealMethod();
|
||||
}
|
||||
|
||||
public void disableLog() {
|
||||
log = false;
|
||||
}
|
||||
|
||||
public void startTracking() {
|
||||
ViewConfiguration vc = ViewConfiguration.get(mTargetContext);
|
||||
ViewConfiguration spyVC = spy(vc);
|
||||
mConfigMap.put(mConfigMap.keyAt(mConfigMap.indexOfValue(vc)), spyVC);
|
||||
doAnswer(this).when(spyVC).getScaledTouchSlop();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user