• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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;
18 
19 import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
20 
21 import android.annotation.TargetApi;
22 import android.appwidget.AppWidgetManager;
23 import android.appwidget.AppWidgetProviderInfo;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.os.Build;
27 import android.os.Bundle;
28 import android.os.UserHandle;
29 import android.util.Log;
30 import android.widget.RemoteViews;
31 
32 import androidx.annotation.NonNull;
33 import androidx.annotation.Nullable;
34 import androidx.annotation.RequiresApi;
35 import androidx.annotation.VisibleForTesting;
36 
37 import com.android.launcher3.logging.FileLog;
38 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
39 import com.android.launcher3.pm.UserCache;
40 import com.android.launcher3.util.PackageUserKey;
41 import com.android.launcher3.widget.custom.CustomWidgetManager;
42 
43 import java.util.Collections;
44 import java.util.List;
45 import java.util.stream.Collectors;
46 import java.util.stream.Stream;
47 
48 /**
49  * Utility class to working with {@link AppWidgetManager}
50  */
51 public class WidgetManagerHelper {
52 
53     private static final String TAG = "WidgetManagerHelper";
54     //TODO: replace this with OPTION_APPWIDGET_RESTORE_COMPLETED b/63667276
55     public static final String WIDGET_OPTION_RESTORE_COMPLETED = "appWidgetRestoreCompleted";
56 
57     final AppWidgetManager mAppWidgetManager;
58     final Context mContext;
59 
WidgetManagerHelper(Context context)60     public WidgetManagerHelper(Context context) {
61         this(context, AppWidgetManager.getInstance(context));
62     }
63 
64     @VisibleForTesting
WidgetManagerHelper(Context context, AppWidgetManager appWidgetManager)65     public WidgetManagerHelper(Context context, AppWidgetManager appWidgetManager) {
66         mContext = context;
67         mAppWidgetManager = appWidgetManager;
68     }
69 
70     /**
71      * @see AppWidgetManager#getAppWidgetInfo(int)
72      */
73     @Nullable
getLauncherAppWidgetInfo( int appWidgetId, ComponentName componentName)74     public LauncherAppWidgetProviderInfo getLauncherAppWidgetInfo(
75             int appWidgetId, ComponentName componentName) {
76 
77         // For custom widgets.
78         if (appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) {
79             return CustomWidgetManager.INSTANCE.get(mContext).getWidgetProvider(componentName);
80         }
81 
82         AppWidgetProviderInfo info = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
83         if (info == null) {
84             FileLog.w(TAG,
85                     "getLauncherAppWidgetInfo: AppWidgetManager returned null AppWidgetInfo for"
86                             + " appWidgetId=" + appWidgetId
87                             + ", componentName=" + componentName);
88             return null;
89         }
90         return LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info);
91     }
92 
93     /**
94      * @see AppWidgetManager#getInstalledProvidersForPackage(String, UserHandle)
95      */
96     @TargetApi(Build.VERSION_CODES.O)
getAllProviders(@ullable PackageUserKey packageUser)97     public List<AppWidgetProviderInfo> getAllProviders(@Nullable PackageUserKey packageUser) {
98         if (!WIDGETS_ENABLED) {
99             return Collections.emptyList();
100         }
101 
102         if (packageUser == null) {
103             return allWidgetsSteam(mContext).collect(Collectors.toList());
104         }
105 
106         try {
107             return mAppWidgetManager.getInstalledProvidersForPackage(
108                     packageUser.mPackageName, packageUser.mUser);
109         } catch (IllegalStateException e) {
110             // b/277189566: Launcher will load the widget when it gets the user-unlock event.
111             // If exception is thrown because of device is locked, it means a race condition occurs
112             // that the user got locked again while launcher is processing the event. In this case
113             // we should return empty list.
114             Log.e(TAG, "getAllProviders: Error getting installed providers for"
115                     + " package=" + packageUser.mPackageName, e);
116             return Collections.emptyList();
117         }
118     }
119 
120     /**
121      * @see AppWidgetManager#bindAppWidgetIdIfAllowed(int, UserHandle, ComponentName, Bundle)
122      */
bindAppWidgetIdIfAllowed(int appWidgetId, AppWidgetProviderInfo info, Bundle options)123     public boolean bindAppWidgetIdIfAllowed(int appWidgetId, AppWidgetProviderInfo info,
124             Bundle options) {
125         if (!WIDGETS_ENABLED) {
126             return false;
127         }
128         if (appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) {
129             return true;
130         }
131         return mAppWidgetManager.bindAppWidgetIdIfAllowed(
132                 appWidgetId, info.getProfile(), info.provider, options);
133     }
134 
findProvider(ComponentName provider, UserHandle user)135     public LauncherAppWidgetProviderInfo findProvider(ComponentName provider, UserHandle user) {
136         if (!WIDGETS_ENABLED) {
137             return null;
138         }
139         for (AppWidgetProviderInfo info :
140                 getAllProviders(new PackageUserKey(provider.getPackageName(), user))) {
141             if (info.provider.equals(provider)) {
142                 return LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info);
143             }
144         }
145         Log.w(TAG, "findProvider: No App Widget Provider found for component=" + provider
146                 + " user=" + user);
147         return null;
148     }
149 
150     /**
151      * Returns if a AppWidgetProvider has marked a widget restored
152      */
isAppWidgetRestored(int appWidgetId)153     public boolean isAppWidgetRestored(int appWidgetId) {
154         return WIDGETS_ENABLED && mAppWidgetManager.getAppWidgetOptions(appWidgetId)
155                 .getBoolean(WIDGET_OPTION_RESTORE_COMPLETED);
156     }
157 
158 
159     /**
160      * Load RemoteViews preview for this provider if available.
161      *
162      * @param info           The provider info for the widget you want to preview.
163      * @param widgetCategory The widget category for which you want to display previews.
164      * @return Returns the widget preview that matches selected category, if available.
165      */
166     @Nullable
167     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
loadGeneratedPreview(@onNull AppWidgetProviderInfo info, int widgetCategory)168     public RemoteViews loadGeneratedPreview(@NonNull AppWidgetProviderInfo info,
169             int widgetCategory) {
170         if (!android.appwidget.flags.Flags.generatedPreviews()) return null;
171         return mAppWidgetManager.getWidgetPreview(info.provider, info.getProfile(), widgetCategory);
172     }
173 
allWidgetsSteam(Context context)174     private static Stream<AppWidgetProviderInfo> allWidgetsSteam(Context context) {
175         AppWidgetManager awm = context.getSystemService(AppWidgetManager.class);
176         return Stream.concat(
177                 UserCache.INSTANCE.get(context)
178                         .getUserProfiles()
179                         .stream()
180                         .flatMap(u -> awm.getInstalledProvidersForProfile(u).stream()),
181                 CustomWidgetManager.INSTANCE.get(context).stream());
182     }
183 }
184