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 android.content.Context;
20 import android.content.pm.ApplicationInfo;
21 
22 import androidx.annotation.Nullable;
23 import androidx.annotation.WorkerThread;
24 
25 import com.android.launcher3.R;
26 import com.android.launcher3.model.WidgetItem;
27 import com.android.launcher3.util.PackageManagerHelper;
28 import com.android.launcher3.util.Preconditions;
29 import com.android.launcher3.util.ResourceBasedOverride;
30 
31 /**
32  * A {@link ResourceBasedOverride} that categorizes widget recommendations.
33  *
34  * <p>Override the {@code widget_recommendation_category_provider_class} resource to provide your
35  * own implementation. Method {@code getWidgetRecommendationCategory} is called per widget to get
36  * the category.</p>
37  */
38 public class WidgetRecommendationCategoryProvider implements ResourceBasedOverride {
39     private static final String TAG = "WidgetRecommendationCategoryProvider";
40 
41     /**
42      * Retrieve instance of this object that can be overridden in runtime based on the build
43      * variant of the application.
44      */
newInstance(Context context)45     public static WidgetRecommendationCategoryProvider newInstance(Context context) {
46         Preconditions.assertWorkerThread();
47         return Overrides.getObject(
48                 WidgetRecommendationCategoryProvider.class, context.getApplicationContext(),
49                 R.string.widget_recommendation_category_provider_class);
50     }
51 
52     /**
53      * Returns a {@link WidgetRecommendationCategory} for the provided widget item that can be used
54      * to display the recommendation grouped by categories.
55      */
56     @WorkerThread
57     @Nullable
getWidgetRecommendationCategory(Context context, WidgetItem item)58     public WidgetRecommendationCategory getWidgetRecommendationCategory(Context context,
59             WidgetItem item) {
60         // This is a default implementation that uses application category to derive the category to
61         // be displayed. The implementation can be overridden in individual launcher customization
62         // via the overridden WidgetRecommendationCategoryProvider resource.
63 
64         Preconditions.assertWorkerThread();
65         try (PackageManagerHelper pmHelper = new PackageManagerHelper(context)) {
66             if (item.widgetInfo != null && item.widgetInfo.getComponent() != null) {
67                 ApplicationInfo applicationInfo = pmHelper.getApplicationInfo(
68                         item.widgetInfo.getComponent().getPackageName(), item.widgetInfo.getUser(),
69                         0 /* flags */);
70                 if (applicationInfo != null) {
71                     return getCategoryFromApplicationCategory(applicationInfo.category);
72                 }
73             }
74         }
75         return null;
76     }
77 
78     /** Maps application category to an appropriate displayable category. */
getCategoryFromApplicationCategory( int applicationCategory)79     private static WidgetRecommendationCategory getCategoryFromApplicationCategory(
80             int applicationCategory) {
81         if (applicationCategory == ApplicationInfo.CATEGORY_PRODUCTIVITY) {
82             return new WidgetRecommendationCategory(
83                     R.string.productivity_widget_recommendation_category_label, /*order=*/0);
84         }
85 
86         if (applicationCategory == ApplicationInfo.CATEGORY_NEWS) {
87             return new WidgetRecommendationCategory(
88                     R.string.news_widget_recommendation_category_label, /*order=*/1);
89         }
90 
91         if (applicationCategory == ApplicationInfo.CATEGORY_SOCIAL) {
92             return new WidgetRecommendationCategory(
93                     R.string.social_widget_recommendation_category_label,
94                     /*order=*/3);
95         }
96 
97         if (applicationCategory == ApplicationInfo.CATEGORY_AUDIO
98                 || applicationCategory == ApplicationInfo.CATEGORY_VIDEO
99                 || applicationCategory == ApplicationInfo.CATEGORY_IMAGE) {
100             return new WidgetRecommendationCategory(
101                     R.string.entertainment_widget_recommendation_category_label,
102                     /*order=*/4);
103         }
104 
105         return new WidgetRecommendationCategory(
106                 R.string.others_widget_recommendation_category_label, /*order=*/2);
107     }
108 }
109