9925bbd147
Revert "Removing unused surface transaction wrappers" Revert submission 19933596-tcompat Reason for revert: b/246899728 Reverted Changes: I31123dff7:Using Transaction directly instead of building sur... I2e2526d21:Removing unused surface transaction wrappers Change-Id: I63d1d8bb723b7bd05d345fb21a67f88e5fb36bc1
227 lines
9.9 KiB
Java
227 lines
9.9 KiB
Java
/*
|
|
* Copyright (C) 2021 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.launcher3.model;
|
|
|
|
import static android.os.Process.myUserHandle;
|
|
|
|
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
|
|
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
|
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
|
import static com.android.launcher3.util.WidgetUtils.createAppWidgetProviderInfo;
|
|
|
|
import static com.google.common.truth.Truth.assertThat;
|
|
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
import static org.mockito.ArgumentMatchers.eq;
|
|
import static org.mockito.Mockito.doAnswer;
|
|
import static org.mockito.Mockito.doReturn;
|
|
|
|
import android.app.prediction.AppTarget;
|
|
import android.app.prediction.AppTargetId;
|
|
import android.appwidget.AppWidgetManager;
|
|
import android.appwidget.AppWidgetProviderInfo;
|
|
import android.content.ComponentName;
|
|
import android.os.UserHandle;
|
|
import android.text.TextUtils;
|
|
import android.util.Log;
|
|
|
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|
import androidx.test.filters.SmallTest;
|
|
|
|
import com.android.launcher3.LauncherAppState;
|
|
import com.android.launcher3.config.FeatureFlags;
|
|
import com.android.launcher3.icons.ComponentWithLabel;
|
|
import com.android.launcher3.icons.IconCache;
|
|
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
|
|
import com.android.launcher3.model.QuickstepModelDelegate.PredictorState;
|
|
import com.android.launcher3.util.LauncherModelHelper;
|
|
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
|
|
import com.android.launcher3.widget.PendingAddWidgetInfo;
|
|
|
|
import org.junit.After;
|
|
import org.junit.Before;
|
|
import org.junit.Test;
|
|
import org.junit.runner.RunWith;
|
|
import org.mockito.Mock;
|
|
import org.mockito.MockitoAnnotations;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
import java.util.stream.Collectors;
|
|
|
|
@SmallTest
|
|
@RunWith(AndroidJUnit4.class)
|
|
public final class WidgetsPredicationUpdateTaskTest {
|
|
|
|
private AppWidgetProviderInfo mApp1Provider1;
|
|
private AppWidgetProviderInfo mApp1Provider2;
|
|
private AppWidgetProviderInfo mApp2Provider1;
|
|
private AppWidgetProviderInfo mApp4Provider1;
|
|
private AppWidgetProviderInfo mApp4Provider2;
|
|
private AppWidgetProviderInfo mApp5Provider1;
|
|
private List<AppWidgetProviderInfo> allWidgets;
|
|
|
|
private FakeBgDataModelCallback mCallback = new FakeBgDataModelCallback();
|
|
private LauncherModelHelper mModelHelper;
|
|
private UserHandle mUserHandle;
|
|
|
|
@Mock
|
|
private IconCache mIconCache;
|
|
|
|
@Before
|
|
public void setup() throws Exception {
|
|
mModelHelper = new LauncherModelHelper();
|
|
MockitoAnnotations.initMocks(this);
|
|
doAnswer(invocation -> {
|
|
ComponentWithLabel componentWithLabel = invocation.getArgument(0);
|
|
return componentWithLabel.getComponent().getShortClassName();
|
|
}).when(mIconCache).getTitleNoCache(any());
|
|
|
|
mUserHandle = myUserHandle();
|
|
mApp1Provider1 = createAppWidgetProviderInfo(
|
|
ComponentName.createRelative("app1", "provider1"));
|
|
mApp1Provider2 = createAppWidgetProviderInfo(
|
|
ComponentName.createRelative("app1", "provider2"));
|
|
mApp2Provider1 = createAppWidgetProviderInfo(
|
|
ComponentName.createRelative("app2", "provider1"));
|
|
mApp4Provider1 = createAppWidgetProviderInfo(
|
|
ComponentName.createRelative("app4", "provider1"));
|
|
mApp4Provider2 = createAppWidgetProviderInfo(
|
|
ComponentName.createRelative("app4", ".provider2"));
|
|
mApp5Provider1 = createAppWidgetProviderInfo(
|
|
ComponentName.createRelative("app5", "provider1"));
|
|
allWidgets = Arrays.asList(mApp1Provider1, mApp1Provider2, mApp2Provider1,
|
|
mApp4Provider1, mApp4Provider2, mApp5Provider1);
|
|
|
|
AppWidgetManager manager = mModelHelper.sandboxContext.spyService(AppWidgetManager.class);
|
|
doReturn(allWidgets).when(manager).getInstalledProviders();
|
|
doReturn(allWidgets).when(manager).getInstalledProvidersForProfile(eq(myUserHandle()));
|
|
doAnswer(i -> {
|
|
String pkg = i.getArgument(0);
|
|
Log.e("Hello", "Getting v " + pkg);
|
|
return TextUtils.isEmpty(pkg) ? allWidgets : allWidgets.stream()
|
|
.filter(a -> pkg.equals(a.provider.getPackageName()))
|
|
.collect(Collectors.toList());
|
|
}).when(manager).getInstalledProvidersForPackage(any(), eq(myUserHandle()));
|
|
|
|
// 2 widgets, app4/provider1 & app5/provider1, have already been added to the workspace.
|
|
mModelHelper.initializeData("widgets_predication_update_task_data");
|
|
|
|
MAIN_EXECUTOR.submit(() -> mModelHelper.getModel().addCallbacks(mCallback)).get();
|
|
MODEL_EXECUTOR.post(() -> mModelHelper.getBgDataModel().widgetsModel.update(
|
|
LauncherAppState.getInstance(mModelHelper.sandboxContext),
|
|
/* packageUser= */ null));
|
|
|
|
MODEL_EXECUTOR.submit(() -> { }).get();
|
|
MAIN_EXECUTOR.submit(() -> { }).get();
|
|
}
|
|
|
|
@After
|
|
public void tearDown() {
|
|
mModelHelper.destroy();
|
|
}
|
|
|
|
@Test
|
|
public void widgetsRecommendationRan_shouldOnlyReturnNotAddedWidgetsInAppPredictionOrder()
|
|
throws Exception {
|
|
// WHEN newPredicationTask is executed with app predication of 5 apps.
|
|
AppTarget app1 = new AppTarget(new AppTargetId("app1"), "app1", "className",
|
|
mUserHandle);
|
|
AppTarget app2 = new AppTarget(new AppTargetId("app2"), "app2", "className",
|
|
mUserHandle);
|
|
AppTarget app3 = new AppTarget(new AppTargetId("app3"), "app3", "className",
|
|
mUserHandle);
|
|
AppTarget app4 = new AppTarget(new AppTargetId("app4"), "app4", "className",
|
|
mUserHandle);
|
|
AppTarget app5 = new AppTarget(new AppTargetId("app5"), "app5", "className",
|
|
mUserHandle);
|
|
mModelHelper.executeTaskForTest(
|
|
newWidgetsPredicationTask(List.of(app5, app3, app2, app4, app1)))
|
|
.forEach(Runnable::run);
|
|
|
|
// THEN only 3 widgets are returned because
|
|
// 1. app5/provider1 & app4/provider1 have already been added to workspace. They are
|
|
// excluded from the result.
|
|
// 2. app3 doesn't have a widget.
|
|
// 3. only 1 widget is picked from app1 because we only want to promote one widget per app.
|
|
List<PendingAddWidgetInfo> recommendedWidgets = mCallback.mRecommendedWidgets.items
|
|
.stream()
|
|
.map(itemInfo -> (PendingAddWidgetInfo) itemInfo)
|
|
.collect(Collectors.toList());
|
|
assertThat(recommendedWidgets).hasSize(3);
|
|
assertWidgetInfo(recommendedWidgets.get(0).info, mApp2Provider1);
|
|
assertWidgetInfo(recommendedWidgets.get(1).info, mApp4Provider2);
|
|
assertWidgetInfo(recommendedWidgets.get(2).info, mApp1Provider1);
|
|
}
|
|
|
|
@Test
|
|
public void widgetsRecommendationRan_localFilterDisabled_shouldReturnWidgetsInPredicationOrder()
|
|
throws Exception {
|
|
if (FeatureFlags.ENABLE_LOCAL_RECOMMENDED_WIDGETS_FILTER.get()) {
|
|
return;
|
|
}
|
|
|
|
// WHEN newPredicationTask is executed with 5 predicated widgets.
|
|
AppTarget widget1 = new AppTarget(new AppTargetId("app1"), "app1", "provider1",
|
|
mUserHandle);
|
|
AppTarget widget2 = new AppTarget(new AppTargetId("app1"), "app1", "provider2",
|
|
mUserHandle);
|
|
// Not installed app
|
|
AppTarget widget3 = new AppTarget(new AppTargetId("app2"), "app3", "provider1",
|
|
mUserHandle);
|
|
// Not installed widget
|
|
AppTarget widget4 = new AppTarget(new AppTargetId("app4"), "app4", "provider3",
|
|
mUserHandle);
|
|
AppTarget widget5 = new AppTarget(new AppTargetId("app5"), "app5", "provider1",
|
|
mUserHandle);
|
|
mModelHelper.executeTaskForTest(
|
|
newWidgetsPredicationTask(List.of(widget5, widget3, widget2, widget4, widget1)))
|
|
.forEach(Runnable::run);
|
|
|
|
// THEN only 3 widgets are returned because the launcher only filters out non-exist widgets.
|
|
List<PendingAddWidgetInfo> recommendedWidgets = mCallback.mRecommendedWidgets.items
|
|
.stream()
|
|
.map(itemInfo -> (PendingAddWidgetInfo) itemInfo)
|
|
.collect(Collectors.toList());
|
|
assertThat(recommendedWidgets).hasSize(3);
|
|
assertWidgetInfo(recommendedWidgets.get(0).info, mApp5Provider1);
|
|
assertWidgetInfo(recommendedWidgets.get(1).info, mApp1Provider2);
|
|
assertWidgetInfo(recommendedWidgets.get(2).info, mApp1Provider1);
|
|
}
|
|
|
|
private void assertWidgetInfo(
|
|
LauncherAppWidgetProviderInfo actual, AppWidgetProviderInfo expected) {
|
|
assertThat(actual.provider).isEqualTo(expected.provider);
|
|
assertThat(actual.getUser()).isEqualTo(expected.getProfile());
|
|
}
|
|
|
|
private WidgetsPredictionUpdateTask newWidgetsPredicationTask(List<AppTarget> appTargets) {
|
|
return new WidgetsPredictionUpdateTask(
|
|
new PredictorState(CONTAINER_WIDGETS_PREDICTION, "test_widgets_prediction"),
|
|
appTargets);
|
|
}
|
|
|
|
private final class FakeBgDataModelCallback implements BgDataModel.Callbacks {
|
|
|
|
private FixedContainerItems mRecommendedWidgets = null;
|
|
|
|
@Override
|
|
public void bindExtraContainerItems(FixedContainerItems item) {
|
|
mRecommendedWidgets = item;
|
|
}
|
|
}
|
|
}
|