use of com.android.launcher3.popup.SystemShortcut.WIDGETS in project android_packages_apps_Launcher3 by ArrowOS.
the class WidgetsTableUtils method groupWidgetItemsIntoTableWithoutReordering.
/**
* Groups {@code widgetItems} into a 2D array which matches their appearance in a UI table while
* maintaining their order.
*
* <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>> groupWidgetItemsIntoTableWithoutReordering(List<WidgetItem> widgetItems, final int maxSpansPerRow) {
List<ArrayList<WidgetItem>> widgetItemsTable = new ArrayList<>();
ArrayList<WidgetItem> widgetItemsAtRow = null;
for (WidgetItem widgetItem : widgetItems) {
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;
}
use of com.android.launcher3.popup.SystemShortcut.WIDGETS in project android_packages_apps_Launcher3 by ArrowOS.
the class LoaderTask method run.
public void run() {
synchronized (this) {
// Skip fast if we are already stopped.
if (mStopped) {
return;
}
}
Object traceToken = TraceHelper.INSTANCE.beginSection(TAG);
TimingLogger logger = new TimingLogger(TAG, "run");
LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger();
try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
List<ShortcutInfo> allShortcuts = new ArrayList<>();
Trace.beginSection("LoadWorkspace");
try {
loadWorkspace(allShortcuts, memoryLogger);
} finally {
Trace.endSection();
}
logASplit(logger, "loadWorkspace");
// (e.g. both grid preview and minimal device mode uses a different db)
if (mApp.getInvariantDeviceProfile().dbFile.equals(mDbName)) {
verifyNotStopped();
sanitizeData();
logASplit(logger, "sanitizeData");
}
verifyNotStopped();
mResults.bindWorkspace(true);
logASplit(logger, "bindWorkspace");
mModelDelegate.workspaceLoadComplete();
// Notify the installer packages of packages with active installs on the first screen.
sendFirstScreenActiveInstallsBroadcast();
logASplit(logger, "sendFirstScreenActiveInstallsBroadcast");
// Take a break
waitForIdle();
logASplit(logger, "step 1 complete");
verifyNotStopped();
// second step
Trace.beginSection("LoadAllApps");
List<LauncherActivityInfo> allActivityList;
try {
allActivityList = loadAllApps();
} finally {
Trace.endSection();
}
logASplit(logger, "loadAllApps");
verifyNotStopped();
mResults.bindAllApps();
logASplit(logger, "bindAllApps");
verifyNotStopped();
IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler();
setIgnorePackages(updateHandler);
updateHandler.updateIcons(allActivityList, LauncherActivityCachingLogic.newInstance(mApp.getContext()), mApp.getModel()::onPackageIconsUpdated);
logASplit(logger, "update icon cache");
if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) {
verifyNotStopped();
logASplit(logger, "save shortcuts in icon cache");
updateHandler.updateIcons(allShortcuts, new ShortcutCachingLogic(), mApp.getModel()::onPackageIconsUpdated);
}
// Take a break
waitForIdle();
logASplit(logger, "step 2 complete");
verifyNotStopped();
// third step
List<ShortcutInfo> allDeepShortcuts = loadDeepShortcuts();
logASplit(logger, "loadDeepShortcuts");
verifyNotStopped();
mResults.bindDeepShortcuts();
logASplit(logger, "bindDeepShortcuts");
if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) {
verifyNotStopped();
logASplit(logger, "save deep shortcuts in icon cache");
updateHandler.updateIcons(allDeepShortcuts, new ShortcutCachingLogic(), (pkgs, user) -> {
});
}
// Take a break
waitForIdle();
logASplit(logger, "step 3 complete");
verifyNotStopped();
// fourth step
List<ComponentWithLabelAndIcon> allWidgetsList = mBgDataModel.widgetsModel.update(mApp, null);
logASplit(logger, "load widgets");
verifyNotStopped();
mResults.bindWidgets();
logASplit(logger, "bindWidgets");
verifyNotStopped();
updateHandler.updateIcons(allWidgetsList, new ComponentWithIconCachingLogic(mApp.getContext(), true), mApp.getModel()::onWidgetLabelsUpdated);
logASplit(logger, "save widgets in icon cache");
// fifth step
if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
loadFolderNames();
}
verifyNotStopped();
updateHandler.finish();
logASplit(logger, "finish icon update");
mModelDelegate.modelLoadComplete();
transaction.commit();
memoryLogger.clearLogs();
} catch (CancellationException e) {
// Loader stopped, ignore
logASplit(logger, "Cancelled");
} catch (Exception e) {
memoryLogger.printLogs();
throw e;
} finally {
logger.dumpToLog();
}
TraceHelper.INSTANCE.endSection(traceToken);
}
use of com.android.launcher3.popup.SystemShortcut.WIDGETS in project android_packages_apps_Launcher3 by ArrowOS.
the class WidgetsPredicationUpdateTaskTest method widgetsRecommendationRan_shouldOnlyReturnNotAddedWidgetsInAppPredictionOrder.
@Test
public void widgetsRecommendationRan_shouldOnlyReturnNotAddedWidgetsInAppPredictionOrder() throws Exception {
// WHEN newPredicationTask is executed with app predication of 5 apps.
AppTarget app1 = new AppTarget(new AppTargetId("app1"), "app1", "className", mUserHandle);
AppTarget app2 = new AppTarget(new AppTargetId("app2"), "app2", "className", mUserHandle);
AppTarget app3 = new AppTarget(new AppTargetId("app3"), "app3", "className", mUserHandle);
AppTarget app4 = new AppTarget(new AppTargetId("app4"), "app4", "className", mUserHandle);
AppTarget app5 = new AppTarget(new AppTargetId("app5"), "app5", "className", mUserHandle);
mModelHelper.executeTaskForTest(newWidgetsPredicationTask(List.of(app5, app3, app2, app4, app1))).forEach(Runnable::run);
// THEN only 3 widgets are returned because
// 1. app5/provider1 & app4/provider1 have already been added to workspace. They are
// excluded from the result.
// 2. app3 doesn't have a widget.
// 3. only 1 widget is picked from app1 because we only want to promote one widget per app.
List<PendingAddWidgetInfo> recommendedWidgets = mCallback.mRecommendedWidgets.items.stream().map(itemInfo -> (PendingAddWidgetInfo) itemInfo).collect(Collectors.toList());
assertThat(recommendedWidgets).hasSize(3);
assertWidgetInfo(recommendedWidgets.get(0).info, mApp2Provider1);
assertWidgetInfo(recommendedWidgets.get(1).info, mApp4Provider2);
assertWidgetInfo(recommendedWidgets.get(2).info, mApp1Provider1);
}
use of com.android.launcher3.popup.SystemShortcut.WIDGETS in project android_packages_apps_Launcher3 by ArrowOS.
the class WidgetsPredicationUpdateTaskTest method widgetsRecommendationRan_localFilterDisabled_shouldReturnWidgetsInPredicationOrder.
@Test
public void widgetsRecommendationRan_localFilterDisabled_shouldReturnWidgetsInPredicationOrder() throws Exception {
if (FeatureFlags.ENABLE_LOCAL_RECOMMENDED_WIDGETS_FILTER.get()) {
return;
}
// WHEN newPredicationTask is executed with 5 predicated widgets.
AppTarget widget1 = new AppTarget(new AppTargetId("app1"), "app1", "provider1", mUserHandle);
AppTarget widget2 = new AppTarget(new AppTargetId("app1"), "app1", "provider2", mUserHandle);
// Not installed app
AppTarget widget3 = new AppTarget(new AppTargetId("app2"), "app3", "provider1", mUserHandle);
// Not installed widget
AppTarget widget4 = new AppTarget(new AppTargetId("app4"), "app4", "provider3", mUserHandle);
AppTarget widget5 = new AppTarget(new AppTargetId("app5"), "app5", "provider1", mUserHandle);
mModelHelper.executeTaskForTest(newWidgetsPredicationTask(List.of(widget5, widget3, widget2, widget4, widget1))).forEach(Runnable::run);
// THEN only 3 widgets are returned because the launcher only filters out non-exist widgets.
List<PendingAddWidgetInfo> recommendedWidgets = mCallback.mRecommendedWidgets.items.stream().map(itemInfo -> (PendingAddWidgetInfo) itemInfo).collect(Collectors.toList());
assertThat(recommendedWidgets).hasSize(3);
assertWidgetInfo(recommendedWidgets.get(0).info, mApp5Provider1);
assertWidgetInfo(recommendedWidgets.get(1).info, mApp1Provider2);
assertWidgetInfo(recommendedWidgets.get(2).info, mApp1Provider1);
}
use of com.android.launcher3.popup.SystemShortcut.WIDGETS in project android_packages_apps_Launcher3 by ArrowOS.
the class AppWidgetsRestoredReceiver method restoreAppWidgetIds.
/**
* Updates the app widgets whose id has changed during the restore process.
*/
@WorkerThread
public static void restoreAppWidgetIds(Context context, int[] oldWidgetIds, int[] newWidgetIds) {
AppWidgetHost appWidgetHost = new LauncherAppWidgetHost(context);
if (WidgetsModel.GO_DISABLE_WIDGETS) {
Log.e(TAG, "Skipping widget ID remap as widgets not supported");
appWidgetHost.deleteHost();
return;
}
if (!RestoreDbTask.isPending(context)) {
// Someone has already gone through our DB once, probably LoaderTask. Skip any further
// modifications of the DB.
Log.e(TAG, "Skipping widget ID remap as DB already in use");
for (int widgetId : newWidgetIds) {
Log.d(TAG, "Deleting widgetId: " + widgetId);
appWidgetHost.deleteAppWidgetId(widgetId);
}
return;
}
final ContentResolver cr = context.getContentResolver();
final AppWidgetManager widgets = AppWidgetManager.getInstance(context);
for (int i = 0; i < oldWidgetIds.length; i++) {
Log.i(TAG, "Widget state restore id " + oldWidgetIds[i] + " => " + newWidgetIds[i]);
final AppWidgetProviderInfo provider = widgets.getAppWidgetInfo(newWidgetIds[i]);
final int state;
if (LoaderTask.isValidProvider(provider)) {
// This will ensure that we show 'Click to setup' UI if required.
state = LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
} else {
state = LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
}
// b/135926478: Work profile widget restore is broken in platform. This forces us to
// recreate the widget during loading with the correct host provider.
long mainProfileId = UserCache.INSTANCE.get(context).getSerialNumberForUser(myUserHandle());
String oldWidgetId = Integer.toString(oldWidgetIds[i]);
final String where = "appWidgetId=? and (restored & 1) = 1 and profileId=?";
final String[] args = new String[] { oldWidgetId, Long.toString(mainProfileId) };
int result = new ContentWriter(context, new ContentWriter.CommitParams(where, args)).put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i]).put(LauncherSettings.Favorites.RESTORED, state).commit();
if (result == 0) {
Cursor cursor = cr.query(Favorites.CONTENT_URI, new String[] { Favorites.APPWIDGET_ID }, "appWidgetId=?", new String[] { oldWidgetId }, null);
try {
if (!cursor.moveToFirst()) {
// The widget no long exists.
appWidgetHost.deleteAppWidgetId(newWidgetIds[i]);
}
} finally {
cursor.close();
}
}
// attempt to update widget id in backup table as well
new ContentWriter(context, ContentWriter.CommitParams.backupCommitParams("appWidgetId=? and profileId=?", args)).put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i]).put(LauncherSettings.Favorites.RESTORED, state).commit();
}
LauncherAppState app = LauncherAppState.getInstanceNoCreate();
if (app != null) {
app.getModel().forceReload();
}
}
Aggregations