Search in sources :

Example 11 with WIDGETS

use of com.android.launcher3.popup.SystemShortcut.WIDGETS in project android_packages_apps_Launcher3 by crdroidandroid.

the class WidgetsTableUtils method groupWidgetItemsIntoTable.

/**
 * Groups widgets items into a 2D array which matches their appearance in a UI table.
 *
 * <p>Grouping:
 * 1. Widgets and shortcuts never group together in the same row.
 * 2. The ordered widgets are grouped together in the same row until their total horizontal
 *    spans exceed the {@code maxSpansPerRow} - 1.
 * 3. The order shortcuts are grouped together in the same row until their total horizontal
 *    spans exceed the {@code maxSpansPerRow} - 1.
 * 4. If there is only one widget in a row, its width may exceed the {@code maxSpansPerRow}.
 *
 * <p>Let's say the {@code maxSpansPerRow} is set to 6. Widgets can be grouped in the same row
 * if their total horizontal spans added don't exceed 5.
 * Example 1: Row 1: 2x2, 2x3, 1x1. Total horizontal spans is 5. This is okay.
 * Example 2: Row 1: 2x2, 4x3, 1x1. the total horizontal spans is 7. This is wrong. 4x3 and 1x1
 * should be moved to a new row.
 * Example 3: Row 1: 6x4. This is okay because this is the only item in the row.
 */
public static List<ArrayList<WidgetItem>> groupWidgetItemsIntoTable(List<WidgetItem> widgetItems, final int maxSpansPerRow) {
    List<WidgetItem> sortedWidgetItems = widgetItems.stream().sorted(WIDGET_SHORTCUT_COMPARATOR).collect(Collectors.toList());
    List<ArrayList<WidgetItem>> widgetItemsTable = new ArrayList<>();
    ArrayList<WidgetItem> widgetItemsAtRow = null;
    for (WidgetItem widgetItem : sortedWidgetItems) {
        if (widgetItemsAtRow == null) {
            widgetItemsAtRow = new ArrayList<>();
            widgetItemsTable.add(widgetItemsAtRow);
        }
        int numOfWidgetItems = widgetItemsAtRow.size();
        int totalHorizontalSpan = widgetItemsAtRow.stream().map(item -> item.spanX).reduce(/* default= */
        0, Integer::sum);
        int totalHorizontalSpanAfterAddingWidget = widgetItem.spanX + totalHorizontalSpan;
        if (numOfWidgetItems == 0) {
            widgetItemsAtRow.add(widgetItem);
        } else if (// widget's description.
        totalHorizontalSpanAfterAddingWidget <= maxSpansPerRow - 1 && widgetItem.hasSameType(widgetItemsAtRow.get(numOfWidgetItems - 1))) {
            // Group items in the same row if
            // 1. they are with the same type, i.e. a row can only have widgets or shortcuts but
            // never a mix of both.
            // 2. the total number of horizontal spans are smaller than or equal to
            // MAX_SPAN_PER_ROW. If an item has a horizontal span > MAX_SPAN_PER_ROW, we just
            // place it in its own row regardless of the horizontal span limit.
            widgetItemsAtRow.add(widgetItem);
        } else {
            widgetItemsAtRow = new ArrayList<>();
            widgetItemsTable.add(widgetItemsAtRow);
            widgetItemsAtRow.add(widgetItem);
        }
    }
    return widgetItemsTable;
}
Also used : List(java.util.List) WidgetItem(com.android.launcher3.model.WidgetItem) Comparator(java.util.Comparator) Collectors(java.util.stream.Collectors) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) WidgetItem(com.android.launcher3.model.WidgetItem)

Example 12 with WIDGETS

use of com.android.launcher3.popup.SystemShortcut.WIDGETS in project android_packages_apps_Launcher3 by crdroidandroid.

the class WidgetsBottomSheet method onWidgetsBound.

