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

Commit 54bd36ef authored by Shamali P's avatar Shamali P
Browse files

Move out picker related methods from widgets model

* The WidgetsBaseEntry and related types are specific to picker UI.
So, moved them to a entry builder class.

Bug: 353347512
Flag: EXEMPT BUGFIX
Test: Unit test
Change-Id: I42b3083b42ee03dc8d548e7464689ea270a36f22
parent 1407aeca
Loading
Loading
Loading
Loading
+21 −26
Original line number Diff line number Diff line
@@ -47,11 +47,11 @@ import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.WidgetPredictionsRequester;
import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.widget.WidgetCell;
import com.android.launcher3.widget.model.WidgetsListBaseEntriesBuilder;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.picker.WidgetsFullSheet;

import java.util.ArrayList;
@@ -60,10 +60,8 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/** An Activity that can host Launcher's widget picker. */
public class WidgetPickerActivity extends BaseActivity {
@@ -112,7 +110,8 @@ public class WidgetPickerActivity extends BaseActivity {
    private WidgetsModel mModel;
    private LauncherAppState mApp;
    private WidgetPredictionsRequester mWidgetPredictionsRequester;
    private final PopupDataProvider mPopupDataProvider = new PopupDataProvider(i -> {});
    private final PopupDataProvider mPopupDataProvider = new PopupDataProvider(i -> {
    });

    private int mDesiredWidgetWidth;
    private int mDesiredWidgetHeight;
@@ -287,41 +286,37 @@ public class WidgetPickerActivity extends BaseActivity {
        };
    }

