summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/com/android/launcher3/DeviceProfile.java48
-rw-r--r--src/com/android/launcher3/Launcher.java12
-rw-r--r--src/com/android/launcher3/LauncherModel.kt3
-rw-r--r--src/com/android/launcher3/LauncherProvider.java72
-rw-r--r--src/com/android/launcher3/Workspace.java37
-rw-r--r--src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java2
-rw-r--r--src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java29
-rw-r--r--src/com/android/launcher3/allapps/AllAppsTransitionController.java3
-rw-r--r--src/com/android/launcher3/allapps/AlphabeticalAppsList.java2
-rw-r--r--src/com/android/launcher3/allapps/PrivateProfileManager.java7
-rw-r--r--src/com/android/launcher3/dot/FolderDotInfo.java13
-rw-r--r--src/com/android/launcher3/folder/Folder.java162
-rw-r--r--src/com/android/launcher3/folder/FolderIcon.java107
-rw-r--r--src/com/android/launcher3/folder/FolderPagedView.java3
-rw-r--r--src/com/android/launcher3/graphics/GridCustomizationsProxy.java14
-rw-r--r--src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java3
-rw-r--r--src/com/android/launcher3/graphics/ShapeDelegate.kt88
-rw-r--r--src/com/android/launcher3/model/LoaderCursor.java5
-rw-r--r--src/com/android/launcher3/model/LoaderTask.java3
-rw-r--r--src/com/android/launcher3/model/ModelDbController.java99
-rw-r--r--src/com/android/launcher3/model/ModelWriter.java15
-rw-r--r--src/com/android/launcher3/model/data/FolderInfo.java106
-rw-r--r--src/com/android/launcher3/model/data/ItemInfo.java9
-rw-r--r--src/com/android/launcher3/pageindicators/PageIndicator.java10
-rw-r--r--src/com/android/launcher3/pageindicators/PageIndicatorArrowClickListener.kt26
-rw-r--r--src/com/android/launcher3/pageindicators/PageIndicatorDots.java195
-rw-r--r--src/com/android/launcher3/popup/PopupContainerWithArrow.java9
-rw-r--r--src/com/android/launcher3/popup/PopupDataProvider.java7
-rw-r--r--src/com/android/launcher3/provider/RestoreDbTask.java9
-rw-r--r--src/com/android/launcher3/touch/AllAppsSwipeController.java26
-rw-r--r--src/com/android/launcher3/touch/WorkspaceTouchListener.java2
-rw-r--r--src/com/android/launcher3/util/ContentWriter.java3
-rw-r--r--src/com/android/launcher3/util/SimpleBroadcastReceiver.java26
-rw-r--r--src/com/android/launcher3/views/ScrimView.java3
-rw-r--r--src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java8
35 files changed, 642 insertions, 524 deletions
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index c85ca49c43..090208a33c 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -30,8 +30,8 @@ import static com.android.launcher3.testing.shared.ResourceUtils.INVALID_RESOURC
import static com.android.launcher3.testing.shared.ResourceUtils.pxFromDp;
import static com.android.launcher3.testing.shared.ResourceUtils.roundPxValueFromFloat;
import static com.android.wm.shell.Flags.enableBubbleBar;
-import static com.android.wm.shell.Flags.enableTinyTaskbar;
import static com.android.wm.shell.Flags.enableBubbleBarOnPhones;
+import static com.android.wm.shell.Flags.enableTinyTaskbar;
import android.annotation.SuppressLint;
import android.content.Context;
@@ -508,9 +508,11 @@ public class DeviceProfile {
bottomSheetOpenDuration = res.getInteger(R.integer.config_bottomSheetOpenDuration);
bottomSheetCloseDuration = res.getInteger(R.integer.config_bottomSheetCloseDuration);
- if (isTablet) {
+ if (shouldShowAllAppsOnSheet()) {
bottomSheetWorkspaceScale = workspaceContentScale;
- if (isMultiDisplay) {
+ if (Flags.allAppsBlur()) {
+ bottomSheetDepth = 2f;
+ } else if (isMultiDisplay) {
// TODO(b/259893832): Revert to use maxWallpaperScale to calculate bottomSheetDepth
// when screen recorder bug is fixed.
if (enableScalingRevealHomeAnimation()) {
@@ -1830,10 +1832,17 @@ public class DeviceProfile {
workspacePageIndicatorHeight - mWorkspacePageIndicatorOverlapWorkspace;
}
int paddingTop = workspaceTopPadding + (mIsScalableGrid ? 0 : edgeMarginPx);
- // On isFixedLandscapeMode on phones we already have padding because of the camera hole
- int paddingSide = inv.isFixedLandscape ? 0 : desiredWorkspaceHorizontalMarginPx;
+ int paddingLeft = desiredWorkspaceHorizontalMarginPx;
+ int paddingRight = desiredWorkspaceHorizontalMarginPx;
- padding.set(paddingSide, paddingTop, paddingSide, paddingBottom);
+ // In fixed Landscape we don't need padding on the side next to the cutout because
+ // the cutout is already adding padding to all of Launcher, we only need on the other
+ // side
+ if (inv.isFixedLandscape) {
+ paddingLeft = isSeascape() ? desiredWorkspaceHorizontalMarginPx : 0;
+ paddingRight = isSeascape() ? 0 : desiredWorkspaceHorizontalMarginPx;
+ }
+ padding.set(paddingLeft, paddingTop, paddingRight, paddingBottom);
}
insetPadding(workspacePadding, cellLayoutPaddingPx);
}
@@ -1931,7 +1940,24 @@ public class DeviceProfile {
hotseatBarPadding.set(mHotseatBarWorkspaceSpacePx, paddingTop,
mInsets.right + mHotseatBarEdgePaddingPx, paddingBottom);
}
- } else if (isTaskbarPresent || inv.isFixedLandscape) {
+ } else if (inv.isFixedLandscape) {
+ // Center the QSB vertically with hotseat
+ int hotseatBarBottomPadding = getHotseatBarBottomPadding();
+ int hotseatPlusQSBWidth = getHotseatRequiredWidth();
+ int qsbWidth = getAdditionalQsbSpace();
+ int availableWidthPxForHotseat = availableWidthPx - Math.abs(workspacePadding.width())
+ - Math.abs(cellLayoutPaddingPx.width());
+ int remainingSpaceOnSide = (availableWidthPxForHotseat - hotseatPlusQSBWidth) / 2;
+
+ hotseatBarPadding.set(
+ (remainingSpaceOnSide + qsbWidth) + mInsets.left + workspacePadding.left
+ + cellLayoutPaddingPx.left,
+ hotseatBarSizePx - hotseatBarBottomPadding - hotseatCellHeightPx,
+ remainingSpaceOnSide + mInsets.right + workspacePadding.right
+ + cellLayoutPaddingPx.right,
+ hotseatBarBottomPadding
+ );
+ } else if (isTaskbarPresent) {
// Center the QSB vertically with hotseat
int hotseatBarBottomPadding = getHotseatBarBottomPadding();
int hotseatBarTopPadding =
@@ -1950,11 +1976,6 @@ public class DeviceProfile {
}
startSpacing += getAdditionalQsbSpace();
- if (inv.isFixedLandscape) {
- endSpacing += mInsets.right;
- startSpacing += mInsets.left;
- }
-
hotseatBarPadding.top = hotseatBarTopPadding;
hotseatBarPadding.bottom = hotseatBarBottomPadding;
boolean isRtl = Utilities.isRtl(context.getResources());
@@ -2164,7 +2185,8 @@ public class DeviceProfile {
}
public boolean isSeascape() {
- return rotationHint == Surface.ROTATION_270 && isVerticalBarLayout();
+ return rotationHint == Surface.ROTATION_270
+ && (isVerticalBarLayout() || inv.isFixedLandscape);
}
public boolean shouldFadeAdjacentWorkspaceScreens() {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 289f175aa9..5c9392d69d 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1472,8 +1472,7 @@ public class Launcher extends StatefulActivity<LauncherState>
// Adding a shortcut to a Folder.
FolderIcon folderIcon = findFolderIcon(container);
if (folderIcon != null) {
- FolderInfo folderInfo = (FolderInfo) folderIcon.getTag();
- folderInfo.add(info, args.rank, false);
+ folderIcon.getFolder().addFolderContent(info, args.rank, false);
} else {
Log.e(TAG, "Could not find folder with id " + container + " to add shortcut.");
}
@@ -1792,7 +1791,6 @@ public class Launcher extends StatefulActivity<LauncherState>
SettingsCache.INSTANCE.get(this).unregister(TOUCHPAD_NATURAL_SCROLLING,
mNaturalScrollingChangedListener);
ScreenOnTracker.INSTANCE.get(this).removeListener(mScreenOnListener);
- mWorkspace.removeFolderListeners();
PluginManagerWrapper.INSTANCE.get(this).removePluginListener(this);
mModel.removeCallbacks(this);
@@ -2053,9 +2051,10 @@ public class Launcher extends StatefulActivity<LauncherState>
@Nullable final String reason) {
if (itemInfo instanceof WorkspaceItemInfo) {
View collectionIcon = mWorkspace.getViewByItemId(itemInfo.container);
- if (collectionIcon instanceof FolderIcon) {
+ if (collectionIcon instanceof FolderIcon folderIcon) {
// Remove the shortcut from the folder before removing it from launcher
- ((FolderInfo) collectionIcon.getTag()).remove((WorkspaceItemInfo) itemInfo, true);
+ Folder folder = folderIcon.getFolder();
+ folder.removeFolderContent(true, itemInfo);
} else if (collectionIcon instanceof AppPairIcon appPairIcon) {
removeItem(appPairIcon, appPairIcon.getInfo(), deleteFromDb,
"removing app pair because one of its member apps was removed");
@@ -2066,9 +2065,6 @@ public class Launcher extends StatefulActivity<LauncherState>
getModelWriter().deleteItemFromDatabase(itemInfo, reason);
}
} else if (itemInfo instanceof CollectionInfo ci) {
- if (v instanceof FolderIcon) {
- ((FolderIcon) v).removeListeners();
- }
mWorkspace.removeWorkspaceItem(v);
if (deleteFromDb) {
getModelWriter().deleteCollectionAndContentsFromDatabase(ci);
diff --git a/src/com/android/launcher3/LauncherModel.kt b/src/com/android/launcher3/LauncherModel.kt
index 02d70ae386..557ad67386 100644
--- a/src/com/android/launcher3/LauncherModel.kt
+++ b/src/com/android/launcher3/LauncherModel.kt
@@ -86,12 +86,11 @@ constructor(
private val loaderFactory: LoaderTaskFactory,
private val binderFactory: BaseLauncherBinderFactory,
private val spaceFinderFactory: Provider<WorkspaceItemSpaceFinder>,
+ val modelDbController: ModelDbController,
) {
private val mCallbacksList = ArrayList<BgDataModel.Callbacks>(1)
- val modelDbController = ModelDbController(context)
-
private val mLock = Any()
private var mLoaderTask: LoaderTask? = null
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 03ecf14ef6..acb2b48aeb 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -26,13 +26,13 @@ import android.content.ContentUris;
import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.database.Cursor;
-import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Process;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.model.ModelDbController;
@@ -74,24 +74,20 @@ public class LauncherProvider extends ContentProvider {
@Override
public String getType(Uri uri) {
- SqlArguments args = new SqlArguments(uri, null, null);
- if (TextUtils.isEmpty(args.where)) {
- return "vnd.android.cursor.dir/" + args.table;
+ if (TextUtils.isEmpty(parseUri(uri, null, null).first)) {
+ return "vnd.android.cursor.dir/" + Favorites.TABLE_NAME;
} else {
- return "vnd.android.cursor.item/" + args.table;
+ return "vnd.android.cursor.item/" + Favorites.TABLE_NAME;
}
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
- SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
- SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
- qb.setTables(args.table);
-
+ Pair<String, String[]> args = parseUri(uri, selection, selectionArgs);
Cursor[] result = new Cursor[1];
executeControllerTask(controller -> {
- result[0] = controller.query(args.table, projection, args.where, args.args, sortOrder);
+ result[0] = controller.query(projection, args.first, args.second, sortOrder);
return 0;
});
return result[0];
@@ -108,7 +104,7 @@ public class LauncherProvider extends ContentProvider {
// attempt allocate and bind the widget.
Integer itemType = values.getAsInteger(Favorites.ITEM_TYPE);
if (itemType != null
- && itemType.intValue() == Favorites.ITEM_TYPE_APPWIDGET
+ && itemType == Favorites.ITEM_TYPE_APPWIDGET
&& !values.containsKey(Favorites.APPWIDGET_ID)) {
ComponentName cn = ComponentName.unflattenFromString(
@@ -135,8 +131,7 @@ public class LauncherProvider extends ContentProvider {
}
}
- SqlArguments args = new SqlArguments(uri);
- return controller.insert(args.table, values);
+ return controller.insert(values);
});
return rowId < 0 ? null : ContentUris.withAppendedId(uri, rowId);
@@ -144,14 +139,14 @@ public class LauncherProvider extends ContentProvider {
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
- SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
- return executeControllerTask(c -> c.delete(args.table, args.where, args.args));
+ Pair<String, String[]> args = parseUri(uri, selection, selectionArgs);
+ return executeControllerTask(c -> c.delete(args.first, args.second));
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
- return executeControllerTask(c -> c.update(args.table, values, args.where, args.args));
+ Pair<String, String[]> args = parseUri(uri, selection, selectionArgs);
+ return executeControllerTask(c -> c.update(values, args.first, args.second));
}
@Override
@@ -209,35 +204,24 @@ public class LauncherProvider extends ContentProvider {
}
}
- static class SqlArguments {
- public final String table;
- public final String where;
- public final String[] args;
-
- SqlArguments(Uri url, String where, String[] args) {
- if (url.getPathSegments().size() == 1) {
- this.table = url.getPathSegments().get(0);
- this.where = where;
- this.args = args;
- } else if (url.getPathSegments().size() != 2) {
- throw new IllegalArgumentException("Invalid URI: " + url);
- } else if (!TextUtils.isEmpty(where)) {
- throw new UnsupportedOperationException("WHERE clause not supported: " + url);
- } else {
- this.table = url.getPathSegments().get(0);
- this.where = "_id=" + ContentUris.parseId(url);
- this.args = null;
+ /**
+ * Parses the uri and returns the where and arg clause.
+ *
+ * Note: This should be called on the binder thread (before posting on any executor) so that
+ * any parsing error gets propagated to the caller.
+ */
+ private static Pair<String, String[]> parseUri(Uri url, String where, String[] args) {
+ switch (url.getPathSegments().size()) {
+ case 1 -> {
+ return Pair.create(where, args);
}
- }
-
- SqlArguments(Uri url) {
- if (url.getPathSegments().size() == 1) {
- table = url.getPathSegments().get(0);
- where = null;
- args = null;
- } else {
- throw new IllegalArgumentException("Invalid URI: " + url);
+ case 2 -> {
+ if (!TextUtils.isEmpty(where)) {
+ throw new UnsupportedOperationException("WHERE clause not supported: " + url);
+ }
+ return Pair.create("_id=" + ContentUris.parseId(url), null);
}
+ default -> throw new IllegalArgumentException("Invalid URI: " + url);
}
}
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 6ed183ab23..59f84ab891 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -137,7 +137,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
-import java.util.stream.Collectors;
/**
* The workspace is a wide area with a wallpaper and a finite number of pages.
@@ -659,7 +658,6 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
}
// Remove the pages and clear the screen models
- removeFolderListeners();
removeAllViews();
mScreenOrder.clear();
mWorkspaceScreens.clear();
@@ -1914,7 +1912,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
boolean aboveShortcut = Folder.willAccept(dropOverView.getTag())
&& ((ItemInfo) dropOverView.getTag()).container != CONTAINER_HOTSEAT_PREDICTION;
- boolean willBecomeShortcut = Folder.willAcceptItemType(info.itemType);
+ boolean willBecomeShortcut = FolderInfo.willAcceptItemType(info.itemType);
return (aboveShortcut && willBecomeShortcut);
}
@@ -1994,8 +1992,8 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
fi.performCreateAnimation(destInfo, v, sourceInfo, d, folderLocation, scale);
} else {
fi.prepareCreateAnimation(v);
- fi.addItem(destInfo);
- fi.addItem(sourceInfo);
+ fi.getFolder().addFolderContent(destInfo);
+ fi.getFolder().addFolderContent(sourceInfo);
}
return true;
}
@@ -3209,21 +3207,6 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
});
}
- /**
- * Removes all folder listeners
- */
- public void removeFolderListeners() {
- mapOverItems(new ItemOperator() {
- @Override
- public boolean evaluate(ItemInfo info, View view) {
- if (view instanceof FolderIcon) {
- ((FolderIcon) view).removeListeners();
- }
- return false;
- }
- });
- }
-
public boolean isDropEnabled() {
return true;
}
@@ -3349,15 +3332,15 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
if (child instanceof DropTarget) {
mDragController.removeDropTarget((DropTarget) child);
}
- } else if (child instanceof FolderIcon) {
+ } else if (child instanceof FolderIcon folderIcon) {
FolderInfo folderInfo = (FolderInfo) info;
- List<ItemInfo> matches = folderInfo.getContents().stream()
+ ItemInfo[] matches = folderInfo.getContents().stream()
.filter(matcher)
- .collect(Collectors.toList());
- if (!matches.isEmpty()) {
- folderInfo.removeAll(matches, false);
- if (((FolderIcon) child).getFolder().isOpen()) {
- ((FolderIcon) child).getFolder().close(false /* animate */);
+ .toArray(ItemInfo[]::new);
+ if (matches.length > 0) {
+ folderIcon.getFolder().removeFolderContent(false, matches);
+ if (folderIcon.getFolder().isOpen()) {
+ folderIcon.getFolder().close(false /* animate */);
}
}
} else if (info instanceof AppPairInfo api) {
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index cd91f8e00b..df34ccf090 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -519,7 +519,7 @@ public class LauncherAccessibilityDelegate extends BaseAccessibilityDelegate<Lau
Folder folder = Folder.getOpen(mContext);
folder.close(true);
WorkspaceItemInfo info = (WorkspaceItemInfo) item;
- folder.getInfo().remove(info, false);
+ folder.removeFolderContent(false, info);
final int[] coordinates = new int[2];
final int screenId = findSpaceOnWorkspace(item, coordinates);
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index fafa60bf6d..f60896eb6d 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -181,6 +181,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
private ScrimView mScrimView;
private int mHeaderColor;
private int mBottomSheetBackgroundColor;
+ private float mBottomSheetBackgroundAlpha = 1f;
private int mTabsProtectionAlpha;
@Nullable private AllAppsTransitionController mAllAppsTransitionController;
@@ -311,7 +312,17 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
0,
0 // Bottom left
};
- mBottomSheetBackgroundColor = getContext().getColor(R.color.materialColorSurfaceDim);
+ if (Flags.allAppsBlur()) {
+ int resId = Utilities.isDarkTheme(getContext())
+ ? android.R.color.system_accent1_800 : android.R.color.system_accent1_100;
+ int layerAbove = ColorUtils.setAlphaComponent(getResources().getColor(resId, null),
+ (int) (0.4f * 255));
+ int layerBelow = ColorUtils.setAlphaComponent(Color.WHITE, (int) (0.1f * 255));
+ mBottomSheetBackgroundColor = ColorUtils.compositeColors(layerAbove, layerBelow);
+ } else {
+ mBottomSheetBackgroundColor = getContext().getColor(R.color.materialColorSurfaceDim);
+ }
+ mBottomSheetBackgroundAlpha = Color.alpha(mBottomSheetBackgroundColor) / 255.0f;
updateBackgroundVisibility(mActivityContext.getDeviceProfile());
mSearchUiManager.initializeSearch(this);
}
@@ -1152,7 +1163,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
if (!grid.isVerticalBarLayout() || FeatureFlags.enableResponsiveWorkspace()) {
int topPadding = grid.allAppsPadding.top;
- if (isSearchBarFloating() && !grid.isTablet) {
+ if (isSearchBarFloating() && !grid.shouldShowAllAppsOnSheet()) {
topPadding += getResources().getDimensionPixelSize(
R.dimen.all_apps_additional_top_padding_floating_search);
}
@@ -1401,7 +1412,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
// Draw full background panel for tablets.
if (hasBottomSheet) {
mHeaderPaint.setColor(mBottomSheetBackgroundColor);
- mHeaderPaint.setAlpha(255);
+ mHeaderPaint.setAlpha((int) (mBottomSheetBackgroundAlpha * 255));
mTmpRectF.set(
leftWithScale,
@@ -1424,6 +1435,10 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
return;
}
+ if (hasBottomSheet) {
+ mHeaderPaint.setAlpha((int) (mHeaderPaint.getAlpha() * mBottomSheetBackgroundAlpha));
+ }
+
// Draw header on background panel
final float headerBottomNoScale =
getHeaderBottom() + getVisibleContainerView().getPaddingTop();
@@ -1455,7 +1470,11 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
mHeaderPaint.setColor(Color.BLUE);
mHeaderPaint.setAlpha(255);
} else {
- mHeaderPaint.setAlpha((int) (getAlpha() * mTabsProtectionAlpha));
+ float tabAlpha = getAlpha() * mTabsProtectionAlpha;
+ if (hasBottomSheet) {
+ tabAlpha *= mBottomSheetBackgroundAlpha;
+ }
+ mHeaderPaint.setAlpha((int) tabAlpha);
}
float left = 0f;
float right = canvas.getWidth();
@@ -1507,7 +1526,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
public int getHeaderBottom() {
int bottom = (int) getTranslationY() + mHeader.getClipTop();
if (isSearchBarFloating()) {
- if (mActivityContext.getDeviceProfile().isTablet) {
+ if (mActivityContext.getDeviceProfile().shouldShowAllAppsOnSheet()) {
return bottom + mBottomSheetBackground.getTop();
}
return bottom;
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 4cc31d296e..350f763939 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -290,7 +290,8 @@ public class AllAppsTransitionController
private void onScaleProgressChanged() {
final float scaleProgress = mAllAppScale.value;
SCALE_PROPERTY.set(mLauncher.getAppsView(), scaleProgress);
- if (!mLauncher.getAppsView().isSearching() || !mLauncher.getDeviceProfile().isTablet) {
+ if (!mLauncher.getAppsView().isSearching()
+ || !mLauncher.getDeviceProfile().shouldShowAllAppsOnSheet()) {
mLauncher.getScrimView().setScrimHeaderScale(scaleProgress);
}
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 870c891f47..f223eaa600 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -436,6 +436,8 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
if (currentItem.itemInfo != null && Objects.equals(
currentItem.itemInfo.getTargetPackage(), PRIVATE_SPACE_PACKAGE)) {
currentItem.itemInfo.bitmap.creationFlags |= FLAG_NO_BADGE;
+ currentItem.itemInfo.contentDescription =
+ mPrivateProviderManager.getPsAppContentDesc();
privateSpaceAppIndex = i;
}
}
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 609edd2c99..1bc1b17d15 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -142,6 +142,7 @@ public class PrivateProfileManager extends UserProfileManager {
private PrivateSpaceSettingsButton mPrivateSpaceSettingsButton;
@Nullable
private ConstraintLayout mFloatingMaskView;
+ private final String mPrivateSpaceAppContentDesc;
private final String mLockedStateContentDesc;
private final String mUnLockedStateContentDesc;
@@ -157,6 +158,8 @@ public class PrivateProfileManager extends UserProfileManager {
UI_HELPER_EXECUTOR.post(() -> initializeInBackgroundThread(appContext));
mPsHeaderHeight = mAllApps.getContext().getResources().getDimensionPixelSize(
R.dimen.ps_header_height);
+ mPrivateSpaceAppContentDesc = mAllApps.getContext()
+ .getString(R.string.ps_app_content_description);
mLockedStateContentDesc = mAllApps.getContext()
.getString(R.string.ps_container_lock_button_content_description);
mUnLockedStateContentDesc = mAllApps.getContext()
@@ -929,6 +932,10 @@ public class PrivateProfileManager extends UserProfileManager {
return mPsHeaderHeight;
}
+ String getPsAppContentDesc() {
+ return mPrivateSpaceAppContentDesc;
+ }
+
boolean isPrivateSpaceItem(BaseAllAppsAdapter.AdapterItem item) {
return getItemInfoMatcher().test(item.itemInfo) || item.decorationInfo != null
|| (item.itemInfo instanceof PrivateSpaceInstallAppButtonInfo);
diff --git a/src/com/android/launcher3/dot/FolderDotInfo.java b/src/com/android/launcher3/dot/FolderDotInfo.java
index 54800a07a8..cb91db7654 100644
--- a/src/com/android/launcher3/dot/FolderDotInfo.java
+++ b/src/com/android/launcher3/dot/FolderDotInfo.java
@@ -30,6 +30,10 @@ public class FolderDotInfo extends DotInfo {
private int mNumNotifications;
+ public void reset() {
+ mNumNotifications = 0;
+ }
+
public void addDotInfo(DotInfo dotToAdd) {
if (dotToAdd == null) {
return;
@@ -39,15 +43,6 @@ public class FolderDotInfo extends DotInfo {
mNumNotifications, MIN_COUNT, DotInfo.MAX_COUNT);
}
- public void subtractDotInfo(DotInfo dotToSubtract) {
- if (dotToSubtract == null) {
- return;
- }
- mNumNotifications -= dotToSubtract.getNotificationKeys().size();
- mNumNotifications = Utilities.boundToRange(
- mNumNotifications, MIN_COUNT, DotInfo.MAX_COUNT);
- }
-
@Override
public int getNotificationCount() {
return mNumNotifications;
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 0ae95196fd..967af053fb 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -19,9 +19,6 @@ package com.android.launcher3.folder;
import static android.text.TextUtils.isEmpty;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
-import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
-import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
-import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
import static com.android.launcher3.LauncherState.EDIT_MODE;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
@@ -29,6 +26,7 @@ import static com.android.launcher3.config.FeatureFlags.ALWAYS_USE_HARDWARE_OPTI
import static com.android.launcher3.folder.FolderGridOrganizer.createFolderGridOrganizer;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_LABEL_UPDATED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED;
+import static com.android.launcher3.model.data.FolderInfo.willAcceptItemType;
import static com.android.launcher3.testing.shared.TestProtocol.FOLDER_OPENED_MESSAGE;
import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
@@ -95,7 +93,6 @@ import com.android.launcher3.logger.LauncherAtom.ToState;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.model.data.FolderInfo;
-import com.android.launcher3.model.data.FolderInfo.FolderListener;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemFactory;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -111,6 +108,7 @@ import com.android.launcher3.widget.PendingAddShortcutInfo;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
@@ -122,7 +120,7 @@ import java.util.stream.Stream;
* Represents a set of icons chosen by the user or generated by the system.
*/
public class Folder extends AbstractFloatingView implements ClipPathView, DragSource,
- View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener,
+ View.OnLongClickListener, DropTarget, TextView.OnEditorActionListener,
View.OnFocusChangeListener, DragListener, ExtendedEditText.OnBackKeyListener,
LauncherBindableItemsContainer {
private static final String TAG = "Launcher.Folder";
@@ -179,15 +177,6 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
return o instanceof ItemInfo info && willAcceptItemType(info.itemType);
}
- /**
- * Checks if {@code itemType} is a type that can be placed in folders.
- */
- public static boolean willAcceptItemType(int itemType) {
- return itemType == ITEM_TYPE_APPLICATION
- || itemType == ITEM_TYPE_DEEP_SHORTCUT
- || itemType == ITEM_TYPE_APP_PAIR;
- }
-
private Alarm mReorderAlarm = new Alarm(Looper.getMainLooper());
private Alarm mOnExitAlarm = new Alarm(Looper.getMainLooper());
private Alarm mOnScrollHintAlarm = new Alarm(Looper.getMainLooper());
@@ -243,7 +232,10 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
private boolean mIsExternalDrag;
private boolean mIsDragInProgress = false;
private boolean mDeleteFolderOnDropCompleted = false;
+
private boolean mSuppressFolderDeletion = false;
+ private boolean mSuppressContentUpdate = false;
+
private boolean mItemAddedBackToSelfViaIcon = false;
private boolean mIsEditingName = false;
@@ -385,9 +377,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
// We do not want to get events for the item being removed, as they will get handled
// when the drop completes
- try (SuppressInfoChanges s = new SuppressInfoChanges()) {
- mInfo.remove(dragObject.dragInfo, true);
- }
+ executeWithContentUpdateSuppressed(() -> removeFolderContent(true, dragObject.dragInfo));
+
mIsDragInProgress = true;
mItemAddedBackToSelfViaIcon = false;
}
@@ -532,8 +523,17 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
lp.customPosition = true;
setLayoutParams(lp);
}
+ reapplyItemInfo();
+ // In case any children didn't come across during loading, clean up the folder accordingly
+ mFolderIcon.post(() -> {
+ if (getItemCount() <= 1) {
+ replaceFolderWithFinalItem();
+ }
+ });
+ }
+
+ public void reapplyItemInfo() {
mItemsInvalidated = true;
- mInfo.addListener(this);
if (!isEmpty(mInfo.title)) {
mFolderName.setText(mInfo.title);
@@ -542,15 +542,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
mFolderName.setText("");
mFolderName.setHint(R.string.folder_hint_text);
}
- // In case any children didn't come across during loading, clean up the folder accordingly
- mFolderIcon.post(() -> {
- if (getItemCount() <= 1) {
- replaceFolderWithFinalItem();
- }
- });
}
-
/**
* Show suggested folder title in FolderEditText if the first suggestion is non-empty, push
* rest of the suggestions to InputMethodManager.
@@ -680,7 +673,6 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
if (!shouldAnimateOpen(items)) {
return;
}
-
Folder openFolder = getOpen(mActivityContext);
closeOpenFolder(openFolder);
@@ -954,9 +946,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
@Override
public boolean acceptDrop(DragObject d) {
- final ItemInfo item = d.dragInfo;
- final int itemType = item.itemType;
- return Folder.willAcceptItemType(itemType);
+ return willAcceptItemType(d.dragInfo.itemType);
}
public void onDragEnter(DragObject d) {
@@ -1121,9 +1111,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
mContent.arrangeChildren(views);
mItemsInvalidated = true;
- try (SuppressInfoChanges s = new SuppressInfoChanges()) {
- mFolderIcon.onDrop(d, true /* itemReturnedOnFailedDrop */);
- }
+ executeWithContentUpdateSuppressed(
+ () -> mFolderIcon.onDrop(d, true /* itemReturnedOnFailedDrop */));
}
}
@@ -1417,9 +1406,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
rearrangeChildren();
// Temporarily suppress the listener, as we did all the work already here.
- try (SuppressInfoChanges s = new SuppressInfoChanges()) {
- mInfo.add(si, mEmptyCellRank, false);
- }
+ executeWithContentUpdateSuppressed(() -> addFolderContent(si, mEmptyCellRank, false));
// We only need to update the locations if it doesn't get handled in
// #onDropCompleted.
@@ -1465,37 +1452,66 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
}
}
- @Override
- public void onAdd(ItemInfo item, int rank) {
- FolderGridOrganizer verifier = createFolderGridOrganizer(
- mActivityContext.getDeviceProfile()).setFolderInfo(mInfo);
- verifier.updateRankAndPos(item, rank);
- mLauncherDelegate.getModelWriter().addOrMoveItemInDatabase(item, mInfo.id, 0, item.cellX,
- item.cellY);
- updateItemLocationsInDatabaseBatch(false);
+ /** Add an app or shortcut */
+ public void addFolderContent(ItemInfo item) {
+ addFolderContent(item, mInfo.getContents().size(), true);
+ }
- if (mContent.areViewsBound()) {
- mContent.createAndAddViewForRank(item, rank);
+ /** Add an app or shortcut for a specified rank */
+ public void addFolderContent(ItemInfo item, int rank, boolean animate) {
+ if (!willAcceptItemType(item.itemType)) {
+ throw new RuntimeException("tried to add an illegal type into a folder");
}
- mItemsInvalidated = true;
+
+ rank = Utilities.boundToRange(rank, 0, mInfo.getContents().size());
+ mInfo.getContents().add(rank, item);
+
+ if (!mSuppressContentUpdate) {
+ FolderGridOrganizer verifier = createFolderGridOrganizer(
+ mActivityContext.getDeviceProfile()).setFolderInfo(mInfo);
+ verifier.updateRankAndPos(item, rank);
+ mLauncherDelegate.getModelWriter().addOrMoveItemInDatabase(item, mInfo.id, 0,
+ item.cellX,
+ item.cellY);
+ updateItemLocationsInDatabaseBatch(false);
+
+ if (mContent.areViewsBound()) {
+ mContent.createAndAddViewForRank(item, rank);
+ }
+ mItemsInvalidated = true;
+ updateTextViewFocus();
+ }
+
+ mLauncherDelegate.getModelWriter().notifyItemModified(mInfo);
+ mFolderIcon.onItemsChanged(animate);
}
- @Override
- public void onRemove(List<ItemInfo> items) {
- mItemsInvalidated = true;
- items.stream().map(this::getViewForInfo).forEach(mContent::removeItem);
- if (mState == STATE_ANIMATING) {
- mRearrangeOnClose = true;
- } else {
- rearrangeChildren();
+ /** Remove all matching app or shortcut. Does not change the DB. */
+ public void removeFolderContent(boolean animate, ItemInfo... items) {
+ List<ItemInfo> itemArray = Arrays.asList(items);
+ if (mInfo.getContents().removeAll(itemArray)) {
+ mLauncherDelegate.getModelWriter().notifyItemModified(mInfo);
}
- if (getItemCount() <= 1) {
- if (mIsOpen) {
- close(true);
+
+ if (!mSuppressContentUpdate) {
+ mItemsInvalidated = true;
+ itemArray.forEach(item -> mContent.removeItem(getViewForInfo(item)));
+ if (mState == STATE_ANIMATING) {
+ mRearrangeOnClose = true;
} else {
- replaceFolderWithFinalItem();
+ rearrangeChildren();
+ }
+ if (getItemCount() <= 1) {
+ if (mIsOpen) {
+ close(true);
+ } else {
+ replaceFolderWithFinalItem();
+ }
}
+ updateTextViewFocus();
}
+
+ mFolderIcon.onItemsChanged(animate);
}
@VisibleForTesting
@@ -1503,16 +1519,6 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
return mContent.iterateOverItems((info, view) -> info == item);
}
- @Override
- public void onItemsChanged(boolean animate) {
- updateTextViewFocus();
- }
-
- @Override
- public void onTitleChanged(CharSequence title) {
- mFolderName.setText(title);
- }
-
/**
* Utility methods to iterate over items of the view
*/
@@ -1666,18 +1672,14 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
}
};
- /**
- * Temporary resource held while we don't want to handle info changes
- */
- private class SuppressInfoChanges implements AutoCloseable {
-
- SuppressInfoChanges() {
- mInfo.removeListener(Folder.this);
- }
-
- @Override
- public void close() {
- mInfo.addListener(Folder.this);
+ /** Executes the task while suppressing the content update for the folder */
+ private void executeWithContentUpdateSuppressed(Runnable task) {
+ if (mSuppressContentUpdate) {
+ task.run();
+ } else {
+ mSuppressContentUpdate = true;
+ task.run();
+ mSuppressContentUpdate = false;
updateTextViewFocus();
}
}
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 0ed87871cc..1cd9bcc965 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -23,6 +23,7 @@ import static com.android.launcher3.folder.PreviewItemManager.INITIAL_ITEM_ANIMA
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_AUTO_LABELED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_AUTO_LABELING_SKIPPED_EMPTY_PRIMARY;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_AUTO_LABELING_SKIPPED_EMPTY_SUGGESTIONS;
+import static com.android.launcher3.model.data.FolderInfo.willAcceptItemType;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -73,7 +74,6 @@ import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.AppPairInfo;
import com.android.launcher3.model.data.FolderInfo;
-import com.android.launcher3.model.data.FolderInfo.FolderListener;
import com.android.launcher3.model.data.FolderInfo.LabelState;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemFactory;
@@ -92,7 +92,7 @@ import java.util.function.Predicate;
/**
* An icon that can appear on in the workspace representing an {@link Folder}.
*/
-public class FolderIcon extends FrameLayout implements FolderListener, FloatingIconViewCompanion,
+public class FolderIcon extends FrameLayout implements FloatingIconViewCompanion,
DraggableView, Reorderable {
private final MultiTranslateDelegate mTranslateDelegate = new MultiTranslateDelegate(this);
@@ -127,7 +127,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
private boolean mForceHideDot;
@ViewDebug.ExportedProperty(category = "launcher", deepExport = true)
- private FolderDotInfo mDotInfo = new FolderDotInfo();
+ private final FolderDotInfo mDotInfo = new FolderDotInfo();
private DotRenderer mDotRenderer;
@ViewDebug.ExportedProperty(category = "launcher", deepExport = true)
private DotRenderer.DrawParams mDotParams;
@@ -178,7 +178,6 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
folder.bind(folderInfo);
icon.setFolder(folder);
- folderInfo.addListener(icon);
return icon;
}
@@ -217,13 +216,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
icon.mDotRenderer = grid.mDotRendererWorkSpace;
icon.setContentDescription(icon.getAccessiblityTitle(folderInfo.title));
-
- // Keep the notification dot up to date with the sum of all the content's dots.
- FolderDotInfo folderDotInfo = new FolderDotInfo();
- for (ItemInfo si : folderInfo.getContents()) {
- folderDotInfo.addDotInfo(activity.getDotInfoForItem(si));
- }
- icon.setDotInfo(folderDotInfo);
+ icon.updateDotInfo();
icon.setAccessibilityDelegate(activity.getAccessibilityDelegate());
@@ -264,22 +257,13 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
}
private boolean willAcceptItem(ItemInfo item) {
- final int itemType = item.itemType;
- return (Folder.willAcceptItemType(itemType) && item != mInfo && !mFolder.isOpen());
+ return (willAcceptItemType(item.itemType) && item != mInfo && !mFolder.isOpen());
}
public boolean acceptDrop(ItemInfo dragInfo) {
return !mFolder.isDestroyed() && willAcceptItem(dragInfo);
}
- public void addItem(ItemInfo item) {
- mInfo.add(item, true);
- }
-
- public void removeItem(ItemInfo item, boolean animate) {
- mInfo.remove(item, animate);
- }
-
public void onDragEnter(ItemInfo dragInfo) {
if (mFolder.isDestroyed() || !willAcceptItem(dragInfo)) return;
CellLayoutLayoutParams lp = (CellLayoutLayoutParams) getLayoutParams();
@@ -308,9 +292,8 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
public void performCreateAnimation(final ItemInfo destInfo, final View destView,
final ItemInfo srcInfo, final DragObject d, Rect dstRect,
float scaleRelativeToDragLayer) {
- final DragView srcView = d.dragView;
prepareCreateAnimation(destView);
- addItem(destInfo);
+ getFolder().addFolderContent(destInfo);
// This will animate the first item from it's position as an icon into its
// position as the first item in the preview
mPreviewItemManager.createFirstItemAnimation(false /* reverse */, null)
@@ -364,7 +347,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
boolean itemAdded = false;
if (itemReturnedOnFailedDrop || index >= MAX_NUM_ITEMS_IN_PREVIEW) {
List<ItemInfo> oldPreviewItems = new ArrayList<>(mCurrentPreviewItems);
- mInfo.add(item, index, false);
+ getFolder().addFolderContent(item, index, false);
mCurrentPreviewItems.clear();
mCurrentPreviewItems.addAll(getPreviewItemsOnPage(0));
@@ -380,12 +363,12 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
mPreviewItemManager.onDrop(oldPreviewItems, mCurrentPreviewItems, item);
itemAdded = true;
} else {
- removeItem(item, false);
+ getFolder().removeFolderContent(false, item);
}
}
if (!itemAdded) {
- mInfo.add(item, index, true);
+ getFolder().addFolderContent(item, index, true);
}
int[] center = new int[2];
@@ -431,7 +414,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
}, DROP_IN_ANIMATION_DURATION);
});
} else {
- addItem(item);
+ getFolder().addFolderContent(item);
}
}
@@ -500,9 +483,23 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
);
}
- public void setDotInfo(FolderDotInfo dotInfo) {
- updateDotScale(mDotInfo.hasDot(), dotInfo.hasDot());
- mDotInfo = dotInfo;
+ /** Keep the notification dot up to date with the sum of all the content's dots. */
+ public void updateDotInfo() {
+ boolean hadDot = mDotInfo.hasDot();
+ mDotInfo.reset();
+ for (ItemInfo si : mInfo.getContents()) {
+ mDotInfo.addDotInfo(mActivity.getDotInfoForItem(si));
+ }
+ boolean isDotted = mDotInfo.hasDot();
+ float newDotScale = isDotted ? 1f : 0f;
+ // Animate when a dot is first added or when it is removed.
+ if ((hadDot ^ isDotted) && isShown()) {
+ animateDotScale(newDotScale);
+ } else {
+ cancelDotScaleAnim();
+ mDotScale = newDotScale;
+ invalidate();
+ }
}
public ClippedFolderIconLayoutRule getLayoutRule() {
@@ -523,22 +520,6 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
}
}
- /**
- * Sets mDotScale to 1 or 0, animating if wasDotted or isDotted is false
- * (the dot is being added or removed).
- */
- private void updateDotScale(boolean wasDotted, boolean isDotted) {
- float newDotScale = isDotted ? 1f : 0f;
- // Animate when a dot is first added or when it is removed.
- if ((wasDotted ^ isDotted) && isShown()) {
- animateDotScale(newDotScale);
- } else {
- cancelDotScaleAnim();
- mDotScale = newDotScale;
- invalidate();
- }
- }
-
private void cancelDotScaleAnim() {
if (mDotScaleAnim != null) {
mDotScaleAnim.cancel();
@@ -682,13 +663,6 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
return mPreviewItemManager.verifyDrawable(who) || super.verifyDrawable(who);
}
- @Override
- public void onItemsChanged(boolean animate) {
- updatePreviewItems(animate);
- invalidate();
- requestLayout();
- }
-
private void updatePreviewItems(boolean animate) {
mPreviewItemManager.updatePreviewItems(animate);
mCurrentPreviewItems.clear();
@@ -702,31 +676,15 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
mPreviewItemManager.updatePreviewItems(itemCheck);
}
- @Override
- public void onAdd(ItemInfo item, int rank) {
- updatePreviewItems(false);
- boolean wasDotted = mDotInfo.hasDot();
- mDotInfo.addDotInfo(mActivity.getDotInfoForItem(item));
- boolean isDotted = mDotInfo.hasDot();
- updateDotScale(wasDotted, isDotted);
- setContentDescription(getAccessiblityTitle(mInfo.title));
- invalidate();
- requestLayout();
- }
-
- @Override
- public void onRemove(List<ItemInfo> items) {
+ public void onItemsChanged(boolean animate) {
updatePreviewItems(false);
- boolean wasDotted = mDotInfo.hasDot();
- items.stream().map(mActivity::getDotInfoForItem).forEach(mDotInfo::subtractDotInfo);
- boolean isDotted = mDotInfo.hasDot();
- updateDotScale(wasDotted, isDotted);
+ updateDotInfo();
setContentDescription(getAccessiblityTitle(mInfo.title));
+ updatePreviewItems(animate);
invalidate();
requestLayout();
}
- @Override
public void onTitleChanged(CharSequence title) {
mFolderName.setText(title);
setContentDescription(getAccessiblityTitle(title));
@@ -762,11 +720,6 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
mLongPressHelper.cancelLongPress();
}
- public void removeListeners() {
- mInfo.removeListener(this);
- mInfo.removeListener(mFolder);
- }
-
private boolean isInHotseat() {
return mInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT;
}
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index bebe1a49ef..0963421f8a 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -47,6 +47,7 @@ import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.model.data.AppPairInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.pageindicators.Direction;
import com.android.launcher3.pageindicators.PageIndicatorDots;
import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator;
import com.android.launcher3.util.Thunk;
@@ -129,6 +130,8 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> implements Cli
public void setFolder(Folder folder) {
mFolder = folder;
mPageIndicator = folder.findViewById(R.id.folder_page_indicator);
+ mPageIndicator.setArrowClickListener(direction -> snapToPageImmediately(
+ (Direction.END == direction) ? mCurrentPage + 1 : mCurrentPage - 1));
initParentViews(folder);
}
diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProxy.java b/src/com/android/launcher3/graphics/GridCustomizationsProxy.java
index 70b9f46c1f..48519ce8bc 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProxy.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProxy.java
@@ -113,6 +113,7 @@ public class GridCustomizationsProxy implements ProxyProvider {
private static final String KEY_SHAPE_OPTIONS = "/shape_options";
// default_grid is for setting grid and shape to system settings
private static final String KEY_DEFAULT_GRID = "/default_grid";
+ private static final String SET_SHAPE = "/shape";
private static final String METHOD_GET_PREVIEW = "get_preview";
@@ -130,6 +131,7 @@ public class GridCustomizationsProxy implements ProxyProvider {
private static final int MESSAGE_ID_UPDATE_SHAPE = 2586;
private static final int MESSAGE_ID_UPDATE_GRID = 7414;
private static final int MESSAGE_ID_UPDATE_COLOR = 856;
+ private static final int MESSAGE_ID_UPDATE_ICON_THEMED = 311;
// Set of all active previews used to track duplicate memory allocations
private final Set<PreviewLifecycleObserver> mActivePreviews =
@@ -264,6 +266,12 @@ public class GridCustomizationsProxy implements ProxyProvider {
mContext.getContentResolver().notifyChange(uri, null);
return 1;
}
+ case SET_SHAPE:
+ if (Flags.newCustomizationPickerUi()) {
+ mPrefs.put(PREF_ICON_SHAPE,
+ requireNonNullElse(values.getAsString(KEY_SHAPE_KEY), ""));
+ }
+ return 1;
case ICON_THEMED:
case SET_ICON_THEMED: {
mThemeManager.setMonoThemeEnabled(values.getAsBoolean(BOOLEAN_VALUE));
@@ -384,6 +392,12 @@ public class GridCustomizationsProxy implements ProxyProvider {
renderer.previewColor(message.getData());
}
break;
+ case MESSAGE_ID_UPDATE_ICON_THEMED:
+ if (Flags.newCustomizationPickerUi()) {
+ Boolean iconThemed = message.getData().getBoolean(BOOLEAN_VALUE);
+ // TODO Update icon themed in the preview
+ }
+ break;
default:
// Unknown command, destroy lifecycle
Log.d(TAG, "Unknown preview command: " + message.what + ", destroying preview");
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index 5a9b9c20f9..457d12e8ca 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -21,7 +21,6 @@ import static android.content.res.Configuration.UI_MODE_NIGHT_YES;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.launcher3.LauncherPrefs.GRID_NAME;
-import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.graphics.ThemeManager.PREF_ICON_SHAPE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -179,7 +178,7 @@ public class PreviewSurfaceRenderer {
ModelDbController mainController =
LauncherAppState.getInstance(mContext).getModel().getModelDbController();
- try (Cursor c = mainController.query(TABLE_NAME,
+ try (Cursor c = mainController.query(
new String[] {
LauncherSettings.Favorites.APPWIDGET_ID,
LauncherSettings.Favorites.SPANX,
diff --git a/src/com/android/launcher3/graphics/ShapeDelegate.kt b/src/com/android/launcher3/graphics/ShapeDelegate.kt
index 7c042929e2..01bfe3018c 100644
--- a/src/com/android/launcher3/graphics/ShapeDelegate.kt
+++ b/src/com/android/launcher3/graphics/ShapeDelegate.kt
@@ -18,6 +18,7 @@ package com.android.launcher3.graphics
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
+import android.animation.ValueAnimator.AnimatorUpdateListener
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Matrix
@@ -41,7 +42,6 @@ import androidx.graphics.shapes.SvgPathParser
import androidx.graphics.shapes.rectangle
import androidx.graphics.shapes.toPath
import androidx.graphics.shapes.transformed
-import com.android.launcher3.anim.RoundedRectRevealOutlineProvider
import com.android.launcher3.icons.GraphicsUtils
import com.android.launcher3.views.ClipPathView
@@ -127,16 +127,20 @@ interface ShapeDelegate {
endRadius: Float,
isReversed: Boolean,
): ValueAnimator where T : View, T : ClipPathView {
- return object :
- RoundedRectRevealOutlineProvider(
- (startRect.width() / 2f) * radiusRatio,
- endRadius,
- startRect,
- endRect,
- ) {
- override fun shouldRemoveElevationDuringAnimation() = true
- }
- .createRevealAnimator(target, isReversed)
+ val startRadius = (startRect.width() / 2f) * radiusRatio
+ return ClipAnimBuilder(target) { progress, path ->
+ val radius = (1 - progress) * startRadius + progress * endRadius
+ path.addRoundRect(
+ (1 - progress) * startRect.left + progress * endRect.left,
+ (1 - progress) * startRect.top + progress * endRect.top,
+ (1 - progress) * startRect.right + progress * endRect.right,
+ (1 - progress) * startRect.bottom + progress * endRect.bottom,
+ radius,
+ radius,
+ Path.Direction.CW,
+ )
+ }
+ .toAnim(isReversed)
}
override fun equals(other: Any?) =
@@ -220,38 +224,44 @@ interface ShapeDelegate {
),
)
- val va =
- if (isReversed) ValueAnimator.ofFloat(1f, 0f) else ValueAnimator.ofFloat(0f, 1f)
- va.addListener(
- object : AnimatorListenerAdapter() {
- private var oldOutlineProvider: ViewOutlineProvider? = null
-
- override fun onAnimationStart(animation: Animator) {
- target.apply {
- oldOutlineProvider = outlineProvider
- outlineProvider = null
- translationZ = -target.elevation
- }
- }
+ return ClipAnimBuilder(target, morph::toPath).toAnim(isReversed)
+ }
+ }
- override fun onAnimationEnd(animation: Animator) {
- target.apply {
- translationZ = 0f
- setClipPath(null)
- outlineProvider = oldOutlineProvider
- }
- }
- }
- )
+ private class ClipAnimBuilder<T>(val target: T, val pathProvider: (Float, Path) -> Unit) :
+ AnimatorListenerAdapter(), AnimatorUpdateListener where T : View, T : ClipPathView {
- val path = Path()
- va.addUpdateListener { anim: ValueAnimator ->
- path.reset()
- morph.toPath(anim.animatedValue as Float, path)
- target.setClipPath(path)
+ private var oldOutlineProvider: ViewOutlineProvider? = null
+ val path = Path()
+
+ override fun onAnimationStart(animation: Animator) {
+ target.apply {
+ oldOutlineProvider = outlineProvider
+ outlineProvider = null
+ translationZ = -target.elevation
+ }
+ }
+
+ override fun onAnimationEnd(animation: Animator) {
+ target.apply {
+ translationZ = 0f
+ setClipPath(null)
+ outlineProvider = oldOutlineProvider
}
- return va
}
+
+ override fun onAnimationUpdate(anim: ValueAnimator) {
+ path.reset()
+ pathProvider.invoke(anim.animatedValue as Float, path)
+ target.setClipPath(path)
+ }
+
+ fun toAnim(isReversed: Boolean) =
+ (if (isReversed) ValueAnimator.ofFloat(1f, 0f) else ValueAnimator.ofFloat(0f, 1f))
+ .also {
+ it.addListener(this)
+ it.addUpdateListener(this)
+ }
}
companion object {
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 77d0d7656b..efe61572fe 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -21,7 +21,6 @@ import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
-import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED;
@@ -466,7 +465,7 @@ public class LoaderCursor extends CursorWrapper {
public boolean commitDeleted() {
if (mItemsToRemove.size() > 0) {
// Remove dead items
- mModel.getModelDbController().delete(TABLE_NAME,
+ mModel.getModelDbController().delete(
Utilities.createDbSelectionQuery(Favorites._ID, mItemsToRemove), null);
return true;
}
@@ -492,7 +491,7 @@ public class LoaderCursor extends CursorWrapper {
// Update restored items that no longer require special handling
ContentValues values = new ContentValues();
values.put(Favorites.RESTORED, 0);
- mModel.getModelDbController().update(TABLE_NAME, values,
+ mModel.getModelDbController().update(values,
Utilities.createDbSelectionQuery(Favorites._ID, mRestoredRows), null);
}
if (mRestoreEventLogger != null) {
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 73af6a221a..78e5d898cd 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -23,7 +23,6 @@ import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE;
import static com.android.launcher3.LauncherPrefs.SHOULD_SHOW_SMARTSPACE;
import static com.android.launcher3.LauncherSettings.Favorites.DESKTOP_ICON_FLAG;
-import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.icons.CacheableShortcutInfo.convertShortcutsToCacheableShortcuts;
import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
@@ -485,7 +484,7 @@ public class LoaderTask implements Runnable {
mShortcutKeyToPinnedShortcuts = new HashMap<>();
final LoaderCursor c = mLoaderCursorFactory.createLoaderCursor(
- dbController.query(TABLE_NAME, null, selection, null, null),
+ dbController.query(null, selection, null, null),
mUserManagerState,
mIsRestoreFromBackup ? restoreEventLogger : null);
final Bundle extras = c.getExtras();
diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java
index feae632bc5..64b9c1c9cd 100644
--- a/src/com/android/launcher3/model/ModelDbController.java
+++ b/src/com/android/launcher3/model/ModelDbController.java
@@ -73,6 +73,8 @@ import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Utilities;
import com.android.launcher3.backuprestore.LauncherRestoreEventLogger;
import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError;
+import com.android.launcher3.dagger.ApplicationContext;
+import com.android.launcher3.dagger.LauncherAppSingleton;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.provider.LauncherDbUtils;
@@ -91,10 +93,13 @@ import java.io.StringReader;
import java.util.List;
import java.util.stream.Collectors;
+import javax.inject.Inject;
+
/**
* Utility class which maintains an instance of Launcher database and provides utility methods
* around it.
*/
+@LauncherAppSingleton
public class ModelDbController {
private static final String TAG = "ModelDbController";
@@ -105,17 +110,25 @@ public class ModelDbController {
protected DatabaseHelper mOpenHelper;
private final Context mContext;
-
- public ModelDbController(Context context) {
+ private final InvariantDeviceProfile mIdp;
+ private final LauncherPrefs mPrefs;
+ private final UserCache mUserCache;
+
+ @Inject
+ ModelDbController(
+ @ApplicationContext Context context,
+ InvariantDeviceProfile idp,
+ LauncherPrefs prefs,
+ UserCache userCache) {
mContext = context;
+ mIdp = idp;
+ mPrefs = prefs;
+ mUserCache = userCache;
}
private void printDBs(String prefix) {
try {
- File directory = new File(
- mContext.getDatabasePath(InvariantDeviceProfile.INSTANCE.get(mContext).dbFile)
- .getParent()
- );
+ File directory = new File(mContext.getDatabasePath(mIdp.dbFile).getParent());
if (directory.exists()) {
for (File file : directory.listFiles()) {
Log.d("b/353505773", prefix + "Database file: " + file.getName());
@@ -130,9 +143,9 @@ public class ModelDbController {
private synchronized void createDbIfNotExists() {
if (mOpenHelper == null) {
- String dbFile = LauncherPrefs.get(mContext).get(DB_FILE);
+ String dbFile = mPrefs.get(DB_FILE);
if (dbFile.isEmpty()) {
- dbFile = InvariantDeviceProfile.INSTANCE.get(mContext).dbFile;
+ dbFile = mIdp.dbFile;
}
mOpenHelper = createDatabaseHelper(false /* forMigration */, dbFile);
printDBs("before: ");
@@ -144,7 +157,7 @@ public class ModelDbController {
protected DatabaseHelper createDatabaseHelper(boolean forMigration, String dbFile) {
// Set the flag for empty DB
Runnable onEmptyDbCreateCallback = forMigration ? () -> { }
- : () -> LauncherPrefs.get(mContext).putSync(getEmptyDbCreatedKey(dbFile).to(true));
+ : () -> mPrefs.putSync(getEmptyDbCreatedKey(dbFile).to(true));
DatabaseHelper databaseHelper = new DatabaseHelper(mContext, dbFile,
this::getSerialNumberForUser, onEmptyDbCreateCallback);
@@ -169,12 +182,12 @@ public class ModelDbController {
* Refer {@link SQLiteDatabase#query}
*/
@WorkerThread
- public Cursor query(String table, String[] projection, String selection,
+ public Cursor query(String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
createDbIfNotExists();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
Cursor result = db.query(
- table, projection, selection, selectionArgs, null, null, sortOrder);
+ TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
final Bundle extra = new Bundle();
extra.putString(EXTRA_DB_NAME, mOpenHelper.getDatabaseName());
@@ -186,12 +199,12 @@ public class ModelDbController {
* Refer {@link SQLiteDatabase#insert(String, String, ContentValues)}
*/
@WorkerThread
- public int insert(String table, ContentValues initialValues) {
+ public int insert(ContentValues initialValues) {
createDbIfNotExists();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
addModifiedTime(initialValues);
- int rowId = mOpenHelper.dbInsertAndCheck(db, table, initialValues);
+ int rowId = mOpenHelper.dbInsertAndCheck(db, TABLE_NAME, initialValues);
if (rowId >= 0) {
onAddOrDeleteOp(db);
}
@@ -202,11 +215,11 @@ public class ModelDbController {
* Refer {@link SQLiteDatabase#delete(String, String, String[])}
*/
@WorkerThread
- public int delete(String table, String selection, String[] selectionArgs) {
+ public int delete(String selection, String[] selectionArgs) {
createDbIfNotExists();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- int count = db.delete(table, selection, selectionArgs);
+ int count = db.delete(TABLE_NAME, selection, selectionArgs);
if (count > 0) {
onAddOrDeleteOp(db);
}
@@ -217,14 +230,12 @@ public class ModelDbController {
* Refer {@link SQLiteDatabase#update(String, ContentValues, String, String[])}
*/
@WorkerThread
- public int update(String table, ContentValues values,
- String selection, String[] selectionArgs) {
+ public int update(ContentValues values, String selection, String[] selectionArgs) {
createDbIfNotExists();
addModifiedTime(values);
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- int count = db.update(table, values, selection, selectionArgs);
- return count;
+ return db.update(TABLE_NAME, values, selection, selectionArgs);
}
/**
@@ -261,7 +272,7 @@ public class ModelDbController {
public void createEmptyDB() {
createDbIfNotExists();
mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
- LauncherPrefs.get(mContext).putSync(getEmptyDbCreatedKey().to(true));
+ mPrefs.putSync(getEmptyDbCreatedKey().to(true));
}
/**
@@ -292,7 +303,6 @@ public class ModelDbController {
mOpenHelper.getReadableDatabase(), Favorites.HYBRID_HOTSEAT_BACKUP_TABLE);
}
-
/**
* Resets the launcher DB if we should reset it.
*/
@@ -302,11 +312,10 @@ public class ModelDbController {
}
FileLog.d(TAG, "resetLauncherDb: Migration failed: resetting launcher database");
createEmptyDB();
- LauncherPrefs.get(mContext).putSync(
- getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()).to(true));
+ mPrefs.putSync(getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()).to(true));
// Write the grid state to avoid another migration
- new DeviceGridState(LauncherAppState.getIDP(mContext)).writeToPrefs(mContext);
+ new DeviceGridState(mIdp).writeToPrefs(mContext);
}
/**
@@ -326,7 +335,7 @@ public class ModelDbController {
}
private boolean isThereExistingDb() {
- if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey())) {
+ if (mPrefs.get(getEmptyDbCreatedKey())) {
// If we already have a new DB, ignore migration
FileLog.d(TAG, "isThereExistingDb: new DB already created, skipping migration");
return true;
@@ -335,8 +344,7 @@ public class ModelDbController {
}
private boolean isGridMigrationNecessary() {
- InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
- if (GridSizeMigrationDBController.needsToMigrate(mContext, idp)) {
+ if (GridSizeMigrationDBController.needsToMigrate(mContext, mIdp)) {
return true;
}
FileLog.d(TAG, "isGridMigrationNecessary: no grid migration needed");
@@ -344,8 +352,7 @@ public class ModelDbController {
}
private boolean isCurrentDbSameAsTarget() {
- InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
- String targetDbName = new DeviceGridState(idp).getDbFile();
+ String targetDbName = new DeviceGridState(mIdp).getDbFile();
if (TextUtils.equals(targetDbName, mOpenHelper.getDatabaseName())) {
FileLog.e(TAG, "isCurrentDbSameAsTarget: target db is same as current"
+ " current db: " + mOpenHelper.getDatabaseName()
@@ -367,7 +374,6 @@ public class ModelDbController {
return;
}
- InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
DatabaseHelper oldHelper = mOpenHelper;
// We save the existing db's before creating the destination db helper so we know what logic
@@ -376,12 +382,12 @@ public class ModelDbController {
.filter(dbName -> mContext.getDatabasePath(dbName).exists())
.collect(Collectors.toList());
- mOpenHelper = createDatabaseHelper(true, new DeviceGridState(idp).getDbFile());
+ mOpenHelper = createDatabaseHelper(true, new DeviceGridState(mIdp).getDbFile());
try {
// This is the current grid we have, given by the mContext
DeviceGridState srcDeviceState = new DeviceGridState(mContext);
// This is the state we want to migrate to that is given by the idp
- DeviceGridState destDeviceState = new DeviceGridState(idp);
+ DeviceGridState destDeviceState = new DeviceGridState(mIdp);
boolean isDestNewDb = !existingDBs.contains(destDeviceState.getDbFile());
GridSizeMigrationLogic gridSizeMigrationLogic = new GridSizeMigrationLogic();
@@ -404,10 +410,10 @@ public class ModelDbController {
ModelDelegate modelDelegate) {
if (!migrateGridIfNeeded(modelDelegate)) {
if (restoreEventLogger != null) {
- if (LauncherPrefs.get(mContext).get(NO_DB_FILES_RESTORED)) {
+ if (mPrefs.get(NO_DB_FILES_RESTORED)) {
restoreEventLogger.logLauncherItemsRestoreFailed(DATA_TYPE_DB_FILE, 1,
RestoreError.DATABASE_FILE_NOT_RESTORED);
- LauncherPrefs.get(mContext).put(NO_DB_FILES_RESTORED, false);
+ mPrefs.put(NO_DB_FILES_RESTORED, false);
FileLog.d(TAG, "There is no data to migrate: resetting launcher database");
} else {
restoreEventLogger.logLauncherItemsRestored(DATA_TYPE_DB_FILE, 1);
@@ -416,11 +422,10 @@ public class ModelDbController {
}
FileLog.d(TAG, "tryMigrateDB: Migration failed: resetting launcher database");
createEmptyDB();
- LauncherPrefs.get(mContext).putSync(
- getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()).to(true));
+ mPrefs.putSync(getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()).to(true));
// Write the grid state to avoid another migration
- new DeviceGridState(LauncherAppState.getIDP(mContext)).writeToPrefs(mContext);
+ new DeviceGridState(mIdp).writeToPrefs(mContext);
} else if (restoreEventLogger != null) {
restoreEventLogger.logLauncherItemsRestored(DATA_TYPE_DB_FILE, 1);
}
@@ -434,17 +439,16 @@ public class ModelDbController {
*/
private boolean migrateGridIfNeeded(ModelDelegate modelDelegate) {
createDbIfNotExists();
- if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey())) {
+ if (mPrefs.get(getEmptyDbCreatedKey())) {
// If we have already create a new DB, ignore migration
FileLog.d(TAG, "migrateGridIfNeeded: new DB already created, skipping migration");
return false;
}
- InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
- if (!GridSizeMigrationDBController.needsToMigrate(mContext, idp)) {
+ if (!GridSizeMigrationDBController.needsToMigrate(mContext, mIdp)) {
FileLog.d(TAG, "migrateGridIfNeeded: no grid migration needed");
return true;
}
- String targetDbName = new DeviceGridState(idp).getDbFile();
+ String targetDbName = new DeviceGridState(mIdp).getDbFile();
if (TextUtils.equals(targetDbName, mOpenHelper.getDatabaseName())) {
FileLog.e(TAG, "migrateGridIfNeeded: target db is same as current"
+ " current db: " + mOpenHelper.getDatabaseName()
@@ -462,7 +466,7 @@ public class ModelDbController {
// This is the current grid we have, given by the mContext
DeviceGridState srcDeviceState = new DeviceGridState(mContext);
// This is the state we want to migrate to that is given by the idp
- DeviceGridState destDeviceState = new DeviceGridState(idp);
+ DeviceGridState destDeviceState = new DeviceGridState(mIdp);
boolean isDestNewDb = !existingDBs.contains(destDeviceState.getDbFile());
return GridSizeMigrationDBController.migrateGridIfNeeded(mContext, srcDeviceState,
destDeviceState, mOpenHelper, oldHelper.getWritableDatabase(), isDestNewDb,
@@ -611,7 +615,7 @@ public class ModelDbController {
}
private void clearFlagEmptyDbCreated() {
- LauncherPrefs.get(mContext).removeSync(getEmptyDbCreatedKey());
+ mPrefs.removeSync(getEmptyDbCreatedKey());
}
/**
@@ -625,7 +629,7 @@ public class ModelDbController {
public synchronized void loadDefaultFavoritesIfNecessary() {
createDbIfNotExists();
- if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey())) {
+ if (mPrefs.get(getEmptyDbCreatedKey())) {
Log.d(TAG, "loading default workspace");
LauncherWidgetHolder widgetHolder = mOpenHelper.newLauncherWidgetHolder();
@@ -737,10 +741,9 @@ public class ModelDbController {
}
private DefaultLayoutParser getDefaultLayoutParser(LauncherWidgetHolder widgetHolder) {
- InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
- int defaultLayout = idp.demoModeLayoutId != 0
+ int defaultLayout = mIdp.demoModeLayoutId != 0
&& mContext.getSystemService(UserManager.class).isDemoUser()
- ? idp.demoModeLayoutId : idp.defaultLayoutId;
+ ? mIdp.demoModeLayoutId : mIdp.defaultLayoutId;
return new DefaultLayoutParser(mContext, widgetHolder,
mOpenHelper, mContext.getResources(), defaultLayout);
@@ -766,6 +769,6 @@ public class ModelDbController {
* Returns the serial number for the provided user
*/
public long getSerialNumberForUser(UserHandle user) {
- return UserCache.INSTANCE.get(mContext).getSerialNumberForUser(user);
+ return mUserCache.getSerialNumberForUser(user);
}
}
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index 0332775224..2650e03c63 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -16,7 +16,6 @@
package com.android.launcher3.model;
-import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.provider.LauncherDbUtils.itemIdMatch;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -229,7 +228,7 @@ public class ModelWriter {
}).executeOnModelThread();
}
- private void notifyItemModified(ItemInfo item) {
+ public void notifyItemModified(ItemInfo item) {
notifyOtherCallbacks(c -> c.bindItemsModified(Collections.singletonList(item)));
}
@@ -253,7 +252,7 @@ public class ModelWriter {
item.onAddToDatabase(writer);
writer.put(Favorites._ID, item.id);
- mModel.getModelDbController().insert(Favorites.TABLE_NAME, writer.getValues(mContext));
+ mModel.getModelDbController().insert(writer.getValues(mContext));
synchronized (mBgDataModel) {
checkItemInfoLocked(item.id, item, stackTrace);
mBgDataModel.addItem(mContext, item, true);
@@ -292,7 +291,7 @@ public class ModelWriter {
notifyDelete(items);
enqueueDeleteRunnable(newModelTask(() -> {
for (ItemInfo item : items) {
- mModel.getModelDbController().delete(TABLE_NAME, itemIdMatch(item.id), null);
+ mModel.getModelDbController().delete(itemIdMatch(item.id), null);
mBgDataModel.removeItem(mContext, item);
verifier.verifyModel();
}
@@ -307,12 +306,12 @@ public class ModelWriter {
notifyDelete(Collections.singleton(info));
enqueueDeleteRunnable(newModelTask(() -> {
- mModel.getModelDbController().delete(Favorites.TABLE_NAME,
+ mModel.getModelDbController().delete(
Favorites.CONTAINER + "=" + info.id, null);
mBgDataModel.removeItem(mContext, info.getContents());
info.getContents().clear();
- mModel.getModelDbController().delete(Favorites.TABLE_NAME,
+ mModel.getModelDbController().delete(
Favorites._ID + "=" + info.id, null);
mBgDataModel.removeItem(mContext, info);
verifier.verifyModel();
@@ -411,7 +410,7 @@ public class ModelWriter {
@Override
public void runImpl() {
mModel.getModelDbController().update(
- TABLE_NAME, mWriter.get().getValues(mContext), itemIdMatch(mItemId), null);
+ mWriter.get().getValues(mContext), itemIdMatch(mItemId), null);
updateItemArrays(mItem, mItemId);
}
}
@@ -433,7 +432,7 @@ public class ModelWriter {
ItemInfo item = mItems.get(i);
final int itemId = item.id;
mModel.getModelDbController().update(
- TABLE_NAME, mValues.get(i), itemIdMatch(itemId), null);
+ mValues.get(i), itemIdMatch(itemId), null);
updateItemArrays(item, itemId);
}
t.commit();
diff --git a/src/com/android/launcher3/model/data/FolderInfo.java b/src/com/android/launcher3/model/data/FolderInfo.java
index 9656ac10b2..4c792a7672 100644
--- a/src/com/android/launcher3/model/data/FolderInfo.java
+++ b/src/com/android/launcher3/model/data/FolderInfo.java
@@ -20,6 +20,9 @@ import static android.text.TextUtils.isEmpty;
import static androidx.core.util.Preconditions.checkNotNull;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
import static com.android.launcher3.logger.LauncherAtom.Attribute.EMPTY_LABEL;
import static com.android.launcher3.logger.LauncherAtom.Attribute.MANUAL_LABEL;
import static com.android.launcher3.logger.LauncherAtom.Attribute.SUGGESTED_LABEL;
@@ -30,8 +33,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderNameInfos;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logger.LauncherAtom.Attribute;
@@ -42,8 +43,6 @@ import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.util.ContentWriter;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
import java.util.OptionalInt;
import java.util.stream.IntStream;
@@ -52,18 +51,6 @@ import java.util.stream.IntStream;
*/
public class FolderInfo extends CollectionInfo {
- public static final int NO_FLAGS = 0x00000000;
-
- /**
- * The folder is locked in sorted mode
- */
- public static final int FLAG_ITEMS_SORTED = 0x00000001;
-
- /**
- * It is a work folder
- */
- public static final int FLAG_WORK_FOLDER = 0x00000002;
-
/**
* The multi-page animation has run for this folder
*/
@@ -95,8 +82,6 @@ public class FolderInfo extends CollectionInfo {
}
}
- public static final String EXTRA_FOLDER_SUGGESTIONS = "suggest";
-
public int options;
public FolderNameInfos suggestedFolderNames;
@@ -106,61 +91,16 @@ public class FolderInfo extends CollectionInfo {
*/
private final ArrayList<ItemInfo> contents = new ArrayList<>();
- private ArrayList<FolderListener> mListeners = new ArrayList<>();
-
public FolderInfo() {
itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
}
- /** Adds a app or shortcut to the contents ArrayList without animation. */
@Override
public void add(@NonNull ItemInfo item) {
- add(item, false /* animate */);
- }
-
- /**
- * Add an app or shortcut
- *
- * @param item
- */
- public void add(ItemInfo item, boolean animate) {
- add(item, getContents().size(), animate);
- }
-
- /**
- * Add an app or shortcut for a specified rank.
- */
- public void add(ItemInfo item, int rank, boolean animate) {
- if (!Folder.willAccept(item)) {
+ if (!willAcceptItemType(item.itemType)) {
throw new RuntimeException("tried to add an illegal type into a folder");
}
-
- rank = Utilities.boundToRange(rank, 0, getContents().size());
- getContents().add(rank, item);
- for (int i = 0; i < mListeners.size(); i++) {
- mListeners.get(i).onAdd(item, rank);
- }
- itemsChanged(animate);
- }
-
- /**
- * Remove an app or shortcut. Does not change the DB.
- *
- * @param item
- */
- public void remove(ItemInfo item, boolean animate) {
- removeAll(Collections.singletonList(item), animate);
- }
-
- /**
- * Remove all matching app or shortcut. Does not change the DB.
- */
- public void removeAll(List<ItemInfo> items, boolean animate) {
- contents.removeAll(items);
- for (int i = 0; i < mListeners.size(); i++) {
- mListeners.get(i).onRemove(items);
- }
- itemsChanged(animate);
+ getContents().add(item);
}
/**
@@ -197,28 +137,6 @@ public class FolderInfo extends CollectionInfo {
writer.put(LauncherSettings.Favorites.OPTIONS, options);
}
- public void addListener(FolderListener listener) {
- mListeners.add(listener);
- }
-
- public void removeListener(FolderListener listener) {
- mListeners.remove(listener);
- }
-
- public void itemsChanged(boolean animate) {
- for (int i = 0; i < mListeners.size(); i++) {
- mListeners.get(i).onItemsChanged(animate);
- }
- }
-
- public interface FolderListener {
- void onAdd(ItemInfo item, int rank);
- void onRemove(List<ItemInfo> item);
- void onItemsChanged(boolean animate);
- void onTitleChanged(CharSequence title);
-
- }
-
public boolean hasOption(int optionFlag) {
return (options & optionFlag) != 0;
}
@@ -261,7 +179,6 @@ public class FolderInfo extends CollectionInfo {
.build();
}
- @Override
public void setTitle(@Nullable CharSequence title, ModelWriter modelWriter) {
// Updating label from null to empty is considered as false touch.
// Retaining null title(ie., UNLABELED state) allows auto-labeling when new items added.
@@ -289,10 +206,6 @@ public class FolderInfo extends CollectionInfo {
if (modelWriter != null) {
modelWriter.updateItemInDatabase(this);
}
-
- for (int i = 0; i < mListeners.size(); i++) {
- mListeners.get(i).onTitleChanged(title);
- }
}
/**
@@ -401,4 +314,13 @@ public class FolderInfo extends CollectionInfo {
}
return LauncherAtom.ToState.TO_STATE_UNSPECIFIED;
}
+
+ /**
+ * Checks if {@code itemType} is a type that can be placed in folders.
+ */
+ public static boolean willAcceptItemType(int itemType) {
+ return itemType == ITEM_TYPE_APPLICATION
+ || itemType == ITEM_TYPE_DEEP_SHORTCUT
+ || itemType == ITEM_TYPE_APP_PAIR;
+ }
}
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 588e75959e..ad7696cd15 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -61,7 +61,6 @@ import com.android.launcher3.logger.LauncherAtom.ShortcutsContainer;
import com.android.launcher3.logger.LauncherAtom.TaskSwitcherContainer;
import com.android.launcher3.logger.LauncherAtom.WallpapersContainer;
import com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers;
-import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ContentWriter;
@@ -536,14 +535,6 @@ public class ItemInfo {
}
/**
- * Sets the title of the item and writes to DB model if needed.
- */
- public void setTitle(@Nullable final CharSequence title,
- @Nullable final ModelWriter modelWriter) {
- this.title = title;
- }
-
- /**
* Returns a string ID that is stable for a user session, but may not be persisted
*/
@Nullable
diff --git a/src/com/android/launcher3/pageindicators/PageIndicator.java b/src/com/android/launcher3/pageindicators/PageIndicator.java
index 0640bf3672..a6f76c4d44 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicator.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.pageindicators;
+import java.util.function.Consumer;
+
/**
* Base class for a page indicator.
*/
@@ -27,6 +29,14 @@ public interface PageIndicator {
void setMarkersCount(int numMarkers);
/**
+ * This is only going to be used by the FolderPagedView's PageIndicator. A refactor is planned
+ * to separate the two purposes of this class, but in the meantime, this indicator will serve to
+ * let the folder snap to the page of its click, and also tell the PageIndicator not to draw
+ * arrows if the click listener is null (at least until after this is refactored).
+ */
+ void setArrowClickListener(Consumer<Direction> listener);
+
+ /**
* Sets a flag indicating whether to pause scroll.
* <p>Should be set to {@code true} while the screen is binding or new data is being applied,
* and to {@code false} once done. This prevents animation conflicts due to scrolling during
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorArrowClickListener.kt b/src/com/android/launcher3/pageindicators/PageIndicatorArrowClickListener.kt
new file mode 100644
index 0000000000..970d210ad9
--- /dev/null
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorArrowClickListener.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2025 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.pageindicators
+
+interface PageIndicatorArrowClickListener {
+ fun onArrowClick(direction: Direction)
+}
+
+enum class Direction {
+ END,
+ START,
+}
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index a9a26a1631..384f87623a 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -32,11 +32,13 @@ import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.graphics.drawable.VectorDrawable;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.IntProperty;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewOutlineProvider;
@@ -51,6 +53,8 @@ import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.Themes;
+import java.util.function.Consumer;
+
/**
* {@link PageIndicator} which shows dots per page. The active page is shown with the current
* accent color.
@@ -71,6 +75,12 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator
private static final int ENTER_ANIMATION_STAGGERED_DELAY = 150;
private static final int ENTER_ANIMATION_DURATION = 400;
+ private static final int LARGE_HEIGHT_MULTIPLIER = 12;
+ private static final int SMALL_HEIGHT_MULTIPLIER = 4;
+ private static final int LARGE_WIDTH_MULTIPLIER = 5;
+ private static final int SMALL_WIDTH_MULTIPLIER = 3;
+ private static final float ARROW_TOUCH_BOX_FACTOR = 5f;
+
private static final int PAGE_INDICATOR_ALPHA = 255;
private static final int DOT_ALPHA = 128;
private static final float DOT_ALPHA_FRACTION = 0.5f;
@@ -78,12 +88,14 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator
private static final int VISIBLE_ALPHA = 255;
private static final int INVISIBLE_ALPHA = 0;
private Paint mPaginationPaint;
+ private Consumer<Direction> mOnArrowClickListener;
// This value approximately overshoots to 1.5 times the original size.
private static final float ENTER_ANIMATION_OVERSHOOT_TENSION = 4.9f;
// This is used to optimize the onDraw method by not constructing a new RectF each draw.
private static final RectF sTempRect = new RectF();
+ private static final RectF sLastActiveRect = new RectF();
private static final FloatProperty<PageIndicatorDots> CURRENT_POSITION =
new FloatProperty<PageIndicatorDots>("current_position") {
@@ -102,23 +114,27 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator
private static final IntProperty<PageIndicatorDots> PAGINATION_ALPHA =
new IntProperty<PageIndicatorDots>("pagination_alpha") {
- @Override
- public Integer get(PageIndicatorDots obj) {
- return obj.mPaginationPaint.getAlpha();
- }
+ @Override
+ public Integer get(PageIndicatorDots obj) {
+ return obj.mPaginationPaint.getAlpha();
+ }
- @Override
- public void setValue(PageIndicatorDots obj, int alpha) {
- obj.mPaginationPaint.setAlpha(alpha);
- obj.invalidate();
- }
- };
+ @Override
+ public void setValue(PageIndicatorDots obj, int alpha) {
+ obj.mPaginationPaint.setAlpha(alpha);
+ obj.invalidate();
+ }
+ };
private final Handler mDelayedPaginationFadeHandler = new Handler(Looper.getMainLooper());
private final float mDotRadius;
private final float mGapWidth;
private final float mCircleGap;
private final boolean mIsRtl;
+ private final VectorDrawable mArrowRight;
+ private final VectorDrawable mArrowLeft;
+ private final Rect mArrowRightBounds = new Rect();
+ private final Rect mArrowLeftBounds = new Rect();
private int mNumPages;
private int mActivePage;
@@ -170,6 +186,8 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator
: DOT_GAP_FACTOR * mDotRadius;
setOutlineProvider(new MyOutlineProver());
mIsRtl = Utilities.isRtl(getResources());
+ mArrowRight = (VectorDrawable) getResources().getDrawable(R.drawable.ic_chevron_end);
+ mArrowLeft = (VectorDrawable) getResources().getDrawable(R.drawable.ic_chevron_start);
}
@Override
@@ -408,6 +426,11 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator
}
@Override
+ public void setArrowClickListener(Consumer<Direction> listener) {
+ mOnArrowClickListener = listener;
+ }
+
+ @Override
public void setPauseScroll(boolean pause, boolean isTwoPanels) {
mIsTwoPanels = isTwoPanels;
@@ -422,11 +445,16 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO(b/394355070): Verify Folder Entry Animation works correctly with visual updates
- // Add extra spacing of mDotRadius on all sides so than entry animation could be run.
+ // Add extra spacing of mDotRadius on all sides so than entry animation could be run
+ // and so the hitboxes of arrows can be clicked easier.
int width = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY ?
- MeasureSpec.getSize(widthMeasureSpec) : (int) ((mNumPages * 3 + 2) * mDotRadius);
+ MeasureSpec.getSize(widthMeasureSpec)
+ : (int) ((mNumPages * ((enableLauncherVisualRefresh())
+ ? LARGE_WIDTH_MULTIPLIER : SMALL_WIDTH_MULTIPLIER) + 2) * mDotRadius);
int height = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY
- ? MeasureSpec.getSize(heightMeasureSpec) : (int) (4 * mDotRadius);
+ ? MeasureSpec.getSize(heightMeasureSpec)
+ : (int) (((enableLauncherVisualRefresh())
+ ? LARGE_HEIGHT_MULTIPLIER : SMALL_HEIGHT_MULTIPLIER) * mDotRadius);
setMeasuredDimension(width, height);
}
@@ -446,18 +474,51 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator
float y = getHeight() / 2;
if (mEntryAnimationRadiusFactors != null) {
- // During entry animation, only draw the circles
- // TODO(b/394355070): Verify Folder Entry Animation works correctly - visual updates
+ if (enableLauncherVisualRefresh()) {
+ x -= mDotRadius;
+ if (mIsRtl) {
+ x = getWidth() - x;
+ circleGap = -circleGap;
+ }
+ sTempRect.top = y - mDotRadius;
+ sTempRect.bottom = y + mDotRadius;
- if (mIsRtl) {
- x = getWidth() - x;
- circleGap = -circleGap;
- }
- for (int i = 0; i < mEntryAnimationRadiusFactors.length; i++) {
- mPaginationPaint.setAlpha(i == mActivePage ? PAGE_INDICATOR_ALPHA : DOT_ALPHA);
- canvas.drawCircle(x, y, mDotRadius * mEntryAnimationRadiusFactors[i],
- mPaginationPaint);
- x += circleGap;
+ for (int i = 0; i < mEntryAnimationRadiusFactors.length; i++) {
+ if (i == mActivePage) {
+ if (mIsRtl) {
+ sTempRect.left = x - (mDotRadius * 3);
+ sTempRect.right = x + mDotRadius;
+ x += circleGap - (mDotRadius * 2);
+ } else {
+ sTempRect.left = x - mDotRadius;
+ sTempRect.right = x + (mDotRadius * 3);
+ x += circleGap + (mDotRadius * 2);
+ }
+ scale(sTempRect, mEntryAnimationRadiusFactors[i]);
+ float scaledRadius = mDotRadius * mEntryAnimationRadiusFactors[i];
+ mPaginationPaint.setAlpha(PAGE_INDICATOR_ALPHA);
+ canvas.drawRoundRect(sTempRect, scaledRadius, scaledRadius,
+ mPaginationPaint);
+ } else {
+ mPaginationPaint.setAlpha(DOT_ALPHA);
+ canvas.drawCircle(x, y, mDotRadius * mEntryAnimationRadiusFactors[i],
+ mPaginationPaint);
+ x += circleGap;
+ }
+ }
+ } else {
+ // During entry animation, only draw the circles
+
+ if (mIsRtl) {
+ x = getWidth() - x;
+ circleGap = -circleGap;
+ }
+ for (int i = 0; i < mEntryAnimationRadiusFactors.length; i++) {
+ mPaginationPaint.setAlpha(i == mActivePage ? PAGE_INDICATOR_ALPHA : DOT_ALPHA);
+ canvas.drawCircle(x, y, mDotRadius * mEntryAnimationRadiusFactors[i],
+ mPaginationPaint);
+ x += circleGap;
+ }
}
} else {
// Save the current alpha value, so we can reset to it again after drawing the dots
@@ -471,12 +532,31 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator
sTempRect.bottom = y + mDotRadius;
sTempRect.left = x - diameter;
- float posDif = Math.abs(mLastPosition - mCurrentPosition);
+ float currentPosition = mCurrentPosition;
+ float lastPosition = mLastPosition;
+
+ if (mIsRtl) {
+ currentPosition = mNumPages - currentPosition - 1;
+ lastPosition = mNumPages - lastPosition - 1;
+ }
+ float posDif = Math.abs(lastPosition - currentPosition);
float boundedPosition = (posDif > 1)
- ? Math.round(mCurrentPosition)
- : mCurrentPosition;
+ ? Math.round(currentPosition)
+ : currentPosition;
float bounceProgress = (posDif > 1) ? posDif - 1 : 0;
- float bounceAdjustment = Math.abs(mCurrentPosition - boundedPosition) * diameter;
+ float bounceAdjustment = Math.abs(currentPosition - boundedPosition) * diameter;
+
+ if (mOnArrowClickListener != null && boundedPosition >= 1) {
+ // Here we draw the Left Arrow
+ mArrowLeft.setAlpha(alpha);
+ int size = (int) (mGapWidth * 4);
+ mArrowLeftBounds.left = (int) (sTempRect.left - mGapWidth - size);
+ mArrowLeftBounds.top = (int) (y - size / 2);
+ mArrowLeftBounds.right = (int) (sTempRect.left - mGapWidth);
+ mArrowLeftBounds.bottom = (int) (y + size / 2);
+ mArrowLeft.setBounds(mArrowLeftBounds);
+ mArrowLeft.draw(canvas);
+ }
// Here we draw the dots, one at a time from the left-most dot to the right-most dot
// 1.0 => 000000 000000111111 000000
@@ -498,10 +578,10 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator
// While the animation is shifting the active pagination dots size from
// the previously active one, to the newly active dot, there is no bounce
// adjustment. The bounce happens in the "Overshoot" phase of the animation.
- // mLastPosition is used to determine when the currentPosition is just
+ // lastPosition is used to determine when the currentPosition is just
// leaving the page, or if it is in the overshoot phase.
if (boundedPosition == i && bounceProgress != 0) {
- if (mLastPosition < mCurrentPosition) {
+ if (lastPosition < currentPosition) {
sTempRect.left -= bounceAdjustment;
} else {
sTempRect.right += bounceAdjustment;
@@ -510,19 +590,34 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator
} else {
sTempRect.right = sTempRect.left + diameter;
- if (mLastPosition == i && bounceProgress != 0) {
- if (mLastPosition > mCurrentPosition) {
+ if (lastPosition == i && bounceProgress != 0) {
+ if (lastPosition > currentPosition) {
sTempRect.left += bounceAdjustment;
} else {
sTempRect.right -= bounceAdjustment;
}
}
}
+ if (Math.round(mCurrentPosition) == i) {
+ sLastActiveRect.set(sTempRect);
+ }
canvas.drawRoundRect(sTempRect, mDotRadius, mDotRadius, mPaginationPaint);
// TODO(b/394355070) Verify RTL experience works correctly with visual updates
sTempRect.left = sTempRect.right + mGapWidth;
}
+
+ if (mOnArrowClickListener != null && boundedPosition <= mNumPages - 2) {
+ // Here we draw the Right Arrow
+ mArrowRight.setAlpha(alpha);
+ int size = (int) (mGapWidth * 4);
+ mArrowRightBounds.left = (int) sTempRect.left;
+ mArrowRightBounds.top = (int) (y - size / 2);
+ mArrowRightBounds.right = (int) (int) (sTempRect.left + size);
+ mArrowRightBounds.bottom = (int) (y + size / 2);
+ mArrowRight.setBounds(mArrowRightBounds);
+ mArrowRight.draw(canvas);
+ }
} else {
// Here we draw the dots
mPaginationPaint.setAlpha((int) (alpha * DOT_ALPHA_FRACTION));
@@ -541,6 +636,38 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator
}
}
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (mOnArrowClickListener == null) {
+ // No - Op. Don't care about touch events
+ } else if ((mIsRtl && withinExpandedBounds(mArrowRightBounds, ev))
+ || (!mIsRtl && withinExpandedBounds(mArrowLeftBounds, ev))) {
+ mOnArrowClickListener.accept(Direction.START);
+ } else if ((mIsRtl && withinExpandedBounds(mArrowLeftBounds, ev))
+ || (!mIsRtl && withinExpandedBounds(mArrowRightBounds, ev))) {
+ mOnArrowClickListener.accept(Direction.END);
+ }
+ return super.onTouchEvent(ev);
+ }
+
+ // For larger Touch box
+ private boolean withinExpandedBounds(Rect rect, MotionEvent ev) {
+ RectF scaledRect = new RectF(rect);
+ scale(scaledRect, ARROW_TOUCH_BOX_FACTOR);
+ return scaledRect.contains(ev.getX(), ev.getY());
+ }
+
+ private static void scale(RectF rect, float factor) {
+ float horizontalAdjustment = rect.width() * (factor - 1) / 2;
+ float verticalAdjustment = rect.height() * (factor - 1) / 2;
+
+ rect.top -= verticalAdjustment;
+ rect.bottom += verticalAdjustment;
+
+ rect.left -= horizontalAdjustment;
+ rect.right += horizontalAdjustment;
+ }
+
private RectF getActiveRect() {
float startCircle = (int) mCurrentPosition;
float delta = mCurrentPosition - startCircle;
@@ -593,8 +720,8 @@ public class PageIndicatorDots extends View implements Insettable, PageIndicator
@Override
public void getOutline(View view, Outline outline) {
if (mEntryAnimationRadiusFactors == null) {
- // TODO(b/394355070): Verify Outline works correctly with visual updates
- RectF activeRect = getActiveRect();
+ RectF activeRect = enableLauncherVisualRefresh()
+ ? sLastActiveRect : getActiveRect();
outline.setRoundRect(
(int) activeRect.left,
(int) activeRect.top,
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index aad1400865..39f68bfe70 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -16,9 +16,12 @@
package com.android.launcher3.popup;
+import static android.multiuser.Flags.enableMovingContentIntoPrivateSpace;
+
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
+import static com.android.launcher3.allapps.AlphabeticalAppsList.PRIVATE_SPACE_PACKAGE;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -65,6 +68,7 @@ import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@@ -207,7 +211,10 @@ public class PopupContainerWithArrow<T extends Context & ActivityContext>
container = (PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
R.layout.popup_container, launcher.getDragLayer(), false);
container.configureForLauncher(launcher, item);
- container.populateAndShowRows(icon, deepShortcutCount, systemShortcuts);
+ boolean shouldHideSystemShortcuts = enableMovingContentIntoPrivateSpace()
+ && Objects.equals(item.getTargetPackage(), PRIVATE_SPACE_PACKAGE);
+ container.populateAndShowRows(icon, deepShortcutCount,
+ shouldHideSystemShortcuts ? Collections.emptyList() : systemShortcuts);
launcher.refreshAndBindWidgetsForPackageUser(PackageUserKey.fromItemInfo(item));
container.requestFocus();
return container;
diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java
index 5c1a7553a5..95110329d3 100644
--- a/src/com/android/launcher3/popup/PopupDataProvider.java
+++ b/src/com/android/launcher3/popup/PopupDataProvider.java
@@ -26,7 +26,6 @@ import androidx.annotation.Nullable;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.allapps.ActivityAllAppsContainerView;
import com.android.launcher3.dot.DotInfo;
-import com.android.launcher3.dot.FolderDotInfo;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.model.data.FolderInfo;
@@ -76,11 +75,7 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan
((BubbleTextView) v).applyDotState(info, true /* animate */);
} else if (v instanceof FolderIcon icon
&& info instanceof FolderInfo fi && fi.anyMatch(matcher)) {
- FolderDotInfo folderDotInfo = new FolderDotInfo();
- for (ItemInfo si : fi.getContents()) {
- folderDotInfo.addDotInfo(getDotInfoForItem(si));
- }
- icon.setDotInfo(folderDotInfo);
+ icon.updateDotInfo();
}
// process all the shortcuts
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 23941bb1e6..f6ee26baa6 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -80,6 +80,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
@@ -206,7 +207,8 @@ public class RestoreDbTask {
LauncherRestoreEventLogger restoreEventLogger =
LauncherRestoreEventLogger.Companion.newInstance(context);
task.sanitizeDB(context, controller, db, backupManager, restoreEventLogger);
- task.restoreAppWidgetIdsIfExists(context, controller, restoreEventLogger);
+ task.restoreAppWidgetIdsIfExists(context, controller, restoreEventLogger,
+ () -> new AppWidgetHost(context, APPWIDGET_HOST_ID));
t.commit();
return true;
} catch (Exception e) {
@@ -438,14 +440,13 @@ public class RestoreDbTask {
@WorkerThread
@VisibleForTesting
void restoreAppWidgetIdsIfExists(Context context, ModelDbController controller,
- LauncherRestoreEventLogger restoreEventLogger) {
+ LauncherRestoreEventLogger restoreEventLogger, Supplier<AppWidgetHost> hostSupplier) {
LauncherPrefs lp = LauncherPrefs.get(context);
if (lp.has(APP_WIDGET_IDS, OLD_APP_WIDGET_IDS)) {
- AppWidgetHost host = new AppWidgetHost(context, APPWIDGET_HOST_ID);
restoreAppWidgetIds(context, controller, restoreEventLogger,
IntArray.fromConcatString(lp.get(OLD_APP_WIDGET_IDS)).toArray(),
IntArray.fromConcatString(lp.get(APP_WIDGET_IDS)).toArray(),
- host);
+ hostSupplier.get());
} else {
FileLog.d(TAG, "Did not receive new app widget id map during Launcher restore");
}
diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java
index 2cc4909712..f86fd6ac33 100644
--- a/src/com/android/launcher3/touch/AllAppsSwipeController.java
+++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java
@@ -22,6 +22,7 @@ import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.app.animation.Interpolators.FINAL_FRAME;
import static com.android.app.animation.Interpolators.INSTANT;
import static com.android.app.animation.Interpolators.LINEAR;
+import static com.android.app.animation.Interpolators.clampToProgress;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
@@ -39,6 +40,7 @@ import android.view.animation.Interpolator;
import com.android.app.animation.Interpolators;
import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Flags;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.states.StateAnimationConfig;
@@ -53,10 +55,10 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController {
private static final float ALL_APPS_SCRIM_VISIBLE_THRESHOLD = 0.1f;
private static final float ALL_APPS_STAGGERED_FADE_THRESHOLD = 0.5f;
- public static final Interpolator ALL_APPS_SCRIM_RESPONDER =
+ private static final Interpolator ALL_APPS_SCRIM_RESPONDER =
Interpolators.clampToProgress(
LINEAR, ALL_APPS_SCRIM_VISIBLE_THRESHOLD, ALL_APPS_STAGGERED_FADE_THRESHOLD);
- public static final Interpolator ALL_APPS_CLAMPING_RESPONDER =
+ private static final Interpolator ALL_APPS_CLAMPING_RESPONDER =
Interpolators.clampToProgress(
LINEAR,
1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD,
@@ -207,7 +209,16 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController {
}
config.setInterpolator(ANIM_WORKSPACE_SCALE, DECELERATED_EASE);
config.setInterpolator(ANIM_DEPTH, DECELERATED_EASE);
- if (launcher.getDeviceProfile().isPhone) {
+ if (Flags.allAppsBlur()) {
+ if (!config.isUserControlled()) {
+ config.setInterpolator(ANIM_DEPTH, EMPHASIZED_DECELERATE);
+ }
+ config.setInterpolator(ANIM_WORKSPACE_FADE,
+ clampToProgress(LINEAR, 1 - ALL_APPS_SCRIM_VISIBLE_THRESHOLD, 1));
+ config.setInterpolator(ANIM_HOTSEAT_FADE,
+ clampToProgress(LINEAR, 1 - ALL_APPS_SCRIM_VISIBLE_THRESHOLD, 1));
+ } else if (launcher.getDeviceProfile().isPhone) {
+ // On phones without blur, reveal the workspace and hotseat when leaving All Apps.
config.setInterpolator(ANIM_WORKSPACE_FADE, INSTANT);
config.setInterpolator(ANIM_HOTSEAT_FADE, INSTANT);
config.animFlags |= StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
@@ -253,7 +264,14 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController {
}
config.setInterpolator(ANIM_WORKSPACE_SCALE, DECELERATED_EASE);
config.setInterpolator(ANIM_DEPTH, DECELERATED_EASE);
- if (launcher.getDeviceProfile().isPhone) {
+ if (Flags.allAppsBlur()) {
+ config.setInterpolator(ANIM_DEPTH, LINEAR);
+ config.setInterpolator(ANIM_WORKSPACE_FADE,
+ clampToProgress(LINEAR, 0, ALL_APPS_SCRIM_VISIBLE_THRESHOLD));
+ config.setInterpolator(ANIM_HOTSEAT_FADE,
+ clampToProgress(LINEAR, 0, ALL_APPS_SCRIM_VISIBLE_THRESHOLD));
+ } else if (launcher.getDeviceProfile().isPhone) {
+ // On phones without blur, hide the workspace and hotseat when entering All Apps.
config.setInterpolator(ANIM_WORKSPACE_FADE, FINAL_FRAME);
config.setInterpolator(ANIM_HOTSEAT_FADE, FINAL_FRAME);
config.animFlags |= StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index d72e6f9e39..576f17616b 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -131,7 +131,7 @@ public class WorkspaceTouchListener extends GestureDetector.SimpleOnGestureListe
}
boolean isInAllAppsBottomSheet = mLauncher.isInState(ALL_APPS)
- && mLauncher.getDeviceProfile().isTablet;
+ && mLauncher.getDeviceProfile().shouldShowAllAppsOnSheet();
final boolean result;
if (mLongPressState == STATE_COMPLETED) {
diff --git a/src/com/android/launcher3/util/ContentWriter.java b/src/com/android/launcher3/util/ContentWriter.java
index 9910dc2e70..c2c1fee561 100644
--- a/src/com/android/launcher3/util/ContentWriter.java
+++ b/src/com/android/launcher3/util/ContentWriter.java
@@ -23,7 +23,6 @@ import android.os.UserHandle;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.GraphicsUtils;
import com.android.launcher3.model.ModelDbController;
@@ -107,7 +106,7 @@ public class ContentWriter {
public int commit() {
if (mCommitParams != null) {
return mCommitParams.mDbController.update(
- Favorites.TABLE_NAME, getValues(mContext),
+ getValues(mContext),
mCommitParams.mWhere, mCommitParams.mSelectionArgs);
}
return 0;
diff --git a/src/com/android/launcher3/util/SimpleBroadcastReceiver.java b/src/com/android/launcher3/util/SimpleBroadcastReceiver.java
index 7a40abe62b..53e0bce182 100644
--- a/src/com/android/launcher3/util/SimpleBroadcastReceiver.java
+++ b/src/com/android/launcher3/util/SimpleBroadcastReceiver.java
@@ -123,6 +123,32 @@ public class SimpleBroadcastReceiver extends BroadcastReceiver {
}
}
+ /**
+ * Same as {@link #register(Runnable, int, String...)} above but with additional permission
+ * params utilizine the original {@link Context}.
+ */
+ @AnyThread
+ public void register(@Nullable Runnable completionCallback,
+ String broadcastPermission, int flags, String... actions) {
+ if (Looper.myLooper() == mHandler.getLooper()) {
+ registerInternal(mContext, completionCallback, broadcastPermission, flags, actions);
+ } else {
+ mHandler.post(() -> registerInternal(mContext, completionCallback, broadcastPermission,
+ flags, actions));
+ }
+ }
+
+ /** Register broadcast receiver with permission and run completion callback if passed. */
+ @AnyThread
+ private void registerInternal(
+ @NonNull Context context, @Nullable Runnable completionCallback,
+ String broadcastPermission, int flags, String... actions) {
+ context.registerReceiver(this, getFilter(actions), broadcastPermission, null, flags);
+ if (completionCallback != null) {
+ completionCallback.run();
+ }
+ }
+
/** Same as {@link #register(Runnable, String...)} above but with pkg name. */
@AnyThread
public void registerPkgActions(@Nullable String pkg, String... actions) {
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index ce58de1ee5..ec71f3118a 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -54,8 +54,7 @@ public class ScrimView extends View implements Insettable {
}
@Override
- public void setInsets(Rect insets) {
- }
+ public void setInsets(Rect insets) {}
@Override
public boolean hasOverlappingRendering() {
diff --git a/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java b/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java
index e94f3a065d..185c3ee9ed 100644
--- a/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java
+++ b/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java
@@ -26,9 +26,12 @@ import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
+import com.android.launcher3.pageindicators.Direction;
import com.android.launcher3.pageindicators.PageIndicator;
import com.android.launcher3.views.ActivityContext;
+import java.util.function.Consumer;
+
/**
* Supports two indicator colors, dedicated for personal and work tabs.
*/
@@ -78,6 +81,11 @@ public class PersonalWorkSlidingTabStrip extends LinearLayout implements PageInd
}
@Override
+ public void setArrowClickListener(Consumer<Direction> listener) {
+ // No-Op. All Apps doesn't need accessibility arrows for single click navigation.
+ }
+
+ @Override
public boolean hasOverlappingRendering() {
return false;
}