Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fedc18e9 authored by Willie Koomson's avatar Willie Koomson
Browse files

Use generated RemoteViews preview for widget picker if available

WidgetCell will use the generated RemoteViews preview to display
previews in the widget picker. It will fallback to current preview
methods if not available.

Introduces WidgetManagerHelper.loadGeneratedPreviews as a utility
function. WidgetManagerHelper is passed into the constructor of
WidgetItem to avoid calling
context.getSystemService(AppWidgetManager.class) for each widget.

Bug: 308041327
Test: atest Launcher3Tests:GeneratedPreviewTest
Flag: ACONFIG com.android.launcher3.enable_generated_previews DEVELOPMENT
Change-Id: I37429057cda83a5321884ace2537038e050b9a58
parent b2f38376
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -202,6 +202,7 @@ android_library {
        "animationlib",
        "com_android_launcher3_flags_lib",
        "com_android_wm_shell_flags_lib",
        "android.appwidget.flags-aconfig-java",
    ],
    sdk_version: "current",
    min_sdk_version: min_launcher3_sdk_version,
+7 −0
Original line number Diff line number Diff line
@@ -141,6 +141,13 @@ flag {
    bug: "297057373"
}

flag {
    name: "enable_generated_previews"
    namespace: "launcher"
    description: "Enables support for RemoteViews previews in the widget picker."
    bug: "306546610"
}

flag {
  name: "enable_categorized_widget_suggestions"
  namespace: "launcher"
+46 −1
Original line number Diff line number Diff line
package com.android.launcher3.model;

import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN;
import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD;
import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX;

import static com.android.launcher3.Utilities.ATLEAST_S;

import android.annotation.SuppressLint;
@@ -7,13 +11,19 @@ import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.util.SparseArray;
import android.widget.RemoteViews;

import androidx.core.os.BuildCompat;

import com.android.launcher3.Flags;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.pm.ShortcutConfigActivityInfo;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetManagerHelper;

/**
 * An wrapper over various items displayed in a widget picker,
@@ -28,9 +38,11 @@ public class WidgetItem extends ComponentKey {
    public final String label;
    public final CharSequence description;
    public final int spanX, spanY;
    public final SparseArray<RemoteViews> generatedPreviews;

    public WidgetItem(LauncherAppWidgetProviderInfo info,
            InvariantDeviceProfile idp, IconCache iconCache, Context context) {
            InvariantDeviceProfile idp, IconCache iconCache, Context context,
            WidgetManagerHelper helper) {
        super(info.provider, info.getProfile());

        label = iconCache.getTitleNoCache(info);
@@ -40,6 +52,27 @@ public class WidgetItem extends ComponentKey {

        spanX = Math.min(info.spanX, idp.numColumns);
        spanY = Math.min(info.spanY, idp.numRows);

        if (BuildCompat.isAtLeastV() && Flags.enableGeneratedPreviews()) {
            generatedPreviews = new SparseArray<>(3);
            for (int widgetCategory : new int[] {
                    WIDGET_CATEGORY_HOME_SCREEN,
                    WIDGET_CATEGORY_KEYGUARD,
                    WIDGET_CATEGORY_SEARCHBOX,
            }) {
                if ((widgetCategory & widgetInfo.generatedPreviewCategories) != 0) {
                    generatedPreviews.put(widgetCategory,
                            helper.loadGeneratedPreview(widgetInfo, widgetCategory));
                }
            }
        } else {
            generatedPreviews = null;
        }
    }

    public WidgetItem(LauncherAppWidgetProviderInfo info,
            InvariantDeviceProfile idp, IconCache iconCache, Context context) {
        this(info, idp, iconCache, context, new WidgetManagerHelper(context));
    }

    public WidgetItem(ShortcutConfigActivityInfo info, IconCache iconCache, PackageManager pm) {
@@ -50,6 +83,7 @@ public class WidgetItem extends ComponentKey {
        widgetInfo = null;
        activityInfo = info;
        spanX = spanY = 1;
        generatedPreviews = null;
    }

    /**
@@ -78,4 +112,15 @@ public class WidgetItem extends ComponentKey {
    public boolean isShortcut() {
        return activityInfo != null;
    }

    /**
     * Returns whether this {@link WidgetItem} has a generated preview for the given widget
     * category.
     */
    public boolean hasGeneratedPreview(int widgetCategory) {
        if (!Flags.enableGeneratedPreviews() || generatedPreviews == null) {
            return false;
        }
        return generatedPreviews.contains(widgetCategory);
    }
}
+8 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.launcher3.widget;

import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN;

import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
import static com.android.launcher3.widget.LauncherAppWidgetProviderInfo.fromProviderInfo;
import static com.android.launcher3.widget.util.WidgetSizes.getWidgetItemSizePx;
@@ -44,6 +46,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.launcher3.CheckLongPressHelper;
import com.android.launcher3.Flags;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.icons.FastBitmapDrawable;
@@ -241,6 +244,11 @@ public class WidgetCell extends LinearLayout {
            mAppWidgetHostViewPreview = createAppWidgetHostView(context);
            setAppWidgetHostViewPreview(mAppWidgetHostViewPreview, item.widgetInfo,
                    mRemoteViewsPreview);
        } else if (Flags.enableGeneratedPreviews()
                && item.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)) {
            mAppWidgetHostViewPreview = createAppWidgetHostView(context);
            setAppWidgetHostViewPreview(mAppWidgetHostViewPreview, item.widgetInfo,
                    item.generatedPreviews.get(WIDGET_CATEGORY_HOME_SCREEN));
        } else if (item.hasPreviewLayout()) {
            // If the context is a Launcher activity, DragView will show mAppWidgetHostViewPreview
            // as a preview during drag & drop. And thus, we should use LauncherAppWidgetHostView,
+20 −0
Original line number Diff line number Diff line
@@ -24,8 +24,11 @@ import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.UserHandle;
import android.widget.RemoteViews;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -130,6 +133,23 @@ public class WidgetManagerHelper {
                appWidgetId).getBoolean(WIDGET_OPTION_RESTORE_COMPLETED);
    }


    /**
     * Load RemoteViews preview for this provider if available.
     *
     * @param info The provider info for the widget you want to preview.
     * @param widgetCategory The widget category for which you want to display previews.
     *
     * @return Returns the widget preview that matches selected category, if available.
     */
    @Nullable
    @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
    public RemoteViews loadGeneratedPreview(@NonNull AppWidgetProviderInfo info,
            int widgetCategory) {
        if (!android.appwidget.flags.Flags.generatedPreviews()) return null;
        return mAppWidgetManager.getWidgetPreview(info.provider, info.getProfile(), widgetCategory);
    }

    private static Stream<AppWidgetProviderInfo> allWidgetsSteam(Context context) {
        AppWidgetManager awm = context.getSystemService(AppWidgetManager.class);
        return Stream.concat(
Loading