Android14系统go版添加微件功能

一般normal版软件自带微件功能,但是go版没有这个功能,但是客户有时会要求也要加上这个微件功能,实现的方法修改如下:

  1. frameworks/base
java 复制代码
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 24b3fdf64b0f..d805ff07871a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4191,7 +4191,7 @@
 
     <!-- True if the device requires AppWidgetService even if it does not have
          the PackageManager.FEATURE_APP_WIDGETS feature -->
-    <bool name="config_enableAppWidgetService">false</bool>
+    <bool name="config_enableAppWidgetService">true</bool>
 
     <!-- True if the device supports Sustained Performance Mode-->
     <bool name="config_sustainedPerformanceModeSupported">false</bool>
  1. frameworks/native
java 复制代码
diff --git a/data/etc/go_handheld_core_hardware.xml b/data/etc/go_handheld_core_hardware.xml
index ee829728c8..23077cbc82 100644
--- a/data/etc/go_handheld_core_hardware.xml
+++ b/data/etc/go_handheld_core_hardware.xml
@@ -36,6 +36,7 @@
     <feature name="android.hardware.security.model.compatible" />
 
     <!-- basic system services -->
+    <feature name="android.software.app_widgets" />
     <feature name="android.software.telecom" />
     <feature name="android.software.backup" />
     <feature name="android.software.home_screen" />
  1. packages/apps/Launcher3