@Override
public void onWidgetsBound() {
    List<WidgetItem> widgets = mActivityContext.getPopupDataProvider().getWidgetsForPackageUser(new PackageUserKey(mOriginalItemInfo.getTargetComponent().getPackageName(), mOriginalItemInfo.user));
    TableLayout widgetsTable = findViewById(R.id.widgets_table);
    widgetsTable.removeAllViews();
    WidgetsTableUtils.groupWidgetItemsIntoTable(widgets, mMaxHorizontalSpan).forEach(row -> {
        TableRow tableRow = new TableRow(getContext());
        tableRow.setGravity(Gravity.TOP);
        row.forEach(widgetItem -> {
            WidgetCell widget = addItemCell(tableRow);
            widget.setPreviewSize(widgetItem);
            widget.applyFromCellItem(widgetItem, LauncherAppState.getInstance(mActivityContext).getWidgetCache());
            widget.ensurePreview();
            widget.setVisibility(View.VISIBLE);
        });
        widgetsTable.addView(tableRow);
    });
}
Also used : TableRow(android.widget.TableRow) WidgetItem(com.android.launcher3.model.WidgetItem) PackageUserKey(com.android.launcher3.util.PackageUserKey) TableLayout(android.widget.TableLayout)

Example 13 with WIDGETS

use of com.android.launcher3.popup.SystemShortcut.WIDGETS in project android_packages_apps_Launcher3 by crdroidandroid.

the class WidgetsListAdapterTest method setWidgets_expandedApp_moreWidgets_shouldNotifyItemChangedWithWidgetItemInfoDiff.

@Test
public void setWidgets_expandedApp_moreWidgets_shouldNotifyItemChangedWithWidgetItemInfoDiff() {
    // GIVEN the adapter was first populated with com.google.test0 & com.google.test1. Each app
    // has one widget.
    ArrayList<WidgetsListBaseEntry> allEntries = generateSampleMap(2);
    mAdapter.setWidgets(allEntries);
    // GIVEN test com.google.test1 is expanded.
    // Visible entries in the adapter are:
    // [com.google.test0, com.google.test1, com.google.test1 content]
    mAdapter.onHeaderClicked(/* showWidgets= */
    true, new PackageUserKey(TEST_PACKAGE_PLACEHOLDER + 1, mUserHandle));
    Mockito.reset(mListener);
    // WHEN the adapter is updated with the same list of apps but com.google.test1 has 2 widgets
    // now.
    WidgetsListContentEntry testPackage1ContentEntry = (WidgetsListContentEntry) allEntries.get(3);
    WidgetItem widgetItem = testPackage1ContentEntry.mWidgets.get(0);
    WidgetsListContentEntry newTestPackage1ContentEntry = new WidgetsListContentEntry(testPackage1ContentEntry.mPkgItem, testPackage1ContentEntry.mTitleSectionName, List.of(widgetItem, widgetItem));
    allEntries.set(3, newTestPackage1ContentEntry);
    mAdapter.setWidgets(allEntries);
    // THEN the onItemRangeChanged is invoked for "com.google.test1 content" at index 2.
    verify(mListener).onItemRangeChanged(eq(2), eq(1), isNull());
}
Also used : WidgetsListBaseEntry(com.android.launcher3.widget.model.WidgetsListBaseEntry) WidgetsListContentEntry(com.android.launcher3.widget.model.WidgetsListContentEntry) PackageUserKey(com.android.launcher3.util.PackageUserKey) WidgetItem(com.android.launcher3.model.WidgetItem) Test(org.junit.Test)

Example 14 with WIDGETS

use of com.android.launcher3.popup.SystemShortcut.WIDGETS in project android_packages_apps_Launcher3 by crdroidandroid.

the class Launcher method inflateAppWidget.

private View inflateAppWidget(LauncherAppWidgetInfo item) {
    if (item.hasOptionFlag(LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET)) {
        item.providerName = QsbContainerView.getSearchComponentName(this);
        if (item.providerName == null) {
            getModelWriter().deleteItemFromDatabase(item);
            return null;
        }
    }
    final AppWidgetHostView view;
    if (mIsSafeModeEnabled) {
        view = new PendingAppWidgetHostView(this, item, mIconCache, true);
        prepareAppWidget(view, item);
        return view;
    }
    Object traceToken = TraceHelper.INSTANCE.beginSection("BIND_WIDGET_id=" + item.appWidgetId);
    try {
        final LauncherAppWidgetProviderInfo appWidgetInfo;
        String removalReason = "";
        if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) {
            // If the provider is not ready, bind as a pending widget.
            appWidgetInfo = null;
            removalReason = "the provider isn't ready.";
        } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
            // The widget id is not valid. Try to find the widget based on the provider info.
            appWidgetInfo = mAppWidgetManager.findProvider(item.providerName, item.user);
            if (appWidgetInfo == null) {
                if (WidgetsModel.GO_DISABLE_WIDGETS) {
                    removalReason = "widgets are disabled on go device.";
                } else {
                    removalReason = "WidgetManagerHelper cannot find a provider from provider info.";
                }
            }
        } else {
            appWidgetInfo = mAppWidgetManager.getLauncherAppWidgetInfo(item.appWidgetId);
            if (appWidgetInfo == null) {
                if (item.appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) {
                    removalReason = "CustomWidgetManager cannot find provider from that widget id.";
                } else {
                    removalReason = "AppWidgetManager cannot find provider for that widget id." + " It could be because AppWidgetService is not available, or the" + " appWidgetId has not been bound to a the provider yet, or you" + " don't have access to that appWidgetId.";
                }
            }
        }
        // If the provider is ready, but the width is not yet restored, try to restore it.
        if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) && (item.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED)) {
            if (appWidgetInfo == null) {
                FileLog.d(TAG, "Removing restored widget: id=" + item.appWidgetId + " belongs to component " + item.providerName + " user " + item.user + ", as the provider is null and " + removalReason);
                getModelWriter().deleteItemFromDatabase(item);
                return null;
            }
            // If we do not have a valid id, try to bind an id.
            if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
                if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_ALLOCATED)) {
                    // Id has not been allocated yet. Allocate a new id.
                    item.appWidgetId = mAppWidgetHost.allocateAppWidgetId();
                    item.restoreStatus |= LauncherAppWidgetInfo.FLAG_ID_ALLOCATED;
                    // Also try to bind the widget. If the bind fails, the user will be shown
                    // a click to setup UI, which will ask for the bind permission.
                    PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(appWidgetInfo, item.sourceContainer);
                    pendingInfo.spanX = item.spanX;
                    pendingInfo.spanY = item.spanY;
                    pendingInfo.minSpanX = item.minSpanX;
                    pendingInfo.minSpanY = item.minSpanY;
                    Bundle options = pendingInfo.getDefaultSizeOptions(this);
                    boolean isDirectConfig = item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG);
                    if (isDirectConfig && item.bindOptions != null) {
                        Bundle newOptions = item.bindOptions.getExtras();
                        if (options != null) {
                            newOptions.putAll(options);
                        }
                        options = newOptions;
                    }
                    boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed(item.appWidgetId, appWidgetInfo, options);
                    // We tried to bind once. If we were not able to bind, we would need to
                    // go through the permission dialog, which means we cannot skip the config
                    // activity.
                    item.bindOptions = null;
                    item.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG;
                    // Bind succeeded
                    if (success) {
                        // If the widget has a configure activity, it is still needs to set it
                        // up, otherwise the widget is ready to go.
                        item.restoreStatus = (appWidgetInfo.configure == null) || isDirectConfig ? LauncherAppWidgetInfo.RESTORE_COMPLETED : LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
                    }
                    getModelWriter().updateItemInDatabase(item);
                }
            } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY) && (appWidgetInfo.configure == null)) {
                // The widget was marked as UI not ready, but there is no configure activity to
                // update the UI.
                item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED;
                getModelWriter().updateItemInDatabase(item);
            } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY) && appWidgetInfo.configure != null) {
                if (mAppWidgetManager.isAppWidgetRestored(item.appWidgetId)) {
                    item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED;
                    getModelWriter().updateItemInDatabase(item);
                }
            }
        }
        if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
            // Verify that we own the widget
            if (appWidgetInfo == null) {
                FileLog.e(TAG, "Removing invalid widget: id=" + item.appWidgetId);
                getModelWriter().deleteWidgetInfo(item, getAppWidgetHost());
                return null;
            }
            item.minSpanX = appWidgetInfo.minSpanX;
            item.minSpanY = appWidgetInfo.minSpanY;
            view = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo);
        } else if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) && appWidgetInfo != null) {
            mAppWidgetHost.addPendingView(item.appWidgetId, new PendingAppWidgetHostView(this, item, mIconCache, false));
            view = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo);
        } else {
            view = new PendingAppWidgetHostView(this, item, mIconCache, false);
        }
        prepareAppWidget(view, item);
    } finally {
        TraceHelper.INSTANCE.endSection(traceToken);
    }
    return view;
}
Also used : LauncherAppWidgetProviderInfo(com.android.launcher3.widget.LauncherAppWidgetProviderInfo) PendingAppWidgetHostView(com.android.launcher3.widget.PendingAppWidgetHostView) LauncherAppWidgetHostView(com.android.launcher3.widget.LauncherAppWidgetHostView) AppWidgetHostView(android.appwidget.AppWidgetHostView) PendingAddWidgetInfo(com.android.launcher3.widget.PendingAddWidgetInfo) Bundle(android.os.Bundle) DragObject(com.android.launcher3.DropTarget.DragObject) PendingAppWidgetHostView(com.android.launcher3.widget.PendingAppWidgetHostView)