    /** Updates the model with widgets, applies filters and launches the widgets sheet once
     * widgets are available */
    /**
     * Updates the model with widgets, applies filters and launches the widgets sheet once
     * widgets are available
     */
    private void refreshAndBindWidgets() {
        MODEL_EXECUTOR.execute(() -> {
            LauncherAppState app = LauncherAppState.getInstance(this);
            Context context = app.getContext();

            mModel.update(app, null);
            final List<WidgetsListBaseEntry> allWidgets =
                    mModel.getFilteredWidgetsListForPicker(context, mWidgetsFilter);
            final List<WidgetsListBaseEntry> defaultWidgets =
                    shouldShowDefaultWidgets() ? mModel.getFilteredWidgetsListForPicker(context,
                            mDefaultWidgetsFilter) : List.of();
            bindWidgets(allWidgets, defaultWidgets);
            bindWidgets(mModel.getWidgetsByPackageItem());
            // Open sheet once widgets are available, so that it doesn't interrupt the open
            // animation.
            openWidgetsSheet();
            if (mUiSurface != null) {
                Map<ComponentKey, WidgetItem> allWidgetItems = allWidgets.stream()
                        .filter(entry -> entry instanceof WidgetsListContentEntry)
                        .flatMap(entry -> entry.mWidgets.stream())
                        .distinct()
                        .collect(Collectors.toMap(
                                widget -> new ComponentKey(widget.componentName, widget.user),
                                Function.identity()
                        ));
                mWidgetPredictionsRequester = new WidgetPredictionsRequester(app.getContext(),
                        mUiSurface, allWidgetItems);
                        mUiSurface, mModel.getWidgetsByComponentKey());
                mWidgetPredictionsRequester.request(mAddedWidgets, this::bindRecommendedWidgets);
            }
        });
    }

    private void bindWidgets(List<WidgetsListBaseEntry> allWidgets,
            List<WidgetsListBaseEntry> defaultWidgets) {
    private void bindWidgets(Map<PackageItemInfo, List<WidgetItem>> widgets) {
        WidgetsListBaseEntriesBuilder builder = new WidgetsListBaseEntriesBuilder(
                mApp.getContext());

        final List<WidgetsListBaseEntry> allWidgets = builder.build(widgets, mWidgetsFilter);
        final List<WidgetsListBaseEntry> defaultWidgets =
                shouldShowDefaultWidgets() ? builder.build(widgets,
                        mDefaultWidgetsFilter) : List.of();

        MAIN_EXECUTOR.execute(() -> mPopupDataProvider.setAllWidgets(allWidgets, defaultWidgets));
    }

@@ -392,7 +387,7 @@ public class WidgetPickerActivity extends BaseActivity {
            mActiveOnBackAnimationCallback.onBackCancelled();
            mActiveOnBackAnimationCallback = null;
        }
    };
    }

    private boolean shouldShowDefaultWidgets() {
        // If optional filters such as size filter are present, we display them as default widgets.
+3 −2
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.LooperIdleLock;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.widget.model.WidgetsListBaseEntriesBuilder;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;

import java.util.ArrayList;
@@ -195,8 +196,8 @@ public class BaseLauncherBinder {
        if (!WIDGETS_ENABLED) {
            return;
        }
        final List<WidgetsListBaseEntry> widgets =
                mBgDataModel.widgetsModel.getWidgetsListForPicker(mApp.getContext());
        List<WidgetsListBaseEntry> widgets = new WidgetsListBaseEntriesBuilder(mApp.getContext())
                .build(mBgDataModel.widgetsModel.getWidgetsByPackageItem());
        executeCallbacksTask(c -> c.bindAllWidgets(widgets), mUiExecutor);
    }

+4 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import com.android.launcher3.model.BgDataModel.FixedContainerItems
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.util.PackageUserKey
import com.android.launcher3.widget.model.WidgetsListBaseEntriesBuilder
import java.util.Objects
import java.util.concurrent.Executor
import java.util.function.Predicate
@@ -78,7 +79,9 @@ class ModelTaskController(
    }

    fun bindUpdatedWidgets(dataModel: BgDataModel) {
        val widgets = dataModel.widgetsModel.getWidgetsListForPicker(app.context)
        val widgets =
            WidgetsListBaseEntriesBuilder(app.context)
                .build(dataModel.widgetsModel.widgetsByPackageItem)
        scheduleCallbackTask { it.bindAllWidgets(widgets) }
    }

+5 −47
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ 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;
@@ -39,9 +38,6 @@ 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 com.android.wm.shell.Flags;

import java.util.ArrayList;
@@ -75,6 +71,9 @@ public class WidgetsModel {
     * Returns all widgets keyed by their component key.
     */
    public synchronized Map<ComponentKey, WidgetItem> getWidgetsByComponentKey() {
        if (!WIDGETS_ENABLED) {
            return Collections.emptyMap();
        }
        return mWidgetsByPackageItem.values().stream()
                .flatMap(Collection::stream).distinct()
                .collect(Collectors.toMap(
@@ -87,51 +86,10 @@ public class WidgetsModel {
     * Returns widgets grouped by the package item that they should belong to.
     */
    public synchronized Map<PackageItemInfo, List<WidgetItem>> getWidgetsByPackageItem() {
        return mWidgetsByPackageItem;
    }

    /**
     * Returns a list of {@link WidgetsListBaseEntry} filtered using given widget item filter. All
     * {@link WidgetItem}s in a single row are sorted (based on label and user), but the overall
     * list of {@link WidgetsListBaseEntry}s is not sorted.
     *
     * @see com.android.launcher3.widget.picker.WidgetsListAdapter#setWidgets(List)
     */
    public synchronized ArrayList<WidgetsListBaseEntry> getFilteredWidgetsListForPicker(
            Context context,
            Predicate<WidgetItem> widgetItemFilter) {
        if (!WIDGETS_ENABLED) {
            return new ArrayList<>();
            return Collections.emptyMap();
        }
        ArrayList<WidgetsListBaseEntry> result = new ArrayList<>();
        AlphabeticIndexCompat indexer = new AlphabeticIndexCompat(context);

        for (Map.Entry<PackageItemInfo, List<WidgetItem>> entry :
                mWidgetsByPackageItem.entrySet()) {
            PackageItemInfo pkgItem = entry.getKey();
            List<WidgetItem> widgetItems = entry.getValue()
                    .stream()
                    .filter(widgetItemFilter).toList();
            if (!widgetItems.isEmpty()) {
                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 list of {@link WidgetsListBaseEntry}. All {@link WidgetItem} in a single row
     * are sorted (based on label and user), but the overall list of
     * {@link WidgetsListBaseEntry}s is not sorted.
     *
     * @see com.android.launcher3.widget.picker.WidgetsListAdapter#setWidgets(List)
     */
    public synchronized ArrayList<WidgetsListBaseEntry> getWidgetsListForPicker(Context context) {
        // return all items
        return getFilteredWidgetsListForPicker(context, /*widgetItemFilter=*/ item -> true);
        return mWidgetsByPackageItem;
    }

    /**
+51 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.launcher3.widget.model

import android.content.Context
import com.android.launcher3.compat.AlphabeticIndexCompat
import com.android.launcher3.model.WidgetItem
import com.android.launcher3.model.data.PackageItemInfo
import java.util.function.Predicate

/**
 * A helper class that builds the list of [WidgetsListBaseEntry]s used by the UI to display widgets.
 */
class WidgetsListBaseEntriesBuilder(val context: Context) {

    /** Builds the widgets list entries in a format understandable by the widget picking UI. */
    @JvmOverloads
    fun build(
        widgetsByPackageItem: Map<PackageItemInfo, List<WidgetItem>>,
        widgetFilter: Predicate<WidgetItem> = Predicate<WidgetItem> { true },
    ): List<WidgetsListBaseEntry> {
        val indexer = AlphabeticIndexCompat(context)

        return buildList {
            for ((pkgItem, widgetItems) in widgetsByPackageItem.entries) {
                val filteredWidgetItems = widgetItems.filter { widgetFilter.test(it) }
                if (filteredWidgetItems.isNotEmpty()) {
                    // Enables fast scroll popup to show right characters in all locales.
                    val sectionName = pkgItem.title?.let { indexer.computeSectionName(it) } ?: ""

                    add(WidgetsListHeaderEntry.create(pkgItem, sectionName, filteredWidgetItems))
                    add(WidgetsListContentEntry(pkgItem, sectionName, filteredWidgetItems))
                }
            }
        }
    }
}
Loading