java 复制代码
diff --git a/go/src/com/android/launcher3/model/LauncherBinder.java b/go/src/com/android/launcher3/model/LauncherBinder.java
index 437d8caf94..66d9db0c67 100644
--- a/go/src/com/android/launcher3/model/LauncherBinder.java
+++ b/go/src/com/android/launcher3/model/LauncherBinder.java
@@ -20,6 +20,11 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.model.BgDataModel.Callbacks;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.widget.model.WidgetsListBaseEntry;
+
+import java.util.HashMap;
+import java.util.List;
 
 /**
  * Binds the results of {@link com.android.launcher3.model.LoaderTask} to the Callbacks objects.
@@ -33,9 +38,17 @@ public class LauncherBinder extends BaseLauncherBinder {
 
     @Override
     public void bindDeepShortcuts() {
+        final HashMap<ComponentKey, Integer> shortcutMapCopy;
+        synchronized (mBgDataModel) {
+            shortcutMapCopy = new HashMap<>(mBgDataModel.deepShortcutMap);
+        }
+        executeCallbacksTask(c -> c.bindDeepShortcutMap(shortcutMapCopy), mUiExecutor);
     }
 
     @Override
     public void bindWidgets() {
+        final List<WidgetsListBaseEntry> widgets =
+                mBgDataModel.widgetsModel.getWidgetsListForPicker(mApp.getContext());
+        executeCallbacksTask(c -> c.bindAllWidgets(widgets), mUiExecutor);
     }
 }
diff --git a/go/src/com/android/launcher3/model/WidgetsModel.java b/go/src/com/android/launcher3/model/WidgetsModel.java
index 1aa5d03f6d..75df5e5787 100644
--- a/go/src/com/android/launcher3/model/WidgetsModel.java
+++ b/go/src/com/android/launcher3/model/WidgetsModel.java
@@ -16,23 +16,57 @@
 
 package com.android.launcher3.model;
 
+import static android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_HIDE_FROM_PICKER;
+
+import static com.android.launcher3.pm.ShortcutConfigActivityInfo.queryList;
+import static com.android.launcher3.widget.WidgetSections.NO_CATEGORY;
+
+import static java.util.stream.Collectors.groupingBy;
+import static java.util.stream.Collectors.mapping;
+import static java.util.stream.Collectors.toList;
+
+import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.UserHandle;
+import android.util.Log;
+import android.util.Pair;
 
 import androidx.annotation.Nullable;
+import androidx.collection.ArrayMap;
 
+import com.android.launcher3.AppFilter;
+import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.AlphabeticIndexCompat;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.icons.ComponentWithLabelAndIcon;
+import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.model.data.PackageItemInfo;
+import com.android.launcher3.pm.ShortcutConfigActivityInfo;
+import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.widget.WidgetManagerHelper;
+import com.android.launcher3.widget.WidgetSections;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
+import com.android.launcher3.widget.model.WidgetsListContentEntry;
+import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 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 java.util.function.Predicate;
 
 /**
  * Widgets data model that is used by the adapters of the widget views and controllers.
@@ -42,10 +76,14 @@ import java.util.Set;
 public class WidgetsModel {
 
     // True is the widget support is disabled.
-    public static final boolean GO_DISABLE_WIDGETS = true;
-    public static final boolean GO_DISABLE_NOTIFICATION_DOTS = true;
+    public static final boolean GO_DISABLE_WIDGETS = false;
+    public static final boolean GO_DISABLE_NOTIFICATION_DOTS = false;
+
+    private static final String TAG = "WidgetsModel";
+    private static final boolean DEBUG = false;
 
-    private static final ArrayList<WidgetsListBaseEntry> EMPTY_WIDGET_LIST = new ArrayList<>();
+    /* Map of widgets and shortcuts that are tracked per package. */
+    private final Map<PackageItemInfo, List<WidgetItem>> mWidgetsList = new HashMap<>();
 
     /**
      * Returns a list of {@link WidgetsListBaseEntry}. All {@link WidgetItem} in a single row are
@@ -56,36 +94,246 @@ public class WidgetsModel {
      * @see com.android.launcher3.widget.picker.WidgetsListAdapter#setWidgets(List)
      */
     public synchronized ArrayList<WidgetsListBaseEntry> getWidgetsListForPicker(Context context) {
-        return EMPTY_WIDGET_LIST;
+        ArrayList<WidgetsListBaseEntry> result = new ArrayList<>();
+        AlphabeticIndexCompat indexer = new AlphabeticIndexCompat(context);
+
+        for (Map.Entry<PackageItemInfo, List<WidgetItem>> entry : mWidgetsList.entrySet()) {
+            PackageItemInfo pkgItem = entry.getKey();
+            List<WidgetItem> widgetItems = entry.getValue();
+            String sectionName = (pkgItem.title == null) ? "" :
+                    indexer.computeSectionName(pkgItem.title);
+            result.add(WidgetsListHeaderEntry.create(pkgItem, sectionName, widgetItems));
+            result.add(new WidgetsListContentEntry(pkgItem, sectionName, widgetItems));
+        }
+        return result;
     }
 
     /** Returns a mapping of packages to their widgets without static shortcuts. */
     public synchronized Map<PackageUserKey, List<WidgetItem>> getAllWidgetsWithoutShortcuts() {
-        return Map.of();
+        Map<PackageUserKey, List<WidgetItem>> packagesToWidgets = new HashMap<>();
+        mWidgetsList.forEach((packageItemInfo, widgetsAndShortcuts) -> {
+            List<WidgetItem> widgets = widgetsAndShortcuts.stream()
+                        .filter(item -> item.widgetInfo != null)
+                        .collect(toList());
+            if (widgets.size() > 0) {
+                packagesToWidgets.put(
+                        new PackageUserKey(packageItemInfo.packageName, packageItemInfo.user),
+                        widgets);
+            }
+        });
+        return packagesToWidgets;
     }
 
     /**
      * @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<ComponentWithLabelAndIcon> update(LauncherAppState app,
-            @Nullable PackageUserKey packageUser) {
-        return Collections.emptyList();
+    public List<ComponentWithLabelAndIcon> update(
+            LauncherAppState app, @Nullable PackageUserKey packageUser) {
+        Preconditions.assertWorkerThread();
+
+        Context context = app.getContext();
+        final ArrayList<WidgetItem> widgetsAndShortcuts = new ArrayList<>();
+        List<ComponentWithLabelAndIcon> updatedItems = new ArrayList<>();
+        try {
+            InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
+            PackageManager pm = app.getContext().getPackageManager();
+
+            // Widgets
+            WidgetManagerHelper widgetManager = new WidgetManagerHelper(context);
+            for (AppWidgetProviderInfo widgetInfo : widgetManager.getAllProviders(packageUser)) {
+                LauncherAppWidgetProviderInfo launcherWidgetInfo =
+                        LauncherAppWidgetProviderInfo.fromProviderInfo(context, widgetInfo);
+
+                widgetsAndShortcuts.add(new WidgetItem(
+                        launcherWidgetInfo, idp, app.getIconCache(), app.getContext()));
+                updatedItems.add(launcherWidgetInfo);
+            }
+
+            // Shortcuts
+            for (ShortcutConfigActivityInfo info :
+                    queryList(context, packageUser)) {
+                widgetsAndShortcuts.add(new WidgetItem(info, app.getIconCache(), pm));
+                updatedItems.add(info);
+            }
+            setWidgetsAndShortcuts(widgetsAndShortcuts, app, packageUser);
+        } catch (Exception e) {
+            if (!FeatureFlags.IS_STUDIO_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;
+            }
+        }
+
+        return updatedItems;
     }
 
+    private synchronized void setWidgetsAndShortcuts(ArrayList<WidgetItem> rawWidgetsShortcuts,
+            LauncherAppState app, @Nullable PackageUserKey packageUser) {
+        if (DEBUG) {
+            Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size());
+        }
+
+        // Temporary cache for {@link PackageItemInfos} to avoid having to go through
+        // {@link mPackageItemInfos} to locate the key to be used for {@link #mWidgetsList}
+        PackageItemInfoCache packageItemInfoCache = new PackageItemInfoCache();
+
+        if (packageUser == null) {
+            // Clear the list if this is an update on all widgets and shortcuts.
+            mWidgetsList.clear();
+        } else {
+            // Otherwise, only clear the widgets and shortcuts for the changed package.
+            mWidgetsList.remove(packageItemInfoCache.getOrCreate(packageUser));
+        }
+
+        // add and update.
+        mWidgetsList.putAll(rawWidgetsShortcuts.stream()
+                .filter(new WidgetValidityCheck(app))
+                .flatMap(widgetItem -> getPackageUserKeys(app.getContext(), widgetItem).stream()
+                        .map(key -> new Pair<>(packageItemInfoCache.getOrCreate(key), widgetItem)))
+                .collect(groupingBy(pair -> pair.first, mapping(pair -> pair.second, toList()))));
+
+        // Update each package entry
+        IconCache iconCache = app.getIconCache();
+        for (PackageItemInfo p : packageItemInfoCache.values()) {
+            iconCache.getTitleAndIconForApp(p, true /* userLowResIcon */);
+        }
+    }
 
     public void onPackageIconsUpdated(Set<String> packageNames, UserHandle user,
             LauncherAppState app) {
+        for (Entry<PackageItemInfo, List<WidgetItem>> entry : mWidgetsList.entrySet()) {
+            if (packageNames.contains(entry.getKey().packageName)) {
+                List<WidgetItem> 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(),
+                                    app.getContext()));
+                        }
+                    }
+                }
+            }
+        }
     }
 
     public WidgetItem getWidgetProviderInfoByProviderName(
             ComponentName providerName, UserHandle user) {
+        List<WidgetItem> widgetsList = mWidgetsList.get(
+                new PackageItemInfo(providerName.getPackageName(), user));
+        if (widgetsList == null) {
+            return null;
+        }
+
+        for (WidgetItem item : widgetsList) {
+            if (item.componentName.equals(providerName)) {
+                return item;
+            }
+        }
         return null;
     }
 
     /** Returns {@link PackageItemInfo} of a pending widget. */