Example 15 with WIDGETS

use of com.android.launcher3.popup.SystemShortcut.WIDGETS in project android_packages_apps_Launcher3 by crdroidandroid.

the class LauncherUIScrollTest method testWidgetsListScroll.

@Test
public void testWidgetsListScroll() throws Exception {
    // Install 100 widgets
    for (int i = 0; i < 100; i++) {
        mModelHelper.installCustomShortcut(TEST_PACKAGE + i, "shortcutProvider");
    }
    // Bind and open widgets
    Launcher launcher = loadLauncher();
    WidgetsFullSheet widgets = WidgetsFullSheet.show(launcher, false);
    doLayout(launcher);
    int currentScroll = widgets.getRecyclerView().getCurrentScrollY();
    launcher.dispatchGenericMotionEvent(createScrollEvent(-1));
    int newScroll = widgets.getRecyclerView().getCurrentScrollY();
    assertNotEquals("Widgets was not scrolled", currentScroll, newScroll);
    assertEquals("Workspace was scrolled", 0, launcher.getWorkspace().getNextPage());
}
Also used : LauncherUIHelper.buildAndBindLauncher(com.android.launcher3.util.LauncherUIHelper.buildAndBindLauncher) Launcher(com.android.launcher3.Launcher) WidgetsFullSheet(com.android.launcher3.widget.picker.WidgetsFullSheet) Test(org.junit.Test)

Aggregations

ArrayList (java.util.ArrayList)64 Test (org.junit.Test)64 WidgetItem (com.android.launcher3.model.WidgetItem)54 WidgetsListContentEntry (com.android.launcher3.widget.model.WidgetsListContentEntry)54 PackageUserKey (com.android.launcher3.util.PackageUserKey)50 List (java.util.List)50 AppWidgetProviderInfo (android.appwidget.AppWidgetProviderInfo)46 SmallTest (androidx.test.filters.SmallTest)44 ComponentName (android.content.ComponentName)42 WidgetsListBaseEntry (com.android.launcher3.widget.model.WidgetsListBaseEntry)41 Point (android.graphics.Point)40 View (android.view.View)37 LauncherAppWidgetHostView (com.android.launcher3.widget.LauncherAppWidgetHostView)32 Collectors (java.util.stream.Collectors)31 Context (android.content.Context)29 IconCache (com.android.launcher3.icons.IconCache)29 LauncherAppWidgetProviderInfo (com.android.launcher3.widget.LauncherAppWidgetProviderInfo)29 WidgetsListHeaderEntry (com.android.launcher3.widget.model.WidgetsListHeaderEntry)29 WorkspaceItemInfo (com.android.launcher3.model.data.WorkspaceItemInfo)27 PendingAddWidgetInfo (com.android.launcher3.widget.PendingAddWidgetInfo)27