1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.launcher3.widget.picker;
18 
19 import static android.content.pm.ApplicationInfo.CATEGORY_AUDIO;
20 import static android.content.pm.ApplicationInfo.CATEGORY_IMAGE;
21 import static android.content.pm.ApplicationInfo.CATEGORY_NEWS;
22 import static android.content.pm.ApplicationInfo.CATEGORY_PRODUCTIVITY;
23 import static android.content.pm.ApplicationInfo.CATEGORY_SOCIAL;
24 import static android.content.pm.ApplicationInfo.CATEGORY_UNDEFINED;
25 import static android.content.pm.ApplicationInfo.CATEGORY_VIDEO;
26 import static android.content.pm.ApplicationInfo.FLAG_INSTALLED;
27 
28 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
29 
30 import static com.google.common.truth.Truth.assertThat;
31 
32 import static org.mockito.ArgumentMatchers.any;
33 import static org.mockito.ArgumentMatchers.eq;
34 import static org.mockito.Mockito.doAnswer;
35 import static org.mockito.Mockito.when;
36 
37 import android.appwidget.AppWidgetProviderInfo;
38 import android.content.ComponentName;
39 import android.content.Context;
40 import android.content.ContextWrapper;
41 import android.content.pm.ApplicationInfo;
42 import android.content.pm.LauncherApps;
43 import android.os.Process;
44 
45 import androidx.test.core.content.pm.ApplicationInfoBuilder;
46 import androidx.test.ext.junit.runners.AndroidJUnit4;
47 import androidx.test.filters.SmallTest;
48 
49 import com.android.launcher3.InvariantDeviceProfile;
50 import com.android.launcher3.R;
51 import com.android.launcher3.icons.IconCache;
52 import com.android.launcher3.model.WidgetItem;
53 import com.android.launcher3.util.Executors;
54 import com.android.launcher3.util.WidgetUtils;
55 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
56 
57 import com.google.common.collect.ImmutableMap;
58 
59 import org.junit.Before;
60 import org.junit.Test;
61 import org.junit.runner.RunWith;
62 import org.mockito.Mock;
63 import org.mockito.MockitoAnnotations;
64 
65 import java.util.Map;
66 
67 @SmallTest
68 @RunWith(AndroidJUnit4.class)
69 public class WidgetRecommendationCategoryProviderTest {
70     private static final String TEST_PACKAGE = "com.foo.test";
71     private static final String TEST_APP_NAME = "foo";
72     private static final WidgetRecommendationCategory PRODUCTIVITY =
73             new WidgetRecommendationCategory(
74                     R.string.productivity_widget_recommendation_category_label,
75                     /*order=*/0);
76     private static final WidgetRecommendationCategory NEWS =
77             new WidgetRecommendationCategory(
78                     R.string.news_widget_recommendation_category_label, /*order=*/1);
79     private static final WidgetRecommendationCategory SUGGESTED_FOR_YOU =
80             new WidgetRecommendationCategory(
81                     R.string.others_widget_recommendation_category_label, /*order=*/2);
82     private static final WidgetRecommendationCategory SOCIAL =
83             new WidgetRecommendationCategory(
84                     R.string.social_widget_recommendation_category_label,
85                     /*order=*/3);
86     private static final WidgetRecommendationCategory ENTERTAINMENT =
87             new WidgetRecommendationCategory(
88                     R.string.entertainment_widget_recommendation_category_label,
89                     /*order=*/4);
90 
91     private final ApplicationInfo mTestAppInfo = ApplicationInfoBuilder.newBuilder().setPackageName(
92             TEST_PACKAGE).setName(TEST_APP_NAME).build();
93     private Context mContext;
94     @Mock
95     private IconCache mIconCache;
96 
97     private WidgetItem mTestWidgetItem;
98     @Mock
99     private LauncherApps mLauncherApps;
100     private InvariantDeviceProfile mTestProfile;
101 
102     @Before
setUp()103     public void setUp() {
104         MockitoAnnotations.initMocks(this);
105         mContext = new ContextWrapper(getInstrumentation().getTargetContext()) {
106             @Override
107             public Object getSystemService(String name) {
108                 return LAUNCHER_APPS_SERVICE.equals(name) ? mLauncherApps : super.getSystemService(
109                         name);
110             }
111         };
112         mTestAppInfo.flags = FLAG_INSTALLED;
113         mTestProfile = new InvariantDeviceProfile();
114         mTestProfile.numRows = 5;
115         mTestProfile.numColumns = 5;
116         createTestWidgetItem();
117     }
118 
119     @Test
getWidgetRecommendationCategory_returnsMappedCategory()120     public void getWidgetRecommendationCategory_returnsMappedCategory() throws Exception {
121         ImmutableMap<Integer, WidgetRecommendationCategory> testCategories = ImmutableMap.of(
122                 CATEGORY_PRODUCTIVITY, PRODUCTIVITY,
123                 CATEGORY_NEWS, NEWS,
124                 CATEGORY_SOCIAL, SOCIAL,
125                 CATEGORY_AUDIO, ENTERTAINMENT,
126                 CATEGORY_IMAGE, ENTERTAINMENT,
127                 CATEGORY_VIDEO, ENTERTAINMENT,
128                 CATEGORY_UNDEFINED, SUGGESTED_FOR_YOU);
129 
130         for (Map.Entry<Integer, WidgetRecommendationCategory> testCategory :
131                 testCategories.entrySet()) {
132 
133             mTestAppInfo.category = testCategory.getKey();
134             when(mLauncherApps.getApplicationInfo(/*packageName=*/ eq(TEST_PACKAGE),
135                     /*flags=*/ eq(0),
136                     /*user=*/ eq(Process.myUserHandle())))
137                     .thenReturn(mTestAppInfo);
138 
139             WidgetRecommendationCategory category = Executors.MODEL_EXECUTOR.submit(() ->
140                     new WidgetRecommendationCategoryProvider().getWidgetRecommendationCategory(
141                             mContext,
142                             mTestWidgetItem)).get();
143 
144             assertThat(category).isEqualTo(testCategory.getValue());
145         }
146     }
147 
createTestWidgetItem()148     private void createTestWidgetItem() {
149         String widgetLabel = "Foo Widget";
150         String widgetClassName = ".mWidget";
151 
152         doAnswer(invocation -> widgetLabel).when(mIconCache).getTitleNoCache(any());
153 
154         AppWidgetProviderInfo providerInfo = WidgetUtils.createAppWidgetProviderInfo(ComponentName
155                 .createRelative(TEST_PACKAGE, widgetClassName));
156 
157         LauncherAppWidgetProviderInfo launcherAppWidgetProviderInfo =
158                 LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, providerInfo);
159         launcherAppWidgetProviderInfo.spanX = 2;
160         launcherAppWidgetProviderInfo.spanY = 2;
161         launcherAppWidgetProviderInfo.label = widgetLabel;
162         mTestWidgetItem = new WidgetItem(launcherAppWidgetProviderInfo, mTestProfile, mIconCache,
163                 mContext
164         );
165     }
166 }
167