Merge "Revert "Move widget picker tests to Robolectric"" into main
This commit is contained in:
@@ -15,12 +15,15 @@
|
||||
*/
|
||||
package com.android.launcher3.util;
|
||||
|
||||
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.Process;
|
||||
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
|
||||
@@ -84,10 +87,10 @@ public class WidgetUtils {
|
||||
* Creates a {@link AppWidgetProviderInfo} for the provided component name
|
||||
*/
|
||||
public static AppWidgetProviderInfo createAppWidgetProviderInfo(ComponentName cn) {
|
||||
ActivityInfo activityInfo = new ActivityInfo();
|
||||
activityInfo.applicationInfo = new ApplicationInfo();
|
||||
AppWidgetProviderInfo info = new AppWidgetProviderInfo();
|
||||
info.providerInfo = activityInfo;
|
||||
AppWidgetProviderInfo info = AppWidgetManager.getInstance(getApplicationContext())
|
||||
.getInstalledProvidersForPackage(
|
||||
getInstrumentation().getContext().getPackageName(), Process.myUserHandle())
|
||||
.get(0);
|
||||
info.provider = cn;
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.widget.picker
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import com.android.launcher3.util.ActivityContextWrapper
|
||||
import com.android.launcher3.widget.WidgetImageView
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.spy
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@MediumTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class WidgetImageViewTest {
|
||||
private lateinit var context: Context
|
||||
private lateinit var widgetImageView: WidgetImageView
|
||||
|
||||
@Mock private lateinit var testDrawable: Drawable
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
context = ActivityContextWrapper(ApplicationProvider.getApplicationContext())
|
||||
widgetImageView = spy(WidgetImageView(context))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getBitmapBounds_aspectRatioLargerThanView_scaledByWidth() {
|
||||
// view - 100 x 100
|
||||
whenever(widgetImageView.width).thenReturn(100)
|
||||
whenever(widgetImageView.height).thenReturn(100)
|
||||
// bitmap - 200 x 100
|
||||
whenever(testDrawable.intrinsicWidth).thenReturn(200)
|
||||
whenever(testDrawable.intrinsicHeight).thenReturn(100)
|
||||
|
||||
widgetImageView.drawable = testDrawable
|
||||
val bitmapBounds = widgetImageView.bitmapBounds
|
||||
|
||||
// new scaled width of bitmap is = 100, and height is scaled to 1/2 = 50
|
||||
assertThat(bitmapBounds).isEqualTo(Rect(0, 25, 100, 75))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getBitmapBounds_aspectRatioSmallerThanView_scaledByHeight() {
|
||||
// view - 100 x 100
|
||||
whenever(widgetImageView.width).thenReturn(100)
|
||||
whenever(widgetImageView.height).thenReturn(100)
|
||||
// bitmap - 100 x 200
|
||||
whenever(testDrawable.intrinsicWidth).thenReturn(100)
|
||||
whenever(testDrawable.intrinsicHeight).thenReturn(200)
|
||||
widgetImageView.drawable = testDrawable
|
||||
|
||||
val bitmapBounds = widgetImageView.bitmapBounds
|
||||
|
||||
// new scaled height of bitmap is = 100, and width is scaled to 1/2 = 50
|
||||
assertThat(bitmapBounds).isEqualTo(Rect(25, 0, 75, 100))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getBitmapBounds_noScale_returnsOriginalDrawableBounds() {
|
||||
// view - 200 x 100
|
||||
whenever(widgetImageView.width).thenReturn(200)
|
||||
whenever(widgetImageView.height).thenReturn(100)
|
||||
// bitmap - 200 x 100
|
||||
whenever(testDrawable.intrinsicWidth).thenReturn(200)
|
||||
whenever(testDrawable.intrinsicHeight).thenReturn(100)
|
||||
|
||||
widgetImageView.drawable = testDrawable
|
||||
val bitmapBounds = widgetImageView.bitmapBounds
|
||||
|
||||
// no scaling
|
||||
assertThat(bitmapBounds).isEqualTo(Rect(0, 0, 200, 100))
|
||||
}
|
||||
}
|
||||
-166
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.widget.picker;
|
||||
|
||||
import static android.content.pm.ApplicationInfo.CATEGORY_AUDIO;
|
||||
import static android.content.pm.ApplicationInfo.CATEGORY_IMAGE;
|
||||
import static android.content.pm.ApplicationInfo.CATEGORY_NEWS;
|
||||
import static android.content.pm.ApplicationInfo.CATEGORY_PRODUCTIVITY;
|
||||
import static android.content.pm.ApplicationInfo.CATEGORY_SOCIAL;
|
||||
import static android.content.pm.ApplicationInfo.CATEGORY_UNDEFINED;
|
||||
import static android.content.pm.ApplicationInfo.CATEGORY_VIDEO;
|
||||
import static android.content.pm.ApplicationInfo.FLAG_INSTALLED;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
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.when;
|
||||
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.os.Process;
|
||||
|
||||
import androidx.test.core.content.pm.ApplicationInfoBuilder;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.model.WidgetItem;
|
||||
import com.android.launcher3.util.Executors;
|
||||
import com.android.launcher3.util.WidgetUtils;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class WidgetRecommendationCategoryProviderTest {
|
||||
private static final String TEST_PACKAGE = "com.foo.test";
|
||||
private static final String TEST_APP_NAME = "foo";
|
||||
private static final WidgetRecommendationCategory PRODUCTIVITY =
|
||||
new WidgetRecommendationCategory(
|
||||
R.string.productivity_widget_recommendation_category_label,
|
||||
/*order=*/0);
|
||||
private static final WidgetRecommendationCategory NEWS =
|
||||
new WidgetRecommendationCategory(
|
||||
R.string.news_widget_recommendation_category_label, /*order=*/1);
|
||||
private static final WidgetRecommendationCategory SUGGESTED_FOR_YOU =
|
||||
new WidgetRecommendationCategory(
|
||||
R.string.others_widget_recommendation_category_label, /*order=*/2);
|
||||
private static final WidgetRecommendationCategory SOCIAL =
|
||||
new WidgetRecommendationCategory(
|
||||
R.string.social_widget_recommendation_category_label,
|
||||
/*order=*/3);
|
||||
private static final WidgetRecommendationCategory ENTERTAINMENT =
|
||||
new WidgetRecommendationCategory(
|
||||
R.string.entertainment_widget_recommendation_category_label,
|
||||
/*order=*/4);
|
||||
|
||||
private final ApplicationInfo mTestAppInfo = ApplicationInfoBuilder.newBuilder().setPackageName(
|
||||
TEST_PACKAGE).setName(TEST_APP_NAME).build();
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private IconCache mIconCache;
|
||||
|
||||
private WidgetItem mTestWidgetItem;
|
||||
@Mock
|
||||
private LauncherApps mLauncherApps;
|
||||
private InvariantDeviceProfile mTestProfile;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = new ContextWrapper(getInstrumentation().getTargetContext()) {
|
||||
@Override
|
||||
public Object getSystemService(String name) {
|
||||
return LAUNCHER_APPS_SERVICE.equals(name) ? mLauncherApps : super.getSystemService(
|
||||
name);
|
||||
}
|
||||
};
|
||||
mTestAppInfo.flags = FLAG_INSTALLED;
|
||||
mTestProfile = new InvariantDeviceProfile();
|
||||
mTestProfile.numRows = 5;
|
||||
mTestProfile.numColumns = 5;
|
||||
createTestWidgetItem();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWidgetRecommendationCategory_returnsMappedCategory() throws Exception {
|
||||
ImmutableMap<Integer, WidgetRecommendationCategory> testCategories = ImmutableMap.of(
|
||||
CATEGORY_PRODUCTIVITY, PRODUCTIVITY,
|
||||
CATEGORY_NEWS, NEWS,
|
||||
CATEGORY_SOCIAL, SOCIAL,
|
||||
CATEGORY_AUDIO, ENTERTAINMENT,
|
||||
CATEGORY_IMAGE, ENTERTAINMENT,
|
||||
CATEGORY_VIDEO, ENTERTAINMENT,
|
||||
CATEGORY_UNDEFINED, SUGGESTED_FOR_YOU);
|
||||
|
||||
for (Map.Entry<Integer, WidgetRecommendationCategory> testCategory :
|
||||
testCategories.entrySet()) {
|
||||
|
||||
mTestAppInfo.category = testCategory.getKey();
|
||||
when(mLauncherApps.getApplicationInfo(/*packageName=*/ eq(TEST_PACKAGE),
|
||||
/*flags=*/ eq(0),
|
||||
/*user=*/ eq(Process.myUserHandle())))
|
||||
.thenReturn(mTestAppInfo);
|
||||
|
||||
WidgetRecommendationCategory category = Executors.MODEL_EXECUTOR.submit(() ->
|
||||
new WidgetRecommendationCategoryProvider().getWidgetRecommendationCategory(
|
||||
mContext,
|
||||
mTestWidgetItem)).get();
|
||||
|
||||
assertThat(category).isEqualTo(testCategory.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void createTestWidgetItem() {
|
||||
String widgetLabel = "Foo Widget";
|
||||
String widgetClassName = ".mWidget";
|
||||
|
||||
doAnswer(invocation -> widgetLabel).when(mIconCache).getTitleNoCache(any());
|
||||
|
||||
AppWidgetProviderInfo providerInfo = WidgetUtils.createAppWidgetProviderInfo(ComponentName
|
||||
.createRelative(TEST_PACKAGE, widgetClassName));
|
||||
|
||||
LauncherAppWidgetProviderInfo launcherAppWidgetProviderInfo =
|
||||
LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, providerInfo);
|
||||
launcherAppWidgetProviderInfo.spanX = 2;
|
||||
launcherAppWidgetProviderInfo.spanY = 2;
|
||||
launcherAppWidgetProviderInfo.label = widgetLabel;
|
||||
mTestWidgetItem = new WidgetItem(launcherAppWidgetProviderInfo, mTestProfile, mIconCache,
|
||||
mContext
|
||||
);
|
||||
}
|
||||
}
|
||||
-87
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.widget.picker;
|
||||
|
||||
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.util.ActivityContextWrapper;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class WidgetsListHeaderAccessibilityTest {
|
||||
private Context mContext;
|
||||
private LayoutInflater mLayoutInflater;
|
||||
@Mock
|
||||
private View.OnClickListener mOnClickListener;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mContext = new ActivityContextWrapper(getApplicationContext());
|
||||
mLayoutInflater = LayoutInflater.from(
|
||||
new ContextThemeWrapper(mContext, R.style.WidgetContainerTheme));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singlePaneCollapsable_hasCustomAccessibilityActions() {
|
||||
WidgetsListHeader header = (WidgetsListHeader) mLayoutInflater.inflate(
|
||||
R.layout.widgets_list_row_header,
|
||||
new FrameLayout(mContext), false);
|
||||
|
||||
assertThat(header.getAccessibilityDelegate()).isNotNull();
|
||||
|
||||
header.setOnClickListener(mOnClickListener);
|
||||
header.getAccessibilityDelegate().performAccessibilityAction(header,
|
||||
AccessibilityNodeInfo.ACTION_EXPAND, null);
|
||||
header.getAccessibilityDelegate().performAccessibilityAction(header,
|
||||
AccessibilityNodeInfo.ACTION_COLLAPSE, null);
|
||||
|
||||
verify(mOnClickListener, times(2)).onClick(header);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void twoPaneNonCollapsable_noCustomAccessibilityDelegate() {
|
||||
WidgetsListHeader header = (WidgetsListHeader) mLayoutInflater.inflate(
|
||||
R.layout.widgets_list_row_header_two_pane,
|
||||
new FrameLayout(mContext), false);
|
||||
|
||||
assertThat(header.getAccessibilityDelegate()).isNull();
|
||||
}
|
||||
}
|
||||
-156
@@ -1,156 +0,0 @@
|
||||
/*
|
||||
* 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.widget.picker;
|
||||
|
||||
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
|
||||
|
||||
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.verify;
|
||||
|
||||
import static java.util.Collections.EMPTY_LIST;
|
||||
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.UserHandle;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.icons.BitmapInfo;
|
||||
import com.android.launcher3.icons.ComponentWithLabel;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.model.WidgetItem;
|
||||
import com.android.launcher3.model.data.PackageItemInfo;
|
||||
import com.android.launcher3.util.ActivityContextWrapper;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
import com.android.launcher3.util.WidgetUtils;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
|
||||
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public final class WidgetsListHeaderViewHolderBinderTest {
|
||||
private static final String TEST_PACKAGE = "com.google.test";
|
||||
private static final String APP_NAME = "Test app";
|
||||
|
||||
private Context mContext;
|
||||
private WidgetsListHeaderViewHolderBinder mViewHolderBinder;
|
||||
private InvariantDeviceProfile mTestProfile;
|
||||
|
||||
@Mock
|
||||
private IconCache mIconCache;
|
||||
@Mock
|
||||
private OnHeaderClickListener mOnHeaderClickListener;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mContext = new ActivityContextWrapper(new ContextThemeWrapper(getApplicationContext(),
|
||||
R.style.WidgetContainerTheme));
|
||||
mTestProfile = new InvariantDeviceProfile();
|
||||
mTestProfile.numRows = 5;
|
||||
mTestProfile.numColumns = 5;
|
||||
|
||||
doAnswer(invocation -> {
|
||||
ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
|
||||
return componentWithLabel.getComponent().getShortClassName();
|
||||
}).when(mIconCache).getTitleNoCache(any());
|
||||
mViewHolderBinder = new WidgetsListHeaderViewHolderBinder(
|
||||
LayoutInflater.from(mContext),
|
||||
mOnHeaderClickListener,
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindViewHolder_appWith3Widgets_shouldShowTheCorrectAppNameAndSubtitle() {
|
||||
WidgetsListHeaderHolder viewHolder = mViewHolderBinder.newViewHolder(
|
||||
new FrameLayout(mContext));
|
||||
WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
|
||||
WidgetsListHeaderEntry entry = generateSampleAppHeader(
|
||||
APP_NAME,
|
||||
TEST_PACKAGE,
|
||||
/* numOfWidgets= */ 3);
|
||||
mViewHolderBinder.bindViewHolder(viewHolder, entry, /* position= */ 0, EMPTY_LIST);
|
||||
|
||||
TextView appTitle = widgetsListHeader.findViewById(R.id.app_title);
|
||||
TextView appSubtitle = widgetsListHeader.findViewById(R.id.app_subtitle);
|
||||
assertThat(appTitle.getText()).isEqualTo(APP_NAME);
|
||||
assertThat(appSubtitle.getText()).isEqualTo("3 widgets");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindViewHolder_shouldAttachOnHeaderClickListener() {
|
||||
WidgetsListHeaderHolder viewHolder = mViewHolderBinder.newViewHolder(
|
||||
new FrameLayout(mContext));
|
||||
WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
|
||||
WidgetsListHeaderEntry entry = generateSampleAppHeader(
|
||||
APP_NAME,
|
||||
TEST_PACKAGE,
|
||||
/* numOfWidgets= */ 3);
|
||||
|
||||
mViewHolderBinder.bindViewHolder(viewHolder, entry, /* position= */ 0, EMPTY_LIST);
|
||||
widgetsListHeader.callOnClick();
|
||||
|
||||
verify(mOnHeaderClickListener).onHeaderClicked(eq(true),
|
||||
eq(PackageUserKey.fromPackageItemInfo(entry.mPkgItem)));
|
||||
}
|
||||
|
||||
private WidgetsListHeaderEntry generateSampleAppHeader(String appName, String packageName,
|
||||
int numOfWidgets) {
|
||||
PackageItemInfo appInfo = new PackageItemInfo(packageName, UserHandle.CURRENT);
|
||||
appInfo.title = appName;
|
||||
appInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
|
||||
|
||||
return WidgetsListHeaderEntry.create(appInfo,
|
||||
/* titleSectionName= */ "",
|
||||
generateWidgetItems(packageName, numOfWidgets));
|
||||
}
|
||||
|
||||
private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
|
||||
ArrayList<WidgetItem> widgetItems = new ArrayList<>();
|
||||
for (int i = 0; i < numOfWidgets; i++) {
|
||||
ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
|
||||
AppWidgetProviderInfo widgetInfo = WidgetUtils.createAppWidgetProviderInfo(cn);
|
||||
|
||||
widgetItems.add(new WidgetItem(
|
||||
LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
|
||||
mTestProfile, mIconCache, mContext));
|
||||
}
|
||||
return widgetItems;
|
||||
}
|
||||
}
|
||||
-161
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* 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.widget.picker;
|
||||
|
||||
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
|
||||
import static java.util.Collections.EMPTY_LIST;
|
||||
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.UserHandle;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View.OnLongClickListener;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TableRow;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.icons.BitmapInfo;
|
||||
import com.android.launcher3.icons.ComponentWithLabel;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.model.WidgetItem;
|
||||
import com.android.launcher3.model.data.PackageItemInfo;
|
||||
import com.android.launcher3.util.ActivityContextWrapper;
|
||||
import com.android.launcher3.util.Executors;
|
||||
import com.android.launcher3.util.WidgetUtils;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
|
||||
import com.android.launcher3.widget.WidgetCell;
|
||||
import com.android.launcher3.widget.WidgetManagerHelper;
|
||||
import com.android.launcher3.widget.model.WidgetsListContentEntry;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public final class WidgetsListTableViewHolderBinderTest {
|
||||
private static final String TEST_PACKAGE = "com.google.test";
|
||||
private static final String APP_NAME = "Test app";
|
||||
|
||||
private Context mContext;
|
||||
private WidgetsListTableViewHolderBinder mViewHolderBinder;
|
||||
private InvariantDeviceProfile mTestProfile;
|
||||
|
||||
@Mock
|
||||
private OnLongClickListener mOnLongClickListener;
|
||||
@Mock
|
||||
private OnClickListener mOnIconClickListener;
|
||||
@Mock
|
||||
private IconCache mIconCache;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = new ActivityContextWrapper(getApplicationContext());
|
||||
mTestProfile = new InvariantDeviceProfile();
|
||||
mTestProfile.numRows = 5;
|
||||
mTestProfile.numColumns = 5;
|
||||
|
||||
doAnswer(invocation -> {
|
||||
ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
|
||||
return componentWithLabel.getComponent().getShortClassName();
|
||||
}).when(mIconCache).getTitleNoCache(any());
|
||||
|
||||
mViewHolderBinder = new WidgetsListTableViewHolderBinder(
|
||||
mContext,
|
||||
LayoutInflater.from(new ContextThemeWrapper(mContext,
|
||||
com.android.launcher3.R.style.WidgetContainerTheme)),
|
||||
mOnIconClickListener,
|
||||
mOnLongClickListener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindViewHolder_appWith3Widgets_shouldHave3Widgets() throws Exception {
|
||||
WidgetsRowViewHolder viewHolder = mViewHolderBinder.newViewHolder(
|
||||
new FrameLayout(mContext));
|
||||
WidgetsListContentEntry entry = generateSampleAppWithWidgets(
|
||||
APP_NAME,
|
||||
TEST_PACKAGE,
|
||||
/* numOfWidgets= */ 3);
|
||||
mViewHolderBinder.bindViewHolder(viewHolder, entry, /* position= */ 0, EMPTY_LIST);
|
||||
Executors.MAIN_EXECUTOR.submit(() -> { }).get();
|
||||
|
||||
// THEN the table container has one row, which contains 3 widgets.
|
||||
// View: .SampleWidget0 | .SampleWidget1 | .SampleWidget2
|
||||
assertThat(viewHolder.tableContainer.getChildCount()).isEqualTo(1);
|
||||
TableRow row = (TableRow) viewHolder.tableContainer.getChildAt(0);
|
||||
assertThat(row.getChildCount()).isEqualTo(3);
|
||||
// Widget 0 label is .SampleWidget0.
|
||||
assertWidgetCellWithLabel(row.getChildAt(0), ".SampleWidget0");
|
||||
// Widget 1 label is .SampleWidget1.
|
||||
assertWidgetCellWithLabel(row.getChildAt(1), ".SampleWidget1");
|
||||
// Widget 2 label is .SampleWidget2.
|
||||
assertWidgetCellWithLabel(row.getChildAt(2), ".SampleWidget2");
|
||||
}
|
||||
|
||||
private WidgetsListContentEntry generateSampleAppWithWidgets(String appName, String packageName,
|
||||
int numOfWidgets) {
|
||||
PackageItemInfo appInfo = new PackageItemInfo(packageName, UserHandle.CURRENT);
|
||||
appInfo.title = appName;
|
||||
appInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
|
||||
|
||||
return new WidgetsListContentEntry(appInfo,
|
||||
/* titleSectionName= */ "",
|
||||
generateWidgetItems(packageName, numOfWidgets),
|
||||
Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
|
||||
WidgetManagerHelper widgetManager = new WidgetManagerHelper(mContext);
|
||||
ArrayList<WidgetItem> widgetItems = new ArrayList<>();
|
||||
for (int i = 0; i < numOfWidgets; i++) {
|
||||
ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
|
||||
AppWidgetProviderInfo widgetInfo = WidgetUtils.createAppWidgetProviderInfo(cn);
|
||||
|
||||
widgetItems.add(new WidgetItem(
|
||||
LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
|
||||
mTestProfile, mIconCache, mContext, widgetManager));
|
||||
}
|
||||
return widgetItems;
|
||||
}
|
||||
|
||||
private void assertWidgetCellWithLabel(View view, String label) {
|
||||
assertThat(view).isInstanceOf(WidgetCell.class);
|
||||
TextView widgetLabel = (TextView) view.findViewById(R.id.widget_name);
|
||||
assertThat(widgetLabel.getText()).isEqualTo(label);
|
||||
}
|
||||
}
|
||||
-262
@@ -1,262 +0,0 @@
|
||||
/*
|
||||
* 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.widget.picker.model;
|
||||
|
||||
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
|
||||
|
||||
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.Mockito.doAnswer;
|
||||
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.icons.ComponentWithLabel;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.model.WidgetItem;
|
||||
import com.android.launcher3.model.data.PackageItemInfo;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
|
||||
import com.android.launcher3.widget.model.WidgetsListContentEntry;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public final class WidgetsListContentEntryTest {
|
||||
private static final String PACKAGE_NAME = "com.android.test";
|
||||
private static final String PACKAGE_NAME_2 = "com.android.test2";
|
||||
private final PackageItemInfo mPackageItemInfo1 = new PackageItemInfo(PACKAGE_NAME,
|
||||
UserHandle.CURRENT);
|
||||
private final PackageItemInfo mPackageItemInfo2 = new PackageItemInfo(PACKAGE_NAME_2,
|
||||
UserHandle.CURRENT);
|
||||
private final ComponentName mWidget1 = ComponentName.createRelative(PACKAGE_NAME, ".mWidget1");
|
||||
private final ComponentName mWidget2 = ComponentName.createRelative(PACKAGE_NAME, ".mWidget2");
|
||||
private final ComponentName mWidget3 = ComponentName.createRelative(PACKAGE_NAME, ".mWidget3");
|
||||
private final Map<ComponentName, String> mWidgetsToLabels = new HashMap();
|
||||
|
||||
@Mock private IconCache mIconCache;
|
||||
|
||||
private InvariantDeviceProfile mTestProfile;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mWidgetsToLabels.put(mWidget1, "Cat");
|
||||
mWidgetsToLabels.put(mWidget2, "Dog");
|
||||
mWidgetsToLabels.put(mWidget3, "Bird");
|
||||
|
||||
mTestProfile = new InvariantDeviceProfile();
|
||||
mTestProfile.numRows = 5;
|
||||
mTestProfile.numColumns = 5;
|
||||
|
||||
doAnswer(invocation -> {
|
||||
ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
|
||||
return mWidgetsToLabels.get(componentWithLabel.getComponent());
|
||||
}).when(mIconCache).getTitleNoCache(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unsortedWidgets_diffLabels_shouldSortWidgetItems() {
|
||||
// GIVEN a list of widgets in unsorted order.
|
||||
// Cat 2x3
|
||||
WidgetItem widgetItem1 = createWidgetItem(mWidget1, /* spanX= */ 2, /* spanY= */ 3);
|
||||
// Dog 2x3
|
||||
WidgetItem widgetItem2 = createWidgetItem(mWidget2, /* spanX= */ 2, /* spanY= */ 3);
|
||||
// Bird 2x3
|
||||
WidgetItem widgetItem3 = createWidgetItem(mWidget3, /* spanX= */ 2, /* spanY= */ 3);
|
||||
|
||||
// WHEN creates a WidgetsListRowEntry with the unsorted widgets.
|
||||
WidgetsListContentEntry widgetsListRowEntry = new WidgetsListContentEntry(mPackageItemInfo1,
|
||||
/* titleSectionName= */ "T",
|
||||
List.of(widgetItem1, widgetItem2, widgetItem3));
|
||||
|
||||
// THEN the widgets list is sorted by their labels alphabetically: [Bird, Cat, Dog].
|
||||
assertThat(widgetsListRowEntry.mWidgets)
|
||||
.containsExactly(widgetItem3, widgetItem1, widgetItem2)
|
||||
.inOrder();
|
||||
assertThat(widgetsListRowEntry.mTitleSectionName).isEqualTo("T");
|
||||
assertThat(widgetsListRowEntry.mPkgItem).isEqualTo(mPackageItemInfo1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unsortedWidgets_sameLabels_differentSize_shouldSortWidgetItems() {
|
||||
// GIVEN a list of widgets in unsorted order.
|
||||
// Cat 3x3
|
||||
WidgetItem widgetItem1 = createWidgetItem(mWidget1, /* spanX= */ 3, /* spanY= */ 3);
|
||||
// Cat 1x2
|
||||
WidgetItem widgetItem2 = createWidgetItem(mWidget1, /* spanX= */ 1, /* spanY= */ 2);
|
||||
// Cat 2x2
|
||||
WidgetItem widgetItem3 = createWidgetItem(mWidget1, /* spanX= */ 2, /* spanY= */ 2);
|
||||
|
||||
// WHEN creates a WidgetsListRowEntry with the unsorted widgets.
|
||||
WidgetsListContentEntry widgetsListRowEntry = new WidgetsListContentEntry(mPackageItemInfo1,
|
||||
/* titleSectionName= */ "T",
|
||||
List.of(widgetItem1, widgetItem2, widgetItem3));
|
||||
|
||||
// THEN the widgets list is sorted by their gird sizes in an ascending order:
|
||||
// [1x2, 2x2, 3x3].
|
||||
assertThat(widgetsListRowEntry.mWidgets)
|
||||
.containsExactly(widgetItem2, widgetItem3, widgetItem1)
|
||||
.inOrder();
|
||||
assertThat(widgetsListRowEntry.mTitleSectionName).isEqualTo("T");
|
||||
assertThat(widgetsListRowEntry.mPkgItem).isEqualTo(mPackageItemInfo1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unsortedWidgets_hodgepodge_shouldSortWidgetItems() {
|
||||
// GIVEN a list of widgets in unsorted order.
|
||||
// Cat 3x3
|
||||
WidgetItem widgetItem1 = createWidgetItem(mWidget1, /* spanX= */ 3, /* spanY= */ 3);
|
||||
// Cat 1x2
|
||||
WidgetItem widgetItem2 = createWidgetItem(mWidget1, /* spanX= */ 1, /* spanY= */ 2);
|
||||
// Dog 2x2
|
||||
WidgetItem widgetItem3 = createWidgetItem(mWidget2, /* spanX= */ 2, /* spanY= */ 2);
|
||||
// Bird 2x2
|
||||
WidgetItem widgetItem4 = createWidgetItem(mWidget3, /* spanX= */ 2, /* spanY= */ 2);
|
||||
|
||||
// WHEN creates a WidgetsListRowEntry with the unsorted widgets.
|
||||
WidgetsListContentEntry widgetsListRowEntry = new WidgetsListContentEntry(mPackageItemInfo1,
|
||||
/* titleSectionName= */ "T",
|
||||
List.of(widgetItem1, widgetItem2, widgetItem3, widgetItem4));
|
||||
|
||||
// THEN the widgets list is first sorted by labels alphabetically. Then, for widgets with
|
||||
// same labels, they are sorted by their gird sizes in an ascending order:
|
||||
// [Bird 2x2, Cat 1x2, Cat 3x3, Dog 2x2]
|
||||
assertThat(widgetsListRowEntry.mWidgets)
|
||||
.containsExactly(widgetItem4, widgetItem2, widgetItem1, widgetItem3)
|
||||
.inOrder();
|
||||
assertThat(widgetsListRowEntry.mTitleSectionName).isEqualTo("T");
|
||||
assertThat(widgetsListRowEntry.mPkgItem).isEqualTo(mPackageItemInfo1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equals_entriesWithDifferentPackageItemInfo_returnFalse() {
|
||||
WidgetItem widgetItem1 = createWidgetItem(mWidget1, /* spanX= */ 2, /* spanY= */ 3);
|
||||
WidgetsListContentEntry widgetsListRowEntry1 = new WidgetsListContentEntry(
|
||||
mPackageItemInfo1,
|
||||
/* titleSectionName= */ "T",
|
||||
List.of(widgetItem1),
|
||||
/* maxSpanSizeInCells= */ 3);
|
||||
WidgetsListContentEntry widgetsListRowEntry2 = new WidgetsListContentEntry(
|
||||
mPackageItemInfo2,
|
||||
/* titleSectionName= */ "T",
|
||||
List.of(widgetItem1),
|
||||
/* maxSpanSizeInCells= */ 3);
|
||||
|
||||
assertThat(widgetsListRowEntry1.equals(widgetsListRowEntry2)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equals_entriesWithDifferentTitleSectionName_returnFalse() {
|
||||
WidgetItem widgetItem1 = createWidgetItem(mWidget1, /* spanX= */ 2, /* spanY= */ 3);
|
||||
WidgetsListContentEntry widgetsListRowEntry1 = new WidgetsListContentEntry(
|
||||
mPackageItemInfo1,
|
||||
/* titleSectionName= */ "T",
|
||||
List.of(widgetItem1),
|
||||
/* maxSpanSizeInCells= */ 3);
|
||||
WidgetsListContentEntry widgetsListRowEntry2 = new WidgetsListContentEntry(
|
||||
mPackageItemInfo1,
|
||||
/* titleSectionName= */ "S",
|
||||
List.of(widgetItem1),
|
||||
/* maxSpanSizeInCells= */ 3);
|
||||
|
||||
assertThat(widgetsListRowEntry1.equals(widgetsListRowEntry2)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equals_entriesWithDifferentWidgetsList_returnFalse() {
|
||||
WidgetItem widgetItem1 = createWidgetItem(mWidget1, /* spanX= */ 2, /* spanY= */ 3);
|
||||
WidgetItem widgetItem2 = createWidgetItem(mWidget2, /* spanX= */ 2, /* spanY= */ 3);
|
||||
WidgetsListContentEntry widgetsListRowEntry1 = new WidgetsListContentEntry(
|
||||
mPackageItemInfo1,
|
||||
/* titleSectionName= */ "T",
|
||||
List.of(widgetItem1),
|
||||
/* maxSpanSizeInCells= */ 3);
|
||||
WidgetsListContentEntry widgetsListRowEntry2 = new WidgetsListContentEntry(
|
||||
mPackageItemInfo1,
|
||||
/* titleSectionName= */ "T",
|
||||
List.of(widgetItem2),
|
||||
/* maxSpanSizeInCells= */ 3);
|
||||
|
||||
assertThat(widgetsListRowEntry1.equals(widgetsListRowEntry2)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equals_entriesWithDifferentMaxSpanSize_returnFalse() {
|
||||
WidgetItem widgetItem1 = createWidgetItem(mWidget1, /* spanX= */ 2, /* spanY= */ 3);
|
||||
WidgetsListContentEntry widgetsListRowEntry1 = new WidgetsListContentEntry(
|
||||
mPackageItemInfo1,
|
||||
/* titleSectionName= */ "T",
|
||||
List.of(widgetItem1),
|
||||
/* maxSpanSizeInCells= */ 3);
|
||||
WidgetsListContentEntry widgetsListRowEntry2 = new WidgetsListContentEntry(
|
||||
mPackageItemInfo1,
|
||||
/* titleSectionName= */ "T",
|
||||
List.of(widgetItem1),
|
||||
/* maxSpanSizeInCells= */ 2);
|
||||
|
||||
assertThat(widgetsListRowEntry1.equals(widgetsListRowEntry2)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equals_entriesWithSameContents_returnTrue() {
|
||||
WidgetItem widgetItem1 = createWidgetItem(mWidget1, /* spanX= */ 2, /* spanY= */ 3);
|
||||
WidgetsListContentEntry widgetsListRowEntry1 = new WidgetsListContentEntry(
|
||||
mPackageItemInfo1,
|
||||
/* titleSectionName= */ "T",
|
||||
List.of(widgetItem1),
|
||||
/* maxSpanSizeInCells= */ 3);
|
||||
WidgetsListContentEntry widgetsListRowEntry2 = new WidgetsListContentEntry(
|
||||
mPackageItemInfo1,
|
||||
/* titleSectionName= */ "T",
|
||||
List.of(widgetItem1),
|
||||
/* maxSpanSizeInCells= */ 3);
|
||||
|
||||
assertThat(widgetsListRowEntry1.equals(widgetsListRowEntry2)).isTrue();
|
||||
}
|
||||
|
||||
private WidgetItem createWidgetItem(ComponentName componentName, int spanX, int spanY) {
|
||||
String label = mWidgetsToLabels.get(componentName);
|
||||
AppWidgetProviderInfo widgetInfo = createAppWidgetProviderInfo(componentName);
|
||||
|
||||
Context context = getApplicationContext();
|
||||
LauncherAppWidgetProviderInfo launcherAppWidgetProviderInfo =
|
||||
LauncherAppWidgetProviderInfo.fromProviderInfo(context, widgetInfo);
|
||||
launcherAppWidgetProviderInfo.spanX = spanX;
|
||||
launcherAppWidgetProviderInfo.spanY = spanY;
|
||||
launcherAppWidgetProviderInfo.label = label;
|
||||
|
||||
return new WidgetItem(launcherAppWidgetProviderInfo, mTestProfile, mIconCache, context);
|
||||
}
|
||||
}
|
||||
-211
@@ -1,211 +0,0 @@
|
||||
/*
|
||||
* 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.widget.picker.search;
|
||||
|
||||
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.WidgetUtils.createAppWidgetProviderInfo;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.matches;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.icons.BitmapInfo;
|
||||
import com.android.launcher3.icons.ComponentWithLabel;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.model.WidgetItem;
|
||||
import com.android.launcher3.model.data.PackageItemInfo;
|
||||
import com.android.launcher3.popup.PopupDataProvider;
|
||||
import com.android.launcher3.search.SearchCallback;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
|
||||
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
|
||||
import com.android.launcher3.widget.model.WidgetsListContentEntry;
|
||||
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class SimpleWidgetsSearchAlgorithmTest {
|
||||
|
||||
@Mock private IconCache mIconCache;
|
||||
|
||||
private InvariantDeviceProfile mTestProfile;
|
||||
private WidgetsListHeaderEntry mCalendarHeaderEntry;
|
||||
private WidgetsListContentEntry mCalendarContentEntry;
|
||||
private WidgetsListHeaderEntry mCameraHeaderEntry;
|
||||
private WidgetsListContentEntry mCameraContentEntry;
|
||||
private WidgetsListHeaderEntry mClockHeaderEntry;
|
||||
private WidgetsListContentEntry mClockContentEntry;
|
||||
private Context mContext;
|
||||
|
||||
private SimpleWidgetsSearchAlgorithm mSimpleWidgetsSearchAlgorithm;
|
||||
@Mock
|
||||
private PopupDataProvider mDataProvider;
|
||||
@Mock
|
||||
private SearchCallback<WidgetsListBaseEntry> mSearchCallback;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
doAnswer(invocation -> {
|
||||
ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
|
||||
return componentWithLabel.getComponent().getShortClassName();
|
||||
}).when(mIconCache).getTitleNoCache(any());
|
||||
mTestProfile = new InvariantDeviceProfile();
|
||||
mTestProfile.numRows = 5;
|
||||
mTestProfile.numColumns = 5;
|
||||
mContext = getApplicationContext();
|
||||
|
||||
mCalendarHeaderEntry =
|
||||
createWidgetsHeaderEntry("com.example.android.Calendar", "Calendar", 2);
|
||||
mCalendarContentEntry =
|
||||
createWidgetsContentEntry("com.example.android.Calendar", "Calendar", 2);
|
||||
mCameraHeaderEntry = createWidgetsHeaderEntry("com.example.android.Camera", "Camera", 11);
|
||||
mCameraContentEntry = createWidgetsContentEntry("com.example.android.Camera", "Camera", 11);
|
||||
mClockHeaderEntry = createWidgetsHeaderEntry("com.example.android.Clock", "Clock", 3);
|
||||
mClockContentEntry = createWidgetsContentEntry("com.example.android.Clock", "Clock", 3);
|
||||
|
||||
mSimpleWidgetsSearchAlgorithm = MAIN_EXECUTOR.submit(
|
||||
() -> new SimpleWidgetsSearchAlgorithm(mDataProvider)).get();
|
||||
doReturn(Collections.EMPTY_LIST).when(mDataProvider).getAllWidgets();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filter_shouldMatchOnAppName() {
|
||||
doReturn(List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
|
||||
mCameraContentEntry, mClockHeaderEntry, mClockContentEntry))
|
||||
.when(mDataProvider)
|
||||
.getAllWidgets();
|
||||
|
||||
assertEquals(List.of(
|
||||
WidgetsListHeaderEntry.createForSearch(
|
||||
mCalendarHeaderEntry.mPkgItem,
|
||||
mCalendarHeaderEntry.mTitleSectionName,
|
||||
mCalendarHeaderEntry.mWidgets),
|
||||
mCalendarContentEntry,
|
||||
WidgetsListHeaderEntry.createForSearch(
|
||||
mCameraHeaderEntry.mPkgItem,
|
||||
mCameraHeaderEntry.mTitleSectionName,
|
||||
mCameraHeaderEntry.mWidgets),
|
||||
mCameraContentEntry),
|
||||
SimpleWidgetsSearchAlgorithm.getFilteredWidgets(mDataProvider, "Ca"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filter_shouldMatchOnWidgetLabel() {
|
||||
doReturn(List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
|
||||
mCameraContentEntry))
|
||||
.when(mDataProvider)
|
||||
.getAllWidgets();
|
||||
|
||||
assertEquals(List.of(
|
||||
WidgetsListHeaderEntry.createForSearch(
|
||||
mCalendarHeaderEntry.mPkgItem,
|
||||
mCalendarHeaderEntry.mTitleSectionName,
|
||||
mCalendarHeaderEntry.mWidgets.subList(1, 2)),
|
||||
new WidgetsListContentEntry(
|
||||
mCalendarHeaderEntry.mPkgItem,
|
||||
mCalendarHeaderEntry.mTitleSectionName,
|
||||
mCalendarHeaderEntry.mWidgets.subList(1, 2)),
|
||||
WidgetsListHeaderEntry.createForSearch(
|
||||
mCameraHeaderEntry.mPkgItem,
|
||||
mCameraHeaderEntry.mTitleSectionName,
|
||||
mCameraHeaderEntry.mWidgets.subList(1, 3)),
|
||||
new WidgetsListContentEntry(
|
||||
mCameraHeaderEntry.mPkgItem,
|
||||
mCameraHeaderEntry.mTitleSectionName,
|
||||
mCameraHeaderEntry.mWidgets.subList(1, 3))),
|
||||
SimpleWidgetsSearchAlgorithm.getFilteredWidgets(mDataProvider, "Widget1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doSearch_shouldInformCallback() throws Exception {
|
||||
doReturn(List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
|
||||
mCameraContentEntry, mClockHeaderEntry, mClockContentEntry))
|
||||
.when(mDataProvider)
|
||||
.getAllWidgets();
|
||||
mSimpleWidgetsSearchAlgorithm.doSearch("Ca", mSearchCallback);
|
||||
getInstrumentation().waitForIdleSync();
|
||||
verify(mSearchCallback).onSearchResult(
|
||||
matches("Ca"), argThat(a -> a != null && !a.isEmpty()));
|
||||
}
|
||||
|
||||
private WidgetsListHeaderEntry createWidgetsHeaderEntry(String packageName, String appName,
|
||||
int numOfWidgets) {
|
||||
List<WidgetItem> widgetItems = generateWidgetItems(packageName, numOfWidgets);
|
||||
PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
|
||||
widgetItems.get(0).user);
|
||||
|
||||
return WidgetsListHeaderEntry.create(pInfo, /* titleSectionName= */ "", widgetItems);
|
||||
}
|
||||
|
||||
private WidgetsListContentEntry createWidgetsContentEntry(String packageName, String appName,
|
||||
int numOfWidgets) {
|
||||
List<WidgetItem> widgetItems = generateWidgetItems(packageName, numOfWidgets);
|
||||
PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
|
||||
widgetItems.get(0).user);
|
||||
|
||||
return new WidgetsListContentEntry(pInfo, /* titleSectionName= */ "", widgetItems);
|
||||
}
|
||||
|
||||
private PackageItemInfo createPackageItemInfo(String packageName, String appName,
|
||||
UserHandle userHandle) {
|
||||
PackageItemInfo pInfo = new PackageItemInfo(packageName, userHandle);
|
||||
pInfo.title = appName;
|
||||
pInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
|
||||
return pInfo;
|
||||
}
|
||||
|
||||
private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
|
||||
ArrayList<WidgetItem> widgetItems = new ArrayList<>();
|
||||
for (int i = 0; i < numOfWidgets; i++) {
|
||||
ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
|
||||
AppWidgetProviderInfo widgetInfo = createAppWidgetProviderInfo(cn);
|
||||
|
||||
WidgetItem widgetItem = new WidgetItem(
|
||||
LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
|
||||
mTestProfile, mIconCache, mContext);
|
||||
widgetItems.add(widgetItem);
|
||||
}
|
||||
return widgetItems;
|
||||
}
|
||||
}
|
||||
-162
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.widget.picker.util
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.graphics.Point
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.launcher3.DeviceProfile
|
||||
import com.android.launcher3.InvariantDeviceProfile
|
||||
import com.android.launcher3.LauncherAppState
|
||||
import com.android.launcher3.icons.IconCache
|
||||
import com.android.launcher3.model.WidgetItem
|
||||
import com.android.launcher3.util.ActivityContextWrapper
|
||||
import com.android.launcher3.util.WidgetUtils.createAppWidgetProviderInfo
|
||||
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo
|
||||
import com.google.common.truth.Truth.assertWithMessage
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class WidgetPreviewContainerSizesTest {
|
||||
private lateinit var context: Context
|
||||
private lateinit var deviceProfile: DeviceProfile
|
||||
private lateinit var testInvariantProfile: InvariantDeviceProfile
|
||||
private lateinit var widgetItemInvariantProfile: InvariantDeviceProfile
|
||||
|
||||
@Mock private lateinit var iconCache: IconCache
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
context = ActivityContextWrapper(ApplicationProvider.getApplicationContext())
|
||||
testInvariantProfile = LauncherAppState.getIDP(context)
|
||||
widgetItemInvariantProfile =
|
||||
InvariantDeviceProfile().apply {
|
||||
numRows = TEST_GRID_SIZE
|
||||
numColumns = TEST_GRID_SIZE
|
||||
}
|
||||
deviceProfile = testInvariantProfile.getDeviceProfile(context).copy(context)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun widgetPreviewContainerSize_forItem_returnsCorrectContainerSize() {
|
||||
val testSizes = getTestSizes(deviceProfile)
|
||||
val expectedPreviewContainers = testSizes.values.toList()
|
||||
|
||||
for ((index, widgetSize) in testSizes.keys.withIndex()) {
|
||||
val widgetItem =
|
||||
createWidgetItem(widgetSize, context, widgetItemInvariantProfile, iconCache)
|
||||
|
||||
assertWithMessage("size for $widgetSize should be: ${expectedPreviewContainers[index]}")
|
||||
.that(WidgetPreviewContainerSize.forItem(widgetItem, deviceProfile))
|
||||
.isEqualTo(expectedPreviewContainers[index])
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TEST_PACKAGE = "com.google.test"
|
||||
private const val TEST_GRID_SIZE = 6
|
||||
|
||||
private val HANDHELD_TEST_SIZES: Map<Point, WidgetPreviewContainerSize> =
|
||||
mapOf(
|
||||
// 1x1
|
||||
Point(1, 1) to WidgetPreviewContainerSize(1, 1),
|
||||
// 2x1
|
||||
Point(2, 1) to WidgetPreviewContainerSize(2, 1),
|
||||
Point(3, 1) to WidgetPreviewContainerSize(2, 1),
|
||||
// 4x1
|
||||
Point(4, 1) to WidgetPreviewContainerSize(4, 1),
|
||||
// 2x2
|
||||
Point(2, 2) to WidgetPreviewContainerSize(2, 2),
|
||||
Point(3, 3) to WidgetPreviewContainerSize(2, 2),
|
||||
Point(3, 2) to WidgetPreviewContainerSize(2, 2),
|
||||
// 2x3
|
||||
Point(2, 3) to WidgetPreviewContainerSize(2, 3),
|
||||
Point(3, 4) to WidgetPreviewContainerSize(2, 3),
|
||||
Point(3, 5) to WidgetPreviewContainerSize(2, 3),
|
||||
// 4x2
|
||||
Point(4, 2) to WidgetPreviewContainerSize(4, 2),
|
||||
// 4x3
|
||||
Point(4, 3) to WidgetPreviewContainerSize(4, 3),
|
||||
Point(4, 4) to WidgetPreviewContainerSize(4, 3),
|
||||
)
|
||||
|
||||
private val TABLET_TEST_SIZES: Map<Point, WidgetPreviewContainerSize> =
|
||||
mapOf(
|
||||
// 1x1
|
||||
Point(1, 1) to WidgetPreviewContainerSize(1, 1),
|
||||
// 2x1
|
||||
Point(2, 1) to WidgetPreviewContainerSize(2, 1),
|
||||
// 3x1
|
||||
Point(3, 1) to WidgetPreviewContainerSize(3, 1),
|
||||
Point(4, 1) to WidgetPreviewContainerSize(3, 1),
|
||||
// 2x2
|
||||
Point(2, 2) to WidgetPreviewContainerSize(2, 2),
|
||||
// 2x3
|
||||
Point(2, 3) to WidgetPreviewContainerSize(2, 3),
|
||||
// 3x2
|
||||
Point(3, 2) to WidgetPreviewContainerSize(3, 2),
|
||||
Point(4, 2) to WidgetPreviewContainerSize(3, 2),
|
||||
Point(5, 2) to WidgetPreviewContainerSize(3, 2),
|
||||
// 3x3
|
||||
Point(3, 3) to WidgetPreviewContainerSize(3, 3),
|
||||
Point(4, 4) to WidgetPreviewContainerSize(3, 3),
|
||||
// 3x4
|
||||
Point(5, 4) to WidgetPreviewContainerSize(3, 4),
|
||||
Point(3, 4) to WidgetPreviewContainerSize(3, 4),
|
||||
Point(5, 5) to WidgetPreviewContainerSize(3, 4),
|
||||
Point(6, 4) to WidgetPreviewContainerSize(3, 4),
|
||||
Point(6, 5) to WidgetPreviewContainerSize(3, 4),
|
||||
)
|
||||
|
||||
private fun getTestSizes(dp: DeviceProfile) =
|
||||
if (dp.isTablet && !dp.isTwoPanels) {
|
||||
TABLET_TEST_SIZES
|
||||
} else {
|
||||
HANDHELD_TEST_SIZES
|
||||
}
|
||||
|
||||
private fun createWidgetItem(
|
||||
widgetSize: Point,
|
||||
context: Context,
|
||||
invariantDeviceProfile: InvariantDeviceProfile,
|
||||
iconCache: IconCache
|
||||
): WidgetItem {
|
||||
val providerInfo =
|
||||
createAppWidgetProviderInfo(
|
||||
ComponentName.createRelative(
|
||||
TEST_PACKAGE,
|
||||
/*cls=*/ ".WidgetProvider_" + widgetSize.x + "x" + widgetSize.y
|
||||
)
|
||||
)
|
||||
val widgetInfo =
|
||||
LauncherAppWidgetProviderInfo.fromProviderInfo(context, providerInfo).apply {
|
||||
spanX = widgetSize.x
|
||||
spanY = widgetSize.y
|
||||
}
|
||||
return WidgetItem(widgetInfo, invariantDeviceProfile, iconCache, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
-312
@@ -1,312 +0,0 @@
|
||||
/*
|
||||
* 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.widget.picker.util;
|
||||
|
||||
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
|
||||
|
||||
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.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.icons.ComponentWithLabel;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.model.WidgetItem;
|
||||
import com.android.launcher3.pm.ShortcutConfigActivityInfo;
|
||||
import com.android.launcher3.util.ActivityContextWrapper;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
|
||||
import com.android.launcher3.widget.util.WidgetsTableUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public final class WidgetsTableUtilsTest {
|
||||
private static final String TEST_PACKAGE = "com.google.test";
|
||||
|
||||
private static final int SPACE_SIZE = 10;
|
||||
// Note - actual widget size includes SPACE_SIZE (border) + cell padding.
|
||||
private static final int CELL_SIZE = 50;
|
||||
private static final int NUM_OF_COLS = 5;
|
||||
private static final int NUM_OF_ROWS = 5;
|
||||
|
||||
@Mock
|
||||
private IconCache mIconCache;
|
||||
|
||||
private DeviceProfile mTestDeviceProfile;
|
||||
|
||||
private Context mContext;
|
||||
private InvariantDeviceProfile mTestInvariantProfile;
|
||||
private WidgetItem mWidget1x1;
|
||||
private WidgetItem mWidget2x2;
|
||||
private WidgetItem mWidget2x3;
|
||||
private WidgetItem mWidget2x4;
|
||||
private WidgetItem mWidget4x4;
|
||||
|
||||
private WidgetItem mShortcut1;
|
||||
private WidgetItem mShortcut2;
|
||||
private WidgetItem mShortcut3;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mContext = new ActivityContextWrapper(getApplicationContext());
|
||||
|
||||
mTestInvariantProfile = new InvariantDeviceProfile();
|
||||
mTestInvariantProfile.numColumns = NUM_OF_COLS;
|
||||
mTestInvariantProfile.numRows = NUM_OF_ROWS;
|
||||
|
||||
initDP();
|
||||
initTestWidgets();
|
||||
initTestShortcuts();
|
||||
|
||||
doAnswer(invocation -> ((ComponentWithLabel) invocation.getArgument(0))
|
||||
.getComponent().getPackageName())
|
||||
.when(mIconCache).getTitleNoCache(any());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void groupWithReordering_widgetsOnly_maxSpanPxPerRow220_cellPadding0() {
|
||||
List<WidgetItem> widgetItems = List.of(mWidget4x4, mWidget2x3, mWidget1x1, mWidget2x4,
|
||||
mWidget2x2);
|
||||
|
||||
List<ArrayList<WidgetItem>> widgetItemInTable =
|
||||
WidgetsTableUtils.groupWidgetItemsUsingRowPxWithReordering(widgetItems, mContext,
|
||||
mTestDeviceProfile, 220, 0);
|
||||
|
||||
// With reordering, rows displayed in order of increasing size.
|
||||
// Row 0: 1x1(50px)
|
||||
// Row 1: 2x2(in a 2x2 container - 110px)
|
||||
// Row 2: 2x3(in a 2x3 container - 110px), 2x4(in a 2x3 container - 110px)
|
||||
// Row 3: 4x4(in a 3x3 container in tablet - 170px; 4x3 on phone - 230px)
|
||||
assertThat(widgetItemInTable).hasSize(4);
|
||||
assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1);
|
||||
assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x2);
|
||||
assertThat(widgetItemInTable.get(2)).containsExactly(mWidget2x3, mWidget2x4);
|
||||
assertThat(widgetItemInTable.get(3)).containsExactly(mWidget4x4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void groupWithReordering_widgetsOnly_maxSpanPxPerRow220_cellPadding10() {
|
||||
List<WidgetItem> widgetItems = List.of(mWidget4x4, mWidget2x3, mWidget1x1, mWidget2x4,
|
||||
mWidget2x2);
|
||||
|
||||
List<ArrayList<WidgetItem>> widgetItemInTable =
|
||||
WidgetsTableUtils.groupWidgetItemsUsingRowPxWithReordering(widgetItems, mContext,
|
||||
mTestDeviceProfile, 220, 10);
|
||||
|
||||
// With reordering, but space taken up by cell padding, so, no grouping (even if 2x2 and 2x3
|
||||
// use same preview container).
|
||||
// Row 0: 1x1(50px)
|
||||
// Row 1: 2x2(in a 2x2 container: 130px)
|
||||
// Row 2: 2x3(in a 2x3 container: 130px)
|
||||
// Row 3: 2x4(in a 2x3 container: 130px)
|
||||
// Row 4: 4x4(in a 3x3 container in tablet - 190px; 4x3 on phone - 250px)
|
||||
assertThat(widgetItemInTable).hasSize(5);
|
||||
assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1);
|
||||
assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x2);
|
||||
assertThat(widgetItemInTable.get(2)).containsExactly(mWidget2x3);
|
||||
assertThat(widgetItemInTable.get(3)).containsExactly(mWidget2x4);
|
||||
assertThat(widgetItemInTable.get(4)).containsExactly(mWidget4x4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void groupWithReordering_widgetsOnly_maxSpanPxPerRow260_cellPadding10() {
|
||||
List<WidgetItem> widgetItems = List.of(mWidget4x4, mWidget2x3, mWidget1x1, mWidget2x4,
|
||||
mWidget2x2);
|
||||
|
||||
List<ArrayList<WidgetItem>> widgetItemInTable =
|
||||
WidgetsTableUtils.groupWidgetItemsUsingRowPxWithReordering(widgetItems, mContext,
|
||||
mTestDeviceProfile, 260, 10);
|
||||
|
||||
// With reordering, even with cellPadding, enough space to group 2x3 and 2x4 (which also use
|
||||
// same container)
|
||||
// Row 0: 1x1(50px)
|
||||
// Row 1: 2x2(in a 2x2 container: 130px)
|
||||
// Row 2: 2x3(in a 2x3 container: 130px), 2x4(in a 2x3 container: 130px)
|
||||
// Row 3: 4x4(in a 3x3 container in tablet - 190px; 4x3 on phone - 250px)
|
||||
assertThat(widgetItemInTable).hasSize(4);
|
||||
assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1);
|
||||
assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x2);
|
||||
assertThat(widgetItemInTable.get(2)).containsExactly(mWidget2x3, mWidget2x4);
|
||||
assertThat(widgetItemInTable.get(3)).containsExactly(mWidget4x4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void groupWithReordering_widgetsOnly_maxSpanPxPerRow350_cellPadding0() {
|
||||
List<WidgetItem> widgetItems = List.of(mWidget4x4, mWidget2x3, mWidget1x1, mWidget2x4,
|
||||
mWidget2x2);
|
||||
|
||||
List<ArrayList<WidgetItem>> widgetItemInTable =
|
||||
WidgetsTableUtils.groupWidgetItemsUsingRowPxWithReordering(widgetItems, mContext,
|
||||
mTestDeviceProfile, 350, 0);
|
||||
|
||||
// With reordering, rows displayed in order of increasing size.
|
||||
// Row 0: 1x1(50px)
|
||||
// Row 1: 2x2(in a 2x2 container: 110px)
|
||||
// Row 2: 2x3(in a 2x3 container: 110px), 2x4(in a 2x3 container: 110px)
|
||||
// Row 3: 4x4(in a 3x3 container in tablet - 170px; 4x3 on phone - 230px)
|
||||
assertThat(widgetItemInTable).hasSize(4);
|
||||
assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1);
|
||||
assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x2);
|
||||
assertThat(widgetItemInTable.get(2)).containsExactly(mWidget2x3, mWidget2x4);
|
||||
assertThat(widgetItemInTable.get(3)).containsExactly(mWidget4x4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void groupWithReordering_mixItems_maxSpanPxPerRow350_cellPadding0() {
|
||||
List<WidgetItem> widgetItems = List.of(mWidget4x4, mShortcut3, mWidget2x3, mShortcut1,
|
||||
mWidget1x1, mShortcut2, mWidget2x4, mWidget2x2);
|
||||
|
||||
List<ArrayList<WidgetItem>> widgetItemInTable =
|
||||
WidgetsTableUtils.groupWidgetItemsUsingRowPxWithReordering(widgetItems, mContext,
|
||||
mTestDeviceProfile, 350, 0);
|
||||
|
||||
// With reordering - rows displays in order of increasing size:
|
||||
// Row 0: 1x1(50px)
|
||||
// Row 1: 2x2(110px)
|
||||
// Row 2: 2x3 (in a 2x3 container 110px), 2x4 (in a 2x3 container 110px)
|
||||
// Row 3: 4x4 (in a 3x3 container in tablet - 170px; 4x3 on phone - 230px)
|
||||
// Row 4: shortcut3, shortcut1, shortcut2 (shortcuts are always displayed at bottom)
|
||||
assertThat(widgetItemInTable).hasSize(5);
|
||||
assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1);
|
||||
assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x2);
|
||||
assertThat(widgetItemInTable.get(2)).containsExactly(mWidget2x3, mWidget2x4);
|
||||
assertThat(widgetItemInTable.get(3)).containsExactly(mWidget4x4);
|
||||
assertThat(widgetItemInTable.get(4)).containsExactly(mShortcut3, mShortcut2, mShortcut1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void groupWithoutReordering_maxSpanPxPerRow220_cellPadding0() {
|
||||
List<WidgetItem> widgetItems =
|
||||
List.of(mWidget4x4, mWidget2x3, mWidget1x1, mWidget2x4, mWidget2x2);
|
||||
|
||||
List<ArrayList<WidgetItem>> widgetItemInTable =
|
||||
WidgetsTableUtils.groupWidgetItemsUsingRowPxWithoutReordering(widgetItems, mContext,
|
||||
mTestDeviceProfile, 220, 0);
|
||||
|
||||
// Without reordering, widgets are grouped only if the next one fits and uses same preview
|
||||
// container:
|
||||
// Row 0: 4x4(in a 3x3 container in tablet - 170px; 4x3 on phone - 230px)
|
||||
// Row 1: 2x3(in a 2x3 container - 110px)
|
||||
// Row 2: 1x1(50px)
|
||||
// Row 3: 2x4(in a 2x3 container - 110px)
|
||||
// Row 4: 2x2(in a 2x2 container - 110px)
|
||||
assertThat(widgetItemInTable).hasSize(5);
|
||||
assertThat(widgetItemInTable.get(0)).containsExactly(mWidget4x4);
|
||||
assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x3);
|
||||
assertThat(widgetItemInTable.get(2)).containsExactly(mWidget1x1);
|
||||
assertThat(widgetItemInTable.get(3)).containsExactly(mWidget2x4);
|
||||
assertThat(widgetItemInTable.get(4)).containsExactly(mWidget2x2);
|
||||
}
|
||||
|
||||
private void initDP() {
|
||||
DeviceProfile dp = LauncherAppState.getIDP(mContext)
|
||||
.getDeviceProfile(mContext).copy(mContext);
|
||||
mTestDeviceProfile = Mockito.spy(dp);
|
||||
|
||||
doAnswer(i -> {
|
||||
((Point) i.getArgument(0)).set(CELL_SIZE, CELL_SIZE);
|
||||
return null;
|
||||
}).when(mTestDeviceProfile).getCellSize(any(Point.class));
|
||||
when(mTestDeviceProfile.getCellSize()).thenReturn(new Point(CELL_SIZE, CELL_SIZE));
|
||||
mTestDeviceProfile.cellLayoutBorderSpacePx = new Point(SPACE_SIZE, SPACE_SIZE);
|
||||
mTestDeviceProfile.widgetPadding.setEmpty();
|
||||
mTestDeviceProfile.allAppsIconSizePx = 0;
|
||||
}
|
||||
|
||||
private void initTestWidgets() {
|
||||
List<Point> widgetSizes = List.of(new Point(1, 1), new Point(2, 2), new Point(2, 3),
|
||||
new Point(2, 4), new Point(4, 4));
|
||||
|
||||
ArrayList<WidgetItem> widgetItems = new ArrayList<>();
|
||||
widgetSizes.stream().forEach(widgetSize -> {
|
||||
AppWidgetProviderInfo info = createAppWidgetProviderInfo(
|
||||
ComponentName.createRelative(
|
||||
TEST_PACKAGE,
|
||||
".WidgetProvider_" + widgetSize.x + "x" + widgetSize.y));
|
||||
LauncherAppWidgetProviderInfo widgetInfo =
|
||||
LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info);
|
||||
widgetInfo.spanX = widgetSize.x;
|
||||
widgetInfo.spanY = widgetSize.y;
|
||||
widgetItems.add(new WidgetItem(
|
||||
widgetInfo, mTestInvariantProfile, mIconCache, mContext));
|
||||
});
|
||||
mWidget1x1 = widgetItems.get(0);
|
||||
mWidget2x2 = widgetItems.get(1);
|
||||
mWidget2x3 = widgetItems.get(2);
|
||||
mWidget2x4 = widgetItems.get(3);
|
||||
mWidget4x4 = widgetItems.get(4);
|
||||
}
|
||||
|
||||
private void initTestShortcuts() {
|
||||
PackageManager packageManager = mContext.getPackageManager();
|
||||
mShortcut1 = new WidgetItem(new TestShortcutConfigActivityInfo(
|
||||
ComponentName.createRelative(TEST_PACKAGE, ".shortcut1"), UserHandle.CURRENT),
|
||||
mIconCache, packageManager);
|
||||
mShortcut2 = new WidgetItem(new TestShortcutConfigActivityInfo(
|
||||
ComponentName.createRelative(TEST_PACKAGE, ".shortcut2"), UserHandle.CURRENT),
|
||||
mIconCache, packageManager);
|
||||
mShortcut3 = new WidgetItem(new TestShortcutConfigActivityInfo(
|
||||
ComponentName.createRelative(TEST_PACKAGE, ".shortcut3"), UserHandle.CURRENT),
|
||||
mIconCache, packageManager);
|
||||
|
||||
}
|
||||
|
||||
private final class TestShortcutConfigActivityInfo extends ShortcutConfigActivityInfo {
|
||||
|
||||
TestShortcutConfigActivityInfo(ComponentName componentName, UserHandle user) {
|
||||
super(componentName, user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getFullResIcon(IconCache cache) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getLabel(PackageManager pm) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user