From 0a926c1d67e63a2b2cdc682b8ae69e06bff8ca07 Mon Sep 17 00:00:00 2001 From: Rajeev Kumar Date: Thu, 1 Nov 2018 18:53:42 -0700 Subject: Create a launcher model override. This change disables shortcuts/widgets loading on Android Go devices. Bug: 112904271 Test: Manual test Change-Id: I2c40f87a8f5d752525c99d254693a4e0a9eeeb2b --- .../com/android/launcher3/model/WidgetsModel.java | 240 +++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java (limited to 'src_shortcuts_overrides/com/android/launcher3') diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java new file mode 100644 index 000000000..9a17ec65c --- /dev/null +++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java @@ -0,0 +1,240 @@ + +package com.android.launcher3.model; + +import static android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_HIDE_FROM_PICKER; + +import android.appwidget.AppWidgetProviderInfo; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.Process; +import android.os.UserHandle; +import android.util.Log; + +import com.android.launcher3.AppFilter; +import com.android.launcher3.icons.ComponentWithLabel; +import com.android.launcher3.icons.IconCache; +import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherAppWidgetProviderInfo; +import com.android.launcher3.Utilities; +import com.android.launcher3.compat.AlphabeticIndexCompat; +import com.android.launcher3.compat.AppWidgetManagerCompat; +import com.android.launcher3.compat.LauncherAppsCompat; +import com.android.launcher3.compat.ShortcutConfigActivityInfo; +import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.util.MultiHashMap; +import com.android.launcher3.util.PackageUserKey; +import com.android.launcher3.util.Preconditions; +import com.android.launcher3.widget.WidgetItemComparator; +import com.android.launcher3.widget.WidgetListRowEntry; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import androidx.annotation.Nullable; + +/** + * Widgets data model that is used by the adapters of the widget views and controllers. + * + *

The widgets and shortcuts are organized using package name as its index. + */ +public class WidgetsModel { + + private static final String TAG = "WidgetsModel"; + private static final boolean DEBUG = false; + + /* Map of widgets and shortcuts that are tracked per package. */ + private final MultiHashMap mWidgetsList = new MultiHashMap<>(); + + private AppFilter mAppFilter; + + /** + * Returns a list of {@link WidgetListRowEntry}. All {@link WidgetItem} in a single row + * are sorted (based on label and user), but the overall list of {@link WidgetListRowEntry}s + * is not sorted. This list is sorted at the UI when using + * {@link com.android.launcher3.widget.WidgetsDiffReporter} + * + * @see com.android.launcher3.widget.WidgetsListAdapter#setWidgets(ArrayList) + */ + public synchronized ArrayList getWidgetsList(Context context) { + ArrayList result = new ArrayList<>(); + AlphabeticIndexCompat indexer = new AlphabeticIndexCompat(context); + + WidgetItemComparator widgetComparator = new WidgetItemComparator(); + for (Map.Entry> entry : mWidgetsList.entrySet()) { + WidgetListRowEntry row = new WidgetListRowEntry(entry.getKey(), entry.getValue()); + row.titleSectionName = indexer.computeSectionName(row.pkgItem.title); + Collections.sort(row.widgets, widgetComparator); + result.add(row); + } + return result; + } + + /** + * @param packageUser If null, all widgets and shortcuts are updated and returned, otherwise + * only widgets and shortcuts associated with the package/user are. + */ + public List update(LauncherAppState app, @Nullable PackageUserKey packageUser) { + Preconditions.assertWorkerThread(); + + Context context = app.getContext(); + final ArrayList widgetsAndShortcuts = new ArrayList<>(); + List updatedItems = new ArrayList<>(); + try { + InvariantDeviceProfile idp = app.getInvariantDeviceProfile(); + PackageManager pm = app.getContext().getPackageManager(); + + // Widgets + AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(context); + for (AppWidgetProviderInfo widgetInfo : widgetManager.getAllProviders(packageUser)) { + LauncherAppWidgetProviderInfo launcherWidgetInfo = + LauncherAppWidgetProviderInfo.fromProviderInfo(context, widgetInfo); + + widgetsAndShortcuts.add(new WidgetItem( + launcherWidgetInfo, idp, app.getIconCache())); + updatedItems.add(launcherWidgetInfo); + } + + // Shortcuts + for (ShortcutConfigActivityInfo info : LauncherAppsCompat.getInstance(context) + .getCustomShortcutActivityList(packageUser)) { + widgetsAndShortcuts.add(new WidgetItem(info, app.getIconCache(), pm)); + updatedItems.add(info); + } + setWidgetsAndShortcuts(widgetsAndShortcuts, app, packageUser); + } catch (Exception e) { + if (!FeatureFlags.IS_DOGFOOD_BUILD && Utilities.isBinderSizeError(e)) { + // the returned value may be incomplete and will not be refreshed until the next + // time Launcher starts. + // TODO: after figuring out a repro step, introduce a dirty bit to check when + // onResume is called to refresh the widget provider list. + } else { + throw e; + } + } + + app.getWidgetCache().removeObsoletePreviews(widgetsAndShortcuts, packageUser); + return updatedItems; + } + + private synchronized void setWidgetsAndShortcuts(ArrayList rawWidgetsShortcuts, + LauncherAppState app, @Nullable PackageUserKey packageUser) { + if (DEBUG) { + Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size()); + } + + // Temporary list for {@link PackageItemInfos} to avoid having to go through + // {@link mPackageItemInfos} to locate the key to be used for {@link #mWidgetsList} + HashMap tmpPackageItemInfos = new HashMap<>(); + + // clear the lists. + if (packageUser == null) { + mWidgetsList.clear(); + } else { + // Only clear the widgets for the given package/user. + PackageItemInfo packageItem = null; + for (PackageItemInfo item : mWidgetsList.keySet()) { + if (item.packageName.equals(packageUser.mPackageName)) { + packageItem = item; + break; + } + } + if (packageItem != null) { + // We want to preserve the user that was on the packageItem previously, + // so add it to tmpPackageItemInfos here to avoid creating a new entry. + tmpPackageItemInfos.put(packageItem.packageName, packageItem); + + Iterator widgetItemIterator = mWidgetsList.get(packageItem).iterator(); + while (widgetItemIterator.hasNext()) { + WidgetItem nextWidget = widgetItemIterator.next(); + if (nextWidget.componentName.getPackageName().equals(packageUser.mPackageName) + && nextWidget.user.equals(packageUser.mUser)) { + widgetItemIterator.remove(); + } + } + } + } + + InvariantDeviceProfile idp = app.getInvariantDeviceProfile(); + UserHandle myUser = Process.myUserHandle(); + + // add and update. + for (WidgetItem item : rawWidgetsShortcuts) { + if (item.widgetInfo != null) { + if ((item.widgetInfo.getWidgetFeatures() & WIDGET_FEATURE_HIDE_FROM_PICKER) != 0) { + // Widget is hidden from picker + continue; + } + + // Ensure that all widgets we show can be added on a workspace of this size + int minSpanX = Math.min(item.widgetInfo.spanX, item.widgetInfo.minSpanX); + int minSpanY = Math.min(item.widgetInfo.spanY, item.widgetInfo.minSpanY); + if (minSpanX > idp.numColumns || minSpanY > idp.numRows) { + if (DEBUG) { + Log.d(TAG, String.format( + "Widget %s : (%d X %d) can't fit on this device", + item.componentName, minSpanX, minSpanY)); + } + continue; + } + } + + if (mAppFilter == null) { + mAppFilter = AppFilter.newInstance(app.getContext()); + } + if (!mAppFilter.shouldShowApp(item.componentName)) { + if (DEBUG) { + Log.d(TAG, String.format("%s is filtered and not added to the widget tray.", + item.componentName)); + } + continue; + } + + String packageName = item.componentName.getPackageName(); + PackageItemInfo pInfo = tmpPackageItemInfos.get(packageName); + if (pInfo == null) { + pInfo = new PackageItemInfo(packageName); + pInfo.user = item.user; + tmpPackageItemInfos.put(packageName, pInfo); + } else if (!myUser.equals(pInfo.user)) { + // Keep updating the user, until we get the primary user. + pInfo.user = item.user; + } + mWidgetsList.addToList(pInfo, item); + } + + // Update each package entry + IconCache iconCache = app.getIconCache(); + for (PackageItemInfo p : tmpPackageItemInfos.values()) { + iconCache.getTitleAndIconForApp(p, true /* userLowResIcon */); + } + } + + public void onPackageIconsUpdated(Set packageNames, UserHandle user, + LauncherAppState app) { + for (Entry> entry : mWidgetsList.entrySet()) { + if (packageNames.contains(entry.getKey().packageName)) { + ArrayList items = entry.getValue(); + int count = items.size(); + for (int i = 0; i < count; i++) { + WidgetItem item = items.get(i); + if (item.user.equals(user)) { + if (item.activityInfo != null) { + items.set(i, new WidgetItem(item.activityInfo, app.getIconCache(), + app.getContext().getPackageManager())); + } else { + items.set(i, new WidgetItem(item.widgetInfo, + app.getInvariantDeviceProfile(), app.getIconCache())); + } + } + } + } + } + } +} \ No newline at end of file -- cgit v1.2.3