-    public static PackageItemInfo newPendingItemInfo(
-            Context context, ComponentName provider, UserHandle userHandle) {
-        return new PackageItemInfo(provider.getPackageName(), userHandle);
+    public static PackageItemInfo newPendingItemInfo(Context context, ComponentName provider,
+            UserHandle user) {
+        Map<ComponentName, IntSet> widgetsToCategories =
+                WidgetSections.getWidgetsToCategory(context);
+        if (widgetsToCategories.containsKey(provider)) {
+            Iterator<Integer> categoriesIterator = widgetsToCategories.get(provider).iterator();
+            int firstCategory = NO_CATEGORY;
+            while (categoriesIterator.hasNext() && firstCategory == NO_CATEGORY) {
+                firstCategory = categoriesIterator.next();
+            }
+            return new PackageItemInfo(provider.getPackageName(), firstCategory, user);
+        }
+        return new PackageItemInfo(provider.getPackageName(), user);
+    }
+
+    private List<PackageUserKey> getPackageUserKeys(Context context, WidgetItem item) {
+        Map<ComponentName, IntSet> widgetsToCategories =
+                WidgetSections.getWidgetsToCategory(context);
+        IntSet categories = widgetsToCategories.get(item.componentName);
+        if (categories == null || categories.isEmpty()) {
+            return Arrays.asList(
+                    new PackageUserKey(item.componentName.getPackageName(), item.user));
+        }
+        List<PackageUserKey> packageUserKeys = new ArrayList<>();
+        categories.forEach(category -> {
+            if (category == NO_CATEGORY) {
+                packageUserKeys.add(
+                        new PackageUserKey(item.componentName.getPackageName(),
+                                item.user));
+            } else {
+                packageUserKeys.add(new PackageUserKey(category, item.user));
+            }
+        });
+        return packageUserKeys;
+    }
+
+    private static class WidgetValidityCheck implements Predicate<WidgetItem> {
+
+        private final InvariantDeviceProfile mIdp;
+        private final AppFilter mAppFilter;
+
+        WidgetValidityCheck(LauncherAppState app) {
+            mIdp = app.getInvariantDeviceProfile();
+            mAppFilter = new AppFilter(app.getContext());
+        }
+
+        @Override
+        public boolean test(WidgetItem item) {
+            if (item.widgetInfo != null) {
+                if ((item.widgetInfo.getWidgetFeatures() & WIDGET_FEATURE_HIDE_FROM_PICKER) != 0) {
+                    // Widget is hidden from picker
+                    return false;
+                }
+
+                // Ensure that all widgets we show can be added on a workspace of this size
+                if (!item.widgetInfo.isMinSizeFulfilled()) {
+                    if (DEBUG) {
+                        Log.d(TAG, String.format(
+                                "Widget %s : can't fit on this device with a grid size: %dx%d",
+                                item.componentName, mIdp.numColumns, mIdp.numRows));
+                    }
+                    return false;
+                }
+            }
+            if (!mAppFilter.shouldShowApp(item.componentName)) {
+                if (DEBUG) {
+                    Log.d(TAG, String.format("%s is filtered and not added to the widget tray.",
+                            item.componentName));
+                }
+                return false;
+            }
+
+            return true;
+        }
+    }
+
+    private static final class PackageItemInfoCache {
+        private final Map<PackageUserKey, PackageItemInfo> mMap = new ArrayMap<>();
+
+        PackageItemInfo getOrCreate(PackageUserKey key) {
+            PackageItemInfo pInfo = mMap.get(key);
+            if (pInfo == null) {
+                pInfo = new PackageItemInfo(key.mPackageName, key.mWidgetCategory, key.mUser);
+                pInfo.user = key.mUser;
+                mMap.put(key,  pInfo);
+            }
+            return pInfo;
+        }
+
+        Collection<PackageItemInfo> values() {
+            return mMap.values();
+        }
     }
 }
\ No newline at end of file
相关推荐
方圆想当图灵18 分钟前
缓存之美:万文详解 Caffeine 实现原理(下)
java·redis·缓存
栗豆包32 分钟前
w175基于springboot的图书管理系统的设计与实现
java·spring boot·后端·spring·tomcat
xvch35 分钟前
Kotlin 2.1.0 入门教程(七)
android·kotlin
望风的懒蜗牛1 小时前
编译Android平台使用的FFmpeg库
android
等一场春雨1 小时前
Java设计模式 十四 行为型模式 (Behavioral Patterns)
java·开发语言·设计模式
浩宇软件开发1 小时前
Android开发,待办事项提醒App的设计与实现(个人中心页)
android·android studio·android开发
ac-er88882 小时前
Yii框架中的多语言支持:如何实现国际化
android·开发语言·php
酱学编程2 小时前
java中的单元测试的使用以及原理
java·单元测试·log4j
我的运维人生2 小时前
Java并发编程深度解析:从理论到实践
java·开发语言·python·运维开发·技术共享
一只爱吃“兔子”的“胡萝卜”3 小时前
2.Spring-AOP
java·后端·spring