Merge "Add originalView of the menu to SystemShortcut" into tm-dev
diff --git a/Android.bp b/Android.bp
index b3027bc..0a55675 100644
--- a/Android.bp
+++ b/Android.bp
@@ -228,7 +228,7 @@
],
}
-// Common source files used to build go launcher
+// Common source files used to build go launcher except go/src files
filegroup {
name: "launcher-go-src-no-build-config",
srcs: [
@@ -236,8 +236,6 @@
"src/**/*.kt",
"quickstep/src/**/*.java",
"quickstep/src/**/*.kt",
- "go/src/**/*.java",
- "go/src/**/*.kt",
"go/quickstep/src/**/*.java",
"go/quickstep/src/**/*.kt",
],
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index b459b2d..4f580e0 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -20,7 +20,7 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.launcher3">
- <uses-sdk android:targetSdkVersion="30" android:minSdkVersion="26"/>
+ <uses-sdk android:targetSdkVersion="33" android:minSdkVersion="26"/>
<!--
Manifest entries specific to Launcher3. This is merged with AndroidManifest-common.xml.
Refer comments around specific entries on how to extend individual components.
diff --git a/go/quickstep/res/values-pt-rPT/strings.xml b/go/quickstep/res/values-pt-rPT/strings.xml
index 7041f41..e64f520 100644
--- a/go/quickstep/res/values-pt-rPT/strings.xml
+++ b/go/quickstep/res/values-pt-rPT/strings.xml
@@ -10,9 +10,9 @@
<string name="dialog_settings" msgid="6564397136021186148">"DEFINIÇÕES"</string>
<string name="niu_actions_confirmation_title" msgid="3863451714863526143">"Traduza ou ouça o texto no ecrã"</string>
<string name="niu_actions_confirmation_text" msgid="2105271481950866089">"Informações como o texto no ecrã, endereços Web e capturas de ecrã podem ser partilhadas com a Google.\n\nPara alterar as informações que partilha, aceda a "<b>"Definições > Apps > App predefinidas > App de assistente digital"</b>"."</string>
- <string name="assistant_not_selected_title" msgid="5017072974603345228">"Escolha um assistente para utilizar esta funcionalidade"</string>
+ <string name="assistant_not_selected_title" msgid="5017072974603345228">"Escolha um assistente para usar esta funcionalidade"</string>
<string name="assistant_not_selected_text" msgid="3244613673884359276">"Para ouvir ou traduzir o texto no ecrã, escolha uma app de assistente digital nas Definições"</string>
- <string name="assistant_not_supported_title" msgid="1675788067597484142">"Mude de assistente para utilizar esta funcionalidade"</string>
+ <string name="assistant_not_supported_title" msgid="1675788067597484142">"Mude de assistente para usar esta funcionalidade"</string>
<string name="assistant_not_supported_text" msgid="1708031078549268884">"Para ouvir ou traduzir o texto no ecrã, mude de app de assistente digital nas Definições"</string>
<string name="tooltip_listen" msgid="7634466447860989102">"Toque aqui para ouvir o texto neste ecrã"</string>
<string name="tooltip_translate" msgid="4184845868901542567">"Toque aqui para traduzir o texto neste ecrã"</string>
diff --git a/go/src/com/android/launcher3/util/AbsGridOccupancy.java b/go/src/com/android/launcher3/util/AbsGridOccupancy.java
new file mode 100644
index 0000000..4a46bd1
--- /dev/null
+++ b/go/src/com/android/launcher3/util/AbsGridOccupancy.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 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.util;
+
+/**
+ * Defines method to find the next vacant cell on a grid.
+ * This uses the default top-down, left-right approach and can be over-written through
+ * code swaps in different launchers.
+ */
+public abstract class AbsGridOccupancy {
+
+ /**
+ * Find the first vacant cell, if there is one.
+ *
+ * @param vacantOut Holds the x and y coordinate of the vacant cell
+ * @param spanX Horizontal cell span.
+ * @param spanY Vertical cell span.
+ *
+ * @return true if a vacant cell was found
+ */
+ protected boolean findVacantCell(int[] vacantOut, boolean[][] cells, int countX, int countY,
+ int spanX, int spanY) {
+ for (int y = 0; (y + spanY) <= countY; y++) {
+ for (int x = 0; (x + spanX) <= countX; x++) {
+ boolean available = !cells[x][y];
+ out:
+ for (int i = x; i < x + spanX; i++) {
+ for (int j = y; j < y + spanY; j++) {
+ available = available && !cells[i][j];
+ if (!available) break out;
+ }
+ }
+ if (available) {
+ vacantOut[0] = x;
+ vacantOut[1] = y;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index cf854ed..10eedc8 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -76,6 +76,9 @@
// Represents the apps list sorted alphabetically inside the all-apps view.
message AllAppsContainer {
+ oneof ParentContainer {
+ TaskBarContainer taskbar_container = 1;
+ }
}
message WidgetsContainer {
@@ -83,6 +86,9 @@
// Represents the predicted apps row(top row) in the all-apps view.
message PredictionContainer {
+ oneof ParentContainer {
+ TaskBarContainer taskbar_container = 1;
+ }
}
// Represents the apps container within search results.
diff --git a/quickstep/AndroidManifest-launcher.xml b/quickstep/AndroidManifest-launcher.xml
index 53910e3..a24a588 100644
--- a/quickstep/AndroidManifest-launcher.xml
+++ b/quickstep/AndroidManifest-launcher.xml
@@ -20,7 +20,7 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.launcher3">
- <uses-sdk android:targetSdkVersion="29" android:minSdkVersion="25"/>
+ <uses-sdk android:targetSdkVersion="33" android:minSdkVersion="26"/>
<!--
Manifest entries specific to Launcher3. This is merged with AndroidManifest-common.xml.
Refer comments around specific entries on how to extend individual components.
diff --git a/quickstep/res/layout/taskbar_all_apps.xml b/quickstep/res/layout/taskbar_all_apps.xml
index d402469..34d4b23 100644
--- a/quickstep/res/layout/taskbar_all_apps.xml
+++ b/quickstep/res/layout/taskbar_all_apps.xml
@@ -34,6 +34,10 @@
android:visibility="gone" />
<include
+ layout="@layout/search_results_rv_layout"
+ android:visibility="gone" />
+
+ <include
layout="@layout/all_apps_rv_layout"
android:visibility="gone" />
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 2b71768..3f08cf3 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -26,7 +26,7 @@
<dimen name="task_menu_corner_radius">22dp</dimen>
<dimen name="task_menu_item_corner_radius">4dp</dimen>
<dimen name="task_menu_spacing">2dp</dimen>
- <dimen name="task_menu_width_grid">234dp</dimen>
+ <dimen name="task_menu_width_grid">216dp</dimen>
<dimen name="task_menu_horizontal_padding">8dp</dimen>
<dimen name="overview_proactive_row_height">48dp</dimen>
<dimen name="overview_proactive_row_bottom_margin">16dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 0e391ce..0f3474e 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -42,7 +42,6 @@
import static com.android.launcher3.config.FeatureFlags.ENABLE_SCRIM_FOR_APP_LAUNCH;
import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION;
import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
-import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS;
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
import static com.android.launcher3.testing.TestProtocol.BAD_STATE;
@@ -105,7 +104,6 @@
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.DynamicResource;
-import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.util.ObjectWrapper;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.Themes;
@@ -195,9 +193,7 @@
private static final int WIDGET_CROSSFADE_DURATION_MILLIS = 125;
protected final BaseQuickstepLauncher mLauncher;
-
private final DragLayer mDragLayer;
- private final AlphaProperty mDragLayerAlpha;
final Handler mHandler;
@@ -241,11 +237,9 @@
public QuickstepTransitionManager(Context context) {
mLauncher = Launcher.cast(Launcher.getLauncher(context));
mDragLayer = mLauncher.getDragLayer();
- mDragLayerAlpha = mDragLayer.getAlphaProperty(ALPHA_INDEX_TRANSITIONS);
mHandler = new Handler(Looper.getMainLooper());
mDeviceProfile = mLauncher.getDeviceProfile();
- mBackAnimationController = new LauncherBackAnimationController(
- mDeviceProfile, mLauncher, this);
+ mBackAnimationController = new LauncherBackAnimationController(mLauncher, this);
Resources res = mLauncher.getResources();
mContentScale = res.getFloat(R.dimen.content_scale);
@@ -526,7 +520,7 @@
endListener = composeViewContentAnimator(launcherAnimator, alphas, scales);
} else {
List<View> viewsToAnimate = new ArrayList<>();
- Workspace workspace = mLauncher.getWorkspace();
+ Workspace<?> workspace = mLauncher.getWorkspace();
workspace.forEachVisiblePage(
view -> viewsToAnimate.add(((CellLayout) view).getShortcutsAndWidgets()));
@@ -1162,7 +1156,7 @@
new LauncherAnimationRunner(mHandler, mWallpaperOpenTransitionRunner,
false /* startAtFrontOfQueue */), mLauncher.getIApplicationThread());
mLauncherOpenTransition.addHomeOpenCheck(mLauncher.getComponentName());
- SystemUiProxy.INSTANCE.getNoCreate().registerRemoteTransition(mLauncherOpenTransition);
+ SystemUiProxy.INSTANCE.get(mLauncher).registerRemoteTransition(mLauncherOpenTransition);
}
if (mBackAnimationController != null) {
mBackAnimationController.registerBackCallbacks(mHandler);
@@ -1173,7 +1167,7 @@
unregisterRemoteAnimations();
unregisterRemoteTransitions();
mStartingWindowListener.setTransitionManager(null);
- SystemUiProxy.INSTANCE.getNoCreate().setStartingWindowListener(null);
+ SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(null);
}
private void unregisterRemoteAnimations() {
@@ -1197,7 +1191,7 @@
}
if (hasControlRemoteAppTransitionPermission()) {
if (mLauncherOpenTransition == null) return;
- SystemUiProxy.INSTANCE.getNoCreate().unregisterRemoteTransition(
+ SystemUiProxy.INSTANCE.get(mLauncher).unregisterRemoteTransition(
mLauncherOpenTransition);
mLauncherOpenTransition = null;
mWallpaperOpenTransitionRunner = null;
@@ -1441,6 +1435,10 @@
}
};
anim.addOnUpdateListener(runner);
+ } else {
+ // If no floating icon or widget is present, animate the to the default window
+ // target rect.
+ anim.addOnUpdateListener(new SpringAnimRunner(targets, targetRect, windowTargetBounds));
}
// Use a fixed velocity to start the animation.
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
index 680012c..d63bc18 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
@@ -131,7 +131,7 @@
private int placeFoldersInWorkspace(ArrayDeque<FolderInfo> folders) {
if (folders.isEmpty()) return 0;
- Workspace workspace = mLauncher.getWorkspace();
+ Workspace<?> workspace = mLauncher.getWorkspace();
InvariantDeviceProfile idp = mLauncher.getDeviceProfile().inv;
GridOccupancy[] occupancyList = new GridOccupancy[workspace.getChildCount()];
@@ -176,7 +176,7 @@
* @return pageId where items are migrated
*/
private int migrateHotseatWhole() {
- Workspace workspace = mLauncher.getWorkspace();
+ Workspace<?> workspace = mLauncher.getWorkspace();
int pageId = -1;
int toRow = 0;
diff --git a/quickstep/src/com/android/launcher3/proxy/StartActivityParams.java b/quickstep/src/com/android/launcher3/proxy/StartActivityParams.java
index bee8bb8..b47ef47 100644
--- a/quickstep/src/com/android/launcher3/proxy/StartActivityParams.java
+++ b/quickstep/src/com/android/launcher3/proxy/StartActivityParams.java
@@ -16,6 +16,10 @@
package com.android.launcher3.proxy;
+import static android.app.PendingIntent.FLAG_MUTABLE;
+import static android.app.PendingIntent.FLAG_ONE_SHOT;
+import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
+
import android.app.Activity;
import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
@@ -45,7 +49,7 @@
public StartActivityParams(Activity activity, int requestCode) {
this(activity.createPendingResult(requestCode, new Intent(),
- PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT), requestCode);
+ FLAG_ONE_SHOT | FLAG_UPDATE_CURRENT | FLAG_MUTABLE), requestCode);
}
public StartActivityParams(PendingIntent pendingIntent, int requestCode) {
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index 3b02599..eda0823 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -53,6 +53,7 @@
public class DepthController implements StateHandler<LauncherState>,
BaseActivity.MultiWindowModeChangedListener {
+ private static final boolean OVERLAY_SCROLL_ENABLED = false;
public static final FloatProperty<DepthController> DEPTH =
new FloatProperty<DepthController>("depth") {
@Override
@@ -294,6 +295,9 @@
}
public void onOverlayScrollChanged(float progress) {
+ if (!OVERLAY_SCROLL_ENABLED) {
+ return;
+ }
// Add some padding to the progress, such we don't change the depth on the last frames of
// the animation. It's possible that a user flinging the feed quickly would scroll
// horizontally by accident, causing the device to enter client composition unnecessarily.
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 175a1d9..f65b907 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -210,7 +210,7 @@
0, 1));
// Center nav buttons in new height for IME.
float transForIme = (mContext.getDeviceProfile().taskbarSize
- - mContext.getTaskbarHeightForIme()) / 2f;
+ - mControllers.taskbarInsetsController.getTaskbarHeightForIme()) / 2f;
// For gesture nav, nav buttons only show for IME anyway so keep them translated down.
float defaultButtonTransY = alwaysShowButtons ? 0 : transForIme;
mPropertyHolders.add(new StatePropertyHolder(mTaskbarNavButtonTranslationYForIme,
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index a9ae7bd..b797807 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -176,7 +176,8 @@
return revealAnim;
}
- public void onIsStashed(boolean isStashed) {
+ /** Called when taskbar is stashed or unstashed. */
+ public void onIsStashedChanged(boolean isStashed) {
mRegionSamplingHelper.setWindowVisible(isStashed);
if (isStashed) {
mStashedHandleView.updateSampledRegion(mStashedHandleBounds);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 296000b..b349637 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -27,8 +27,6 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
-import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
-import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR;
import android.animation.AnimatorSet;
import android.app.ActivityOptions;
@@ -38,7 +36,6 @@
import android.content.pm.ActivityInfo.Config;
import android.content.pm.LauncherApps;
import android.content.res.Resources;
-import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Process;
@@ -87,7 +84,6 @@
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.rotation.RotationButtonController;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
import java.io.PrintWriter;
@@ -112,7 +108,6 @@
private final WindowManager mWindowManager;
private final @Nullable RoundedCorner mLeftCorner, mRightCorner;
- private final int mTaskbarHeightForIme;
private WindowManager.LayoutParams mWindowLayoutParams;
private boolean mIsFullscreen;
// The size we should return to when we call setTaskbarWindowFullscreen(false)
@@ -153,7 +148,15 @@
Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE), 0);
updateIconSize(resources);
- mTaskbarHeightForIme = resources.getDimensionPixelSize(R.dimen.taskbar_ime_size);
+
+ // Get display and corners first, as views might use them in constructor.
+ Display display = windowContext.getDisplay();
+ Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY
+ ? windowContext.getApplicationContext()
+ : windowContext.getApplicationContext().createDisplayContext(display);
+ mWindowManager = c.getSystemService(WindowManager.class);
+ mLeftCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT);
+ mRightCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT);
// Inflate views.
mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate(
@@ -163,14 +166,6 @@
FrameLayout navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view);
StashedHandleView stashedHandleView = mDragLayer.findViewById(R.id.stashed_handle);
- Display display = windowContext.getDisplay();
- Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY
- ? windowContext.getApplicationContext()
- : windowContext.getApplicationContext().createDisplayContext(display);
- mWindowManager = c.getSystemService(WindowManager.class);
- mLeftCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT);
- mRightCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT);
-
mAccessibilityDelegate = new TaskbarShortcutMenuAccessibilityDelegate(this);
// Construct controllers.
@@ -200,25 +195,14 @@
new TaskbarAutohideSuspendController(this),
new TaskbarPopupController(this),
new TaskbarForceVisibleImmersiveController(this),
- new TaskbarAllAppsController(this));
+ new TaskbarAllAppsController(this),
+ new TaskbarInsetsController(this));
}
public void init(TaskbarSharedState sharedState) {
mLastRequestedNonFullscreenHeight = getDefaultTaskbarWindowHeight();
mWindowLayoutParams = createDefaultWindowLayoutParams();
- WindowManagerWrapper wmWrapper = WindowManagerWrapper.getInstance();
- wmWrapper.setProvidesInsetsTypes(
- mWindowLayoutParams,
- new int[] { ITYPE_EXTRA_NAVIGATION_BAR, ITYPE_BOTTOM_TAPPABLE_ELEMENT }
- );
- // Adjust the frame by the rounded corners (ie. leaving just the bar as the inset) when
- // the IME is showing
- mWindowLayoutParams.providedInternalImeInsets = Insets.of(0,
- getDefaultTaskbarWindowHeight() - mTaskbarHeightForIme, 0, 0);
-
- mWindowLayoutParams.insetsRoundedCornerFrame = true;
-
// Initialize controllers after all are constructed.
mControllers.init(sharedState);
updateSysuiStateFlags(sharedState.sysuiStateFlags, true /* fromInit */);
@@ -298,6 +282,10 @@
return mRightCorner == null ? 0 : mRightCorner.getRadius();
}
+ public WindowManager.LayoutParams getWindowLayoutParams() {
+ return mWindowLayoutParams;
+ }
+
@Override
public TaskbarDragLayer getDragLayer() {
return mDragLayer;
@@ -374,6 +362,14 @@
folderBuilder.clearHotseat();
itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
.setFolder(folderBuilder));
+ } else if (oldContainer.hasAllAppsContainer()) {
+ itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
+ .setAllAppsContainer(oldContainer.getAllAppsContainer().toBuilder()
+ .setTaskbarContainer(LauncherAtom.TaskBarContainer.newBuilder())));
+ } else if (oldContainer.hasPredictionContainer()) {
+ itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
+ .setPredictionContainer(oldContainer.getPredictionContainer().toBuilder()
+ .setTaskbarContainer(LauncherAtom.TaskBarContainer.newBuilder())));
}
}
@@ -563,8 +559,7 @@
}
}
mWindowLayoutParams.height = height;
- mWindowLayoutParams.providedInternalImeInsets =
- Insets.of(0, height - mTaskbarHeightForIme, 0, 0);
+ mControllers.taskbarInsetsController.onTaskbarWindowHeightOrInsetsChanged();
mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
}
@@ -576,13 +571,6 @@
}
/**
- * Returns the bottom insets taskbar provides to the IME when IME is visible.
- */
- public int getTaskbarHeightForIme() {
- return mTaskbarHeightForIme;
- }
-
- /**
* Either adds or removes {@link WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE} on the taskbar
* window.
*/
@@ -691,6 +679,7 @@
}
} else if (tag instanceof AppInfo) {
startItemInfoActivity((AppInfo) tag);
+ mControllers.uiController.onTaskbarIconLaunched((AppInfo) tag);
} else {
Log.e(TAG, "Unknown type clicked: " + tag);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
new file mode 100644
index 0000000..1177bdb
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 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.taskbar
+
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.Path
+import com.android.launcher3.R
+
+/**
+ * Helps draw the taskbar background, made up of a rectangle plus two inverted rounded corners.
+ */
+class TaskbarBackgroundRenderer(context: TaskbarActivityContext) {
+
+ val paint: Paint = Paint()
+ var backgroundHeight = context.deviceProfile.taskbarSize.toFloat()
+
+ private val leftCornerRadius = context.leftCornerRadius.toFloat()
+ private val rightCornerRadius = context.rightCornerRadius.toFloat()
+ private val invertedLeftCornerPath: Path = Path()
+ private val invertedRightCornerPath: Path = Path()
+
+ init {
+ paint.color = context.getColor(R.color.taskbar_background)
+ paint.flags = Paint.ANTI_ALIAS_FLAG
+ paint.style = Paint.Style.FILL
+
+ // Create the paths for the inverted rounded corners above the taskbar. Start with a filled
+ // square, and then subtract out a circle from the appropriate corner.
+ val square = Path()
+ square.addRect(0f, 0f, leftCornerRadius, leftCornerRadius, Path.Direction.CW)
+ val circle = Path()
+ circle.addCircle(leftCornerRadius, 0f, leftCornerRadius, Path.Direction.CW)
+ invertedLeftCornerPath.op(square, circle, Path.Op.DIFFERENCE)
+ square.reset()
+ square.addRect(0f, 0f, rightCornerRadius, rightCornerRadius, Path.Direction.CW)
+ circle.reset()
+ circle.addCircle(0f, 0f, rightCornerRadius, Path.Direction.CW)
+ invertedRightCornerPath.op(square, circle, Path.Op.DIFFERENCE)
+ }
+
+ /**
+ * Draws the background with the given paint and height, on the provided canvas.
+ */
+ fun draw(canvas: Canvas) {
+ canvas.save()
+ canvas.translate(0f, canvas.height - backgroundHeight)
+
+ // Draw the background behind taskbar content.
+ canvas.drawRect(0f, 0f, canvas.width.toFloat(), backgroundHeight, paint)
+
+ // Draw the inverted rounded corners above the taskbar.
+ canvas.translate(0f, -leftCornerRadius)
+ canvas.drawPath(invertedLeftCornerPath, paint)
+ canvas.translate(0f, leftCornerRadius)
+ canvas.translate(canvas.width - rightCornerRadius, -rightCornerRadius)
+ canvas.drawPath(invertedRightCornerPath, paint)
+
+ canvas.restore()
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index a3586396..ff08e3d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -51,6 +51,7 @@
public final TaskbarPopupController taskbarPopupController;
public final TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController;
public final TaskbarAllAppsController taskbarAllAppsController;
+ public final TaskbarInsetsController taskbarInsetsController;
@Nullable private LoggableTaskbarController[] mControllersToLog = null;
@@ -76,7 +77,8 @@
TaskbarAutohideSuspendController taskbarAutoHideSuspendController,
TaskbarPopupController taskbarPopupController,
TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController,
- TaskbarAllAppsController taskbarAllAppsController) {
+ TaskbarAllAppsController taskbarAllAppsController,
+ TaskbarInsetsController taskbarInsetsController) {
this.taskbarActivityContext = taskbarActivityContext;
this.taskbarDragController = taskbarDragController;
this.navButtonController = navButtonController;
@@ -94,6 +96,7 @@
this.taskbarPopupController = taskbarPopupController;
this.taskbarForceVisibleImmersiveController = taskbarForceVisibleImmersiveController;
this.taskbarAllAppsController = taskbarAllAppsController;
+ this.taskbarInsetsController = taskbarInsetsController;
}
/**
@@ -119,13 +122,14 @@
taskbarForceVisibleImmersiveController.init(this);
taskbarAllAppsController.init(this, sharedState);
navButtonController.init(this);
+ taskbarInsetsController.init(this);
mControllersToLog = new LoggableTaskbarController[] {
taskbarDragController, navButtonController, navbarButtonsViewController,
taskbarDragLayerController, taskbarScrimViewController, taskbarViewController,
taskbarUnfoldAnimationController, taskbarKeyguardController,
stashedHandleViewController, taskbarStashController, taskbarEduController,
- taskbarAutohideSuspendController, taskbarPopupController
+ taskbarAutohideSuspendController, taskbarPopupController, taskbarInsetsController
};
mAreAllControllersInitialized = true;
@@ -156,6 +160,7 @@
taskbarForceVisibleImmersiveController.onDestroy();
taskbarAllAppsController.onDestroy();
navButtonController.onDestroy();
+ taskbarInsetsController.onDestroy();
mControllersToLog = null;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 9ba4a65..5c10565 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -477,7 +477,6 @@
tx.setScale(dragSurface, scale, scale);
tx.setAlpha(dragSurface, alpha);
tx.apply();
- tx.close();
}
});
mReturnAnimator.addListener(new AnimatorListenerAdapter() {
@@ -498,6 +497,7 @@
}
private void cleanUpSurface() {
+ tx.close();
maybeOnDragEnd();
// Synchronize removing the drag surface with the next draw after calling
// maybeOnDragEnd()
@@ -508,7 +508,6 @@
syncer.addToSync(syncId, viewRoot.getView());
syncer.addTransactionToSync(syncId, transaction);
syncer.markSyncReady(syncId);
-
mReturnAnimator = null;
}
});
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index 4a80665..c1a6185 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -20,8 +20,6 @@
import android.content.Context;
import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -31,7 +29,6 @@
import androidx.annotation.Nullable;
import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.R;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.views.BaseDragLayer;
@@ -44,13 +41,11 @@
*/
public class TaskbarDragLayer extends BaseDragLayer<TaskbarActivityContext> {
- private final Paint mTaskbarBackgroundPaint;
- private final Path mInvertedLeftCornerPath, mInvertedRightCornerPath;
+ private final TaskbarBackgroundRenderer mBackgroundRenderer;
private final OnComputeInsetsListener mTaskbarInsetsComputer = this::onComputeTaskbarInsets;
// Initialized in init.
private TaskbarDragLayerController.TaskbarDragLayerCallbacks mControllerCallbacks;
- private float mLeftCornerRadius, mRightCornerRadius;
private float mTaskbarBackgroundOffset;
@@ -70,35 +65,13 @@
public TaskbarDragLayer(@NonNull Context context, @Nullable AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, 1 /* alphaChannelCount */);
- mTaskbarBackgroundPaint = new Paint();
- mTaskbarBackgroundPaint.setColor(getResources().getColor(R.color.taskbar_background));
- mTaskbarBackgroundPaint.setAlpha(0);
- mTaskbarBackgroundPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
- mTaskbarBackgroundPaint.setStyle(Paint.Style.FILL);
-
- // Will be set in init(), but this ensures they are always non-null.
- mInvertedLeftCornerPath = new Path();
- mInvertedRightCornerPath = new Path();
+ mBackgroundRenderer = new TaskbarBackgroundRenderer(mActivity);
+ mBackgroundRenderer.getPaint().setAlpha(0);
}
public void init(TaskbarDragLayerController.TaskbarDragLayerCallbacks callbacks) {
mControllerCallbacks = callbacks;
- // Create the paths for the inverted rounded corners above the taskbar. Start with a filled
- // square, and then subtracting out a circle from the appropriate corner.
- mLeftCornerRadius = mActivity.getLeftCornerRadius();
- mRightCornerRadius = mActivity.getRightCornerRadius();
- Path square = new Path();
- square.addRect(0, 0, mLeftCornerRadius, mLeftCornerRadius, Path.Direction.CW);
- Path circle = new Path();
- circle.addCircle(mLeftCornerRadius, 0, mLeftCornerRadius, Path.Direction.CW);
- mInvertedLeftCornerPath.op(square, circle, Path.Op.DIFFERENCE);
- square.reset();
- square.addRect(0, 0, mRightCornerRadius, mRightCornerRadius, Path.Direction.CW);
- circle.reset();
- circle.addCircle(0, 0, mRightCornerRadius, Path.Direction.CW);
- mInvertedRightCornerPath.op(square, circle, Path.Op.DIFFERENCE);
-
recreateControllers();
}
@@ -110,7 +83,6 @@
private void onComputeTaskbarInsets(InsetsInfo insetsInfo) {
if (mControllerCallbacks != null) {
mControllerCallbacks.updateInsetsTouchability(insetsInfo);
- mControllerCallbacks.updateContentInsets(insetsInfo.contentInsets);
}
}
@@ -151,20 +123,8 @@
protected void dispatchDraw(Canvas canvas) {
float backgroundHeight = mControllerCallbacks.getTaskbarBackgroundHeight()
* (1f - mTaskbarBackgroundOffset);
- canvas.save();
- canvas.translate(0, canvas.getHeight() - backgroundHeight);
-
- // Draw the background behind taskbar content.
- canvas.drawRect(0, 0, canvas.getWidth(), backgroundHeight, mTaskbarBackgroundPaint);
-
- // Draw the inverted rounded corners above the taskbar.
- canvas.translate(0, -mLeftCornerRadius);
- canvas.drawPath(mInvertedLeftCornerPath, mTaskbarBackgroundPaint);
- canvas.translate(0, mLeftCornerRadius);
- canvas.translate(canvas.getWidth() - mRightCornerRadius, -mRightCornerRadius);
- canvas.drawPath(mInvertedRightCornerPath, mTaskbarBackgroundPaint);
-
- canvas.restore();
+ mBackgroundRenderer.setBackgroundHeight(backgroundHeight);
+ mBackgroundRenderer.draw(canvas);
super.dispatchDraw(canvas);
}
@@ -173,7 +133,7 @@
* @param alpha 0 is fully transparent, 1 is fully opaque.
*/
protected void setTaskbarBackgroundAlpha(float alpha) {
- mTaskbarBackgroundPaint.setAlpha((int) (alpha * 255));
+ mBackgroundRenderer.getPaint().setAlpha((int) (alpha * 255));
invalidate();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index c7330d3..3e2695c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -15,18 +15,10 @@
*/
package com.android.launcher3.taskbar;
-import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
-import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS;
-import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_CONTENT;
-import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_FRAME;
-import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_REGION;
-
import android.content.res.Resources;
import android.graphics.Rect;
-import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.R;
-import com.android.launcher3.anim.AlphaUpdateListener;
import com.android.launcher3.util.TouchController;
import com.android.quickstep.AnimatedFloat;
import com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo;
@@ -168,47 +160,7 @@
* @see InsetsInfo#setTouchableInsets(int)
*/
public void updateInsetsTouchability(InsetsInfo insetsInfo) {
- insetsInfo.touchableRegion.setEmpty();
- // Always have nav buttons be touchable
- mControllers.navbarButtonsViewController.addVisibleButtonsRegion(
- mTaskbarDragLayer, insetsInfo.touchableRegion);
- boolean insetsIsTouchableRegion = true;
-
- if (mTaskbarDragLayer.getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
- // Let touches pass through us.
- insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
- } else if (mControllers.navbarButtonsViewController.isImeVisible()) {
- insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
- } else if (!mControllers.uiController.isTaskbarTouchable()) {
- // Let touches pass through us.
- insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
- } else if (mControllers.taskbarDragController.isSystemDragInProgress()) {
- // Let touches pass through us.
- insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
- } else if (AbstractFloatingView.getOpenView(mActivity, TYPE_TASKBAR_ALL_APPS) != null) {
- // Let touches pass through us.
- insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
- } else if (mControllers.taskbarViewController.areIconsVisible()
- || AbstractFloatingView.getOpenView(mActivity, TYPE_ALL) != null
- || mActivity.isNavBarKidsModeActive()) {
- // Taskbar has some touchable elements, take over the full taskbar area
- insetsInfo.setTouchableInsets(mActivity.isTaskbarWindowFullscreen()
- ? TOUCHABLE_INSETS_FRAME : TOUCHABLE_INSETS_CONTENT);
- insetsIsTouchableRegion = false;
- } else {
- insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
- }
- mActivity.excludeFromMagnificationRegion(insetsIsTouchableRegion);
- }
-
- /**
- * Called to update the {@link InsetsInfo#contentInsets}. This is reported to apps but our
- * internal launcher will ignore these insets.
- */
- public void updateContentInsets(Rect outContentInsets) {
- int contentHeight = mControllers.taskbarStashController
- .getContentHeightToReportToApps();
- outContentInsets.top = mTaskbarDragLayer.getHeight() - contentHeight;
+ mControllers.taskbarInsetsController.updateInsetsTouchability(insetsInfo);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
new file mode 100644
index 0000000..9870a2e
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2022 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.taskbar
+
+import android.graphics.Insets
+import android.view.WindowManager
+import com.android.launcher3.AbstractFloatingView
+import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS
+import com.android.launcher3.R
+import com.android.launcher3.anim.AlphaUpdateListener
+import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
+import com.android.quickstep.KtR
+import com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo
+import com.android.systemui.shared.system.WindowManagerWrapper
+import com.android.systemui.shared.system.WindowManagerWrapper.*
+import java.io.PrintWriter
+
+/**
+ * Handles the insets that Taskbar provides to underlying apps and the IME.
+ */
+class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTaskbarController {
+
+ /** The bottom insets taskbar provides to the IME when IME is visible. */
+ val taskbarHeightForIme: Int = context.resources.getDimensionPixelSize(
+ KtR.dimen.taskbar_ime_size)
+
+ // Initialized in init.
+ private lateinit var controllers: TaskbarControllers
+ private lateinit var windowLayoutParams: WindowManager.LayoutParams
+
+ fun init(controllers: TaskbarControllers) {
+ this.controllers = controllers
+ windowLayoutParams = context.windowLayoutParams
+
+ val wmWrapper: WindowManagerWrapper = getInstance()
+ wmWrapper.setProvidesInsetsTypes(
+ windowLayoutParams,
+ intArrayOf(
+ ITYPE_EXTRA_NAVIGATION_BAR,
+ ITYPE_BOTTOM_TAPPABLE_ELEMENT
+ )
+ )
+
+ windowLayoutParams.providedInternalInsets = arrayOfNulls<Insets>(ITYPE_SIZE)
+ windowLayoutParams.providedInternalImeInsets = arrayOfNulls<Insets>(ITYPE_SIZE)
+
+ onTaskbarWindowHeightOrInsetsChanged()
+
+ windowLayoutParams.insetsRoundedCornerFrame = true
+ }
+
+ fun onDestroy() {}
+
+ fun onTaskbarWindowHeightOrInsetsChanged() {
+ var reducingSize = getReducingInsetsForTaskbarInsetsHeight(
+ controllers.taskbarStashController.contentHeightToReportToApps)
+ windowLayoutParams.providedInternalInsets[ITYPE_EXTRA_NAVIGATION_BAR] = reducingSize
+ reducingSize = getReducingInsetsForTaskbarInsetsHeight(
+ controllers.taskbarStashController.tappableHeightToReportToApps)
+ windowLayoutParams.providedInternalInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT] = reducingSize
+
+ reducingSize = getReducingInsetsForTaskbarInsetsHeight(taskbarHeightForIme)
+ windowLayoutParams.providedInternalImeInsets[ITYPE_EXTRA_NAVIGATION_BAR] = reducingSize
+ windowLayoutParams.providedInternalImeInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT] = reducingSize
+ }
+
+ /**
+ * WindowLayoutParams.providedInternal*Insets expects Insets that subtract from the window frame
+ * height (i.e. WindowLayoutParams#height). So for Taskbar to report bottom insets to apps, it
+ * actually provides insets from the top of its window frame.
+ * @param height The number of pixels from the bottom of the screen that Taskbar insets.
+ */
+ private fun getReducingInsetsForTaskbarInsetsHeight(height: Int): Insets {
+ return Insets.of(0, windowLayoutParams.height - height, 0, 0)
+ }
+
+ /**
+ * Called to update the touchable insets.
+ * @see InsetsInfo.setTouchableInsets
+ */
+ fun updateInsetsTouchability(insetsInfo: InsetsInfo) {
+ insetsInfo.touchableRegion.setEmpty()
+ // Always have nav buttons be touchable
+ controllers.navbarButtonsViewController.addVisibleButtonsRegion(
+ context.dragLayer, insetsInfo.touchableRegion
+ )
+ var insetsIsTouchableRegion = true
+ if (context.dragLayer.alpha < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
+ // Let touches pass through us.
+ insetsInfo.setTouchableInsets(InsetsInfo.TOUCHABLE_INSETS_REGION)
+ } else if (controllers.navbarButtonsViewController.isImeVisible) {
+ insetsInfo.setTouchableInsets(InsetsInfo.TOUCHABLE_INSETS_REGION)
+ } else if (!controllers.uiController.isTaskbarTouchable) {
+ // Let touches pass through us.
+ insetsInfo.setTouchableInsets(InsetsInfo.TOUCHABLE_INSETS_REGION)
+ } else if (controllers.taskbarDragController.isSystemDragInProgress) {
+ // Let touches pass through us.
+ insetsInfo.setTouchableInsets(InsetsInfo.TOUCHABLE_INSETS_REGION)
+ } else if (AbstractFloatingView.hasOpenView(context, TYPE_TASKBAR_ALL_APPS)) {
+ // Let touches pass through us.
+ insetsInfo.setTouchableInsets(InsetsInfo.TOUCHABLE_INSETS_REGION)
+ } else if (controllers.taskbarViewController.areIconsVisible()
+ || AbstractFloatingView.hasOpenView(context, AbstractFloatingView.TYPE_ALL)
+ || context.isNavBarKidsModeActive
+ ) {
+ // Taskbar has some touchable elements, take over the full taskbar area
+ insetsInfo.setTouchableInsets(
+ if (context.isTaskbarWindowFullscreen) {
+ InsetsInfo.TOUCHABLE_INSETS_FRAME
+ } else {
+ InsetsInfo.TOUCHABLE_INSETS_CONTENT
+ }
+ )
+ insetsIsTouchableRegion = false
+ } else {
+ insetsInfo.setTouchableInsets(InsetsInfo.TOUCHABLE_INSETS_REGION)
+ }
+ context.excludeFromMagnificationRegion(insetsIsTouchableRegion)
+ }
+
+ override fun dumpLogs(prefix: String, pw: PrintWriter) {
+ pw.println(prefix + "TaskbarInsetsController:")
+ pw.println("$prefix\twindowHeight=${windowLayoutParams.height}")
+ pw.println("$prefix\tprovidedInternalInsets[ITYPE_EXTRA_NAVIGATION_BAR]=" +
+ "${windowLayoutParams.providedInternalInsets[ITYPE_EXTRA_NAVIGATION_BAR]}")
+ pw.println("$prefix\tprovidedInternalInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT]=" +
+ "${windowLayoutParams.providedInternalInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT]}")
+ pw.println("$prefix\tprovidedInternalImeInsets[ITYPE_EXTRA_NAVIGATION_BAR]=" +
+ "${windowLayoutParams.providedInternalImeInsets[ITYPE_EXTRA_NAVIGATION_BAR]}")
+ pw.println("$prefix\tprovidedInternalImeInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT]=" +
+ "${windowLayoutParams.providedInternalImeInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT]}")
+ }
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 8e31a74..e02a9d7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -19,6 +19,7 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
import android.content.ComponentCallbacks;
@@ -41,7 +42,6 @@
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider;
import com.android.launcher3.util.DisplayController;
-import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.SimpleBroadcastReceiver;
import com.android.quickstep.RecentsActivity;
@@ -55,7 +55,7 @@
/**
* Class to manage taskbar lifecycle
*/
-public class TaskbarManager implements DisplayController.DisplayInfoChangeListener {
+public class TaskbarManager {
private static final Uri USER_SETUP_COMPLETE_URI = Settings.Secure.getUriFor(
Settings.Secure.USER_SETUP_COMPLETE);
@@ -91,8 +91,15 @@
* navigation mode, that callback gets called too soon, before it's internal navigation mode
* reflects the current one.
* DisplayController's callback is delayed enough to get the correct nav mode value
+ *
+ * We also use density change here because DeviceProfile has had a chance to update it's state
+ * whereas density for component callbacks registered in this class don't update DeviceProfile.
+ * Confused? Me too. Make it less confusing (TODO: b/227669780)
+ *
+ * Flags used with {@link #mDispInfoChangeListener}
*/
- private static final int CHANGE_FLAGS = CHANGE_NAVIGATION_MODE;
+ private static final int CHANGE_FLAGS = CHANGE_NAVIGATION_MODE | CHANGE_DENSITY;
+ private final DisplayController.DisplayInfoChangeListener mDispInfoChangeListener;
private boolean mUserUnlocked = false;
@@ -105,6 +112,7 @@
SystemUiProxy.INSTANCE.get(mContext), new Handler());
mUserSetupCompleteListener = isUserSetupComplete -> recreateTaskbar();
mNavBarKidsModeListener = isNavBarKidsMode -> recreateTaskbar();
+ // TODO(b/227669780): Consolidate this w/ DisplayController callbacks
mComponentCallbacks = new ComponentCallbacks() {
private Configuration mOldConfig = mContext.getResources().getConfiguration();
@@ -116,7 +124,7 @@
int configDiff = mOldConfig.diff(newConfig);
int configsRequiringRecreate = ActivityInfo.CONFIG_ASSETS_PATHS
| ActivityInfo.CONFIG_LAYOUT_DIRECTION | ActivityInfo.CONFIG_UI_MODE
- | ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_SCREEN_SIZE;
+ | ActivityInfo.CONFIG_SCREEN_SIZE;
boolean requiresRecreate = (configDiff & configsRequiringRecreate) != 0;
if ((configDiff & ActivityInfo.CONFIG_SCREEN_SIZE) != 0
&& mTaskbarActivityContext != null && dp != null) {
@@ -151,8 +159,12 @@
public void onLowMemory() { }
};
mShutdownReceiver = new SimpleBroadcastReceiver(i -> destroyExistingTaskbar());
-
- mDisplayController.addChangeListener(this);
+ mDispInfoChangeListener = (context, info, flags) -> {
+ if ((flags & CHANGE_FLAGS) != 0) {
+ recreateTaskbar();
+ }
+ };
+ mDisplayController.addChangeListener(mDispInfoChangeListener);
SettingsCache.INSTANCE.get(mContext).register(USER_SETUP_COMPLETE_URI,
mUserSetupCompleteListener);
SettingsCache.INSTANCE.get(mContext).register(NAV_BAR_KIDS_MODE,
@@ -163,13 +175,6 @@
recreateTaskbar();
}
- @Override
- public void onDisplayInfoChanged(Context context, Info info, int flags) {
- if ((flags & CHANGE_FLAGS) != 0) {
- recreateTaskbar();
- }
- }
-
private void destroyExistingTaskbar() {
if (mTaskbarActivityContext != null) {
mTaskbarActivityContext.onDestroy();
@@ -310,7 +315,7 @@
*/
public void destroy() {
destroyExistingTaskbar();
- mDisplayController.removeChangeListener(this);
+ mDisplayController.removeChangeListener(mDispInfoChangeListener);
SettingsCache.INSTANCE.get(mContext).unregister(USER_SETUP_COMPLETE_URI,
mUserSetupCompleteListener);
SettingsCache.INSTANCE.get(mContext).unregister(NAV_BAR_KIDS_MODE,
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimView.java
index 94a3307..1d3757f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimView.java
@@ -17,22 +17,19 @@
import android.content.Context;
import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;
+import com.android.launcher3.views.ActivityContext;
+
/**
* View that handles scrimming the taskbar and the inverted corners it draws. The scrim is used
* when bubbles is expanded.
*/
public class TaskbarScrimView extends View {
- private final Paint mTaskbarScrimPaint;
- private final Path mInvertedLeftCornerPath, mInvertedRightCornerPath;
+ private final TaskbarBackgroundRenderer mRenderer;
private boolean mShowScrim;
- private float mLeftCornerRadius, mRightCornerRadius;
- private float mBackgroundHeight;
public TaskbarScrimView(Context context) {
this(context, null);
@@ -49,14 +46,9 @@
public TaskbarScrimView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
-
- mTaskbarScrimPaint = new Paint();
- mTaskbarScrimPaint.setColor(getResources().getColor(android.R.color.system_neutral1_1000));
- mTaskbarScrimPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
- mTaskbarScrimPaint.setStyle(Paint.Style.FILL);
-
- mInvertedLeftCornerPath = new Path();
- mInvertedRightCornerPath = new Path();
+ mRenderer = new TaskbarBackgroundRenderer(ActivityContext.lookupContext(context));
+ mRenderer.getPaint().setColor(getResources().getColor(
+ android.R.color.system_neutral1_1000));
}
@Override
@@ -64,31 +56,7 @@
super.onDraw(canvas);
if (mShowScrim) {
- canvas.save();
- canvas.translate(0, canvas.getHeight() - mBackgroundHeight);
-
- // Scrim the taskbar itself.
- canvas.drawRect(0, 0, canvas.getWidth(), mBackgroundHeight, mTaskbarScrimPaint);
-
- // Scrim the inverted rounded corners above the taskbar.
- canvas.translate(0, -mLeftCornerRadius);
- canvas.drawPath(mInvertedLeftCornerPath, mTaskbarScrimPaint);
- canvas.translate(0, mLeftCornerRadius);
- canvas.translate(canvas.getWidth() - mRightCornerRadius, -mRightCornerRadius);
- canvas.drawPath(mInvertedRightCornerPath, mTaskbarScrimPaint);
-
- canvas.restore();
- }
- }
-
- /**
- * Sets the height of the taskbar background.
- * @param height the height of the background.
- */
- protected void setBackgroundHeight(float height) {
- mBackgroundHeight = height;
- if (mShowScrim) {
- invalidate();
+ mRenderer.draw(canvas);
}
}
@@ -98,32 +66,7 @@
*/
protected void setScrimAlpha(float alpha) {
mShowScrim = alpha > 0f;
- mTaskbarScrimPaint.setAlpha((int) (alpha * 255));
+ mRenderer.getPaint().setAlpha((int) (alpha * 255));
invalidate();
}
-
- /**
- * Sets the radius of the left and right corners above the taskbar.
- * @param leftCornerRadius the radius of the left corner.
- * @param rightCornerRadius the radius of the right corner.
- */
- protected void setCornerSizes(float leftCornerRadius, float rightCornerRadius) {
- mLeftCornerRadius = leftCornerRadius;
- mRightCornerRadius = rightCornerRadius;
-
- Path square = new Path();
- square.addRect(0, 0, mLeftCornerRadius, mLeftCornerRadius, Path.Direction.CW);
- Path circle = new Path();
- circle.addCircle(mLeftCornerRadius, 0, mLeftCornerRadius, Path.Direction.CW);
- mInvertedLeftCornerPath.op(square, circle, Path.Op.DIFFERENCE);
- square.reset();
- square.addRect(0, 0, mRightCornerRadius, mRightCornerRadius, Path.Direction.CW);
- circle.reset();
- circle.addCircle(0, 0, mRightCornerRadius, Path.Direction.CW);
- mInvertedRightCornerPath.op(square, circle, Path.Op.DIFFERENCE);
-
- if (mShowScrim) {
- invalidate();
- }
- }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
index 02bbae4..58ace17 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
@@ -49,9 +49,6 @@
public TaskbarScrimViewController(TaskbarActivityContext activity, TaskbarScrimView scrimView) {
mActivity = activity;
mScrimView = scrimView;
- mScrimView.setCornerSizes(mActivity.getLeftCornerRadius(),
- mActivity.getRightCornerRadius());
- mScrimView.setBackgroundHeight(mActivity.getDeviceProfile().taskbarSize);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 3521ee3..f34759d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -30,9 +30,11 @@
import android.content.SharedPreferences;
import android.util.Log;
import android.view.ViewConfiguration;
+import android.view.WindowInsets;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
+import com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.quickstep.AnimatedFloat;
@@ -279,6 +281,8 @@
/**
* Returns the height that taskbar will inset when inside apps.
+ * @see WindowInsets.Type#navigationBars()
+ * @see WindowInsets.Type#systemBars()
*/
public int getContentHeightToReportToApps() {
if (supportsVisualStashing() && hasAnyFlag(FLAGS_REPORT_STASHED_INSETS_TO_APP)) {
@@ -303,6 +307,15 @@
return mUnstashedHeight;
}
+ /**
+ * Returns the height that taskbar will inset when inside apps.
+ * @see WindowInsets.Type#tappableElement()
+ */
+ public int getTappableHeightToReportToApps() {
+ int contentHeight = getContentHeightToReportToApps();
+ return contentHeight <= mStashedHeight ? 0 : contentHeight;
+ }
+
public int getStashedHeight() {
return mStashedHeight;
}
@@ -441,7 +454,7 @@
@Override
public void onAnimationStart(Animator animation) {
mIsStashed = isStashed;
- onIsStashed(mIsStashed);
+ onIsStashedChanged(mIsStashed);
}
@Override
@@ -488,8 +501,11 @@
.setDuration(TASKBAR_HINT_STASH_DURATION).start();
}
- private void onIsStashed(boolean isStashed) {
- mControllers.stashedHandleViewController.onIsStashed(isStashed);
+ private void onIsStashedChanged(boolean isStashed) {
+ mControllers.runAfterInit(() -> {
+ mControllers.stashedHandleViewController.onIsStashedChanged(isStashed);
+ mControllers.taskbarInsetsController.onTaskbarWindowHeightOrInsetsChanged();
+ });
}
public void applyState() {
@@ -518,14 +534,41 @@
*/
public void setSystemGestureInProgress(boolean inProgress) {
mIsSystemGestureInProgress = inProgress;
- // Only update FLAG_STASHED_IN_APP_IME when system gesture is not in progress.
- if (!mIsSystemGestureInProgress) {
+ if (mIsSystemGestureInProgress) {
+ return;
+ }
+
+ // Only update the following flags when system gesture is not in progress.
+ maybeResetStashedInAppAllApps(hasAnyFlag(FLAG_STASHED_IN_APP_IME) == mIsImeShowing);
+ if (hasAnyFlag(FLAG_STASHED_IN_APP_IME) != mIsImeShowing) {
updateStateForFlag(FLAG_STASHED_IN_APP_IME, mIsImeShowing);
applyState(TASKBAR_STASH_DURATION_FOR_IME, getTaskbarStashStartDelayForIme());
}
}
/**
+ * Reset stashed in all apps only if no system gesture is in progress.
+ * <p>
+ * Otherwise, the reset should be deferred until after the gesture is finished.
+ *
+ * @see #setSystemGestureInProgress
+ */
+ public void maybeResetStashedInAppAllApps() {
+ maybeResetStashedInAppAllApps(true);
+ }
+
+ private void maybeResetStashedInAppAllApps(boolean applyState) {
+ if (mIsSystemGestureInProgress) {
+ return;
+ }
+
+ updateStateForFlag(FLAG_STASHED_IN_APP_ALL_APPS, false);
+ if (applyState) {
+ applyState(TaskbarAllAppsSlideInView.DEFAULT_CLOSE_DURATION);
+ }
+ }
+
+ /**
* When hiding the IME, delay the unstash animation to align with the end of the transition.
*/
private long getTaskbarStashStartDelayForIme() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 8291475..7548398 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -312,8 +312,8 @@
if (!mTouchEnabled) {
return true;
}
- if (mIconLayoutBounds.contains((int) event.getX(), (int) event.getY())) {
- // Don't allow long pressing between icons.
+ if (mIconLayoutBounds.left <= event.getX() && event.getX() <= mIconLayoutBounds.right) {
+ // Don't allow long pressing between icons, or above/below them.
return true;
}
if (mControllerCallbacks.onTouchEvent(event)) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index e1ce898..6416720 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP;
import static com.android.quickstep.AnimatedFloat.VALUE;
import android.annotation.NonNull;
@@ -341,7 +342,10 @@
}
public View.OnClickListener getAllAppsButtonClickListener() {
- return v -> mControllers.taskbarAllAppsController.show();
+ return v -> {
+ mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP);
+ mControllers.taskbarAllAppsController.show();
+ };
}
public View.OnLongClickListener getIconOnLongClickListener() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
index 0ea2aa0..51fa4d9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
@@ -44,9 +44,10 @@
}
@Override
- protected BaseAllAppsAdapter getAdapter(AlphabeticalAppsList<TaskbarAllAppsContext> mAppsList,
+ protected BaseAllAppsAdapter<TaskbarAllAppsContext> createAdapter(
+ AlphabeticalAppsList<TaskbarAllAppsContext> appsList,
BaseAdapterProvider[] adapterProviders) {
- return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), mAppsList,
+ return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), appsList,
adapterProviders);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index 5d2d72a..a37ebac 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -34,7 +34,7 @@
public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarAllAppsContext>
implements Insettable, DeviceProfile.OnDeviceProfileChangeListener {
static final int DEFAULT_OPEN_DURATION = 500;
- static final int DEFAULT_CLOSE_DURATION = 200;
+ public static final int DEFAULT_CLOSE_DURATION = 200;
private TaskbarAllAppsContainerView mAppsView;
private OnCloseListener mOnCloseBeginListener;
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
index 32ebbe8..f19b7de 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
@@ -16,7 +16,6 @@
package com.android.launcher3.taskbar.allapps;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_IN_APP_ALL_APPS;
-import static com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView.DEFAULT_CLOSE_DURATION;
import static com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView.DEFAULT_OPEN_DURATION;
import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT;
@@ -86,9 +85,9 @@
mSlideInView.setOnCloseBeginListener(() -> {
AbstractFloatingView.closeOpenContainer(
mContext, AbstractFloatingView.TYPE_ACTION_POPUP);
- mTaskbarStashController.updateStateForFlag(
- FLAG_STASHED_IN_APP_ALL_APPS, false);
- mTaskbarStashController.applyState(DEFAULT_CLOSE_DURATION);
+ // Post in case view is closing due to gesture navigation. If a gesture is in progress,
+ // wait to unstash until after the gesture is finished.
+ mSlideInView.post(mTaskbarStashController::maybeResetStashedInAppAllApps);
});
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 829accc..f32b315 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -263,7 +263,7 @@
switch (state.ordinal) {
case HINT_STATE_ORDINAL: {
- Workspace workspace = getWorkspace();
+ Workspace<?> workspace = getWorkspace();
getStateManager().goToState(NORMAL);
if (workspace.getNextPage() != Workspace.DEFAULT_PAGE) {
workspace.post(workspace::moveToDefaultScreen);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 947d3e2..86f26c3 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -107,7 +107,6 @@
*/
private void handleSplitSelectionState(@NonNull LauncherState toState,
@Nullable PendingAnimation builder) {
- LauncherState currentState = mLauncher.getStateManager().getState();
boolean animate = builder != null;
PagedOrientationHandler orientationHandler =
((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler();
@@ -116,7 +115,7 @@
TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
mLauncher.getDeviceProfile());
- if (isSplitSelectionState(currentState, toState)) {
+ if (toState == OVERVIEW_SPLIT_SELECT) {
// Animation to "dismiss" selected taskView
PendingAnimation splitSelectInitAnimation = mRecentsView.createSplitSelectInitAnimation(
toState.getTransitionDuration(mLauncher));
@@ -125,30 +124,18 @@
toState.getSplitSelectTranslation(mLauncher), LINEAR);
splitSelectInitAnimation.setFloat(mRecentsView, taskViewsFloat.second, 0, LINEAR);
- if (!animate && isSplitSelectionState(currentState, toState)) {
+ if (!animate) {
splitSelectInitAnimation.buildAnim().start();
- } else if (animate &&
- isSplitSelectionState(currentState, toState)) {
+ } else {
builder.add(splitSelectInitAnimation.buildAnim());
}
- }
- if (isSplitSelectionState(currentState, toState)) {
mRecentsView.applySplitPrimaryScrollOffset();
} else {
mRecentsView.resetSplitPrimaryScrollOffset();
}
}
- /**
- * @return true if {@param toState} is {@link LauncherState#OVERVIEW_SPLIT_SELECT}
- * and {@param fromState} is not {@link LauncherState#OVERVIEW_SPLIT_SELECT}
- */
- private boolean isSplitSelectionState(@NonNull LauncherState fromState,
- @NonNull LauncherState toState) {
- return fromState != OVERVIEW_SPLIT_SELECT && toState == OVERVIEW_SPLIT_SELECT;
- }
-
private void setAlphas(PropertySetter propertySetter, StateAnimationConfig config,
LauncherState state) {
float clearAllButtonAlpha = state.areElementsVisible(mLauncher, CLEAR_ALL_BUTTON) ? 1 : 0;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index 4d05349..b1d83e7 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -118,7 +118,7 @@
config.duration = Math.max(config.duration, scrollDuration);
overview.snapToPage(DEFAULT_PAGE, Math.toIntExact(config.duration));
- Workspace workspace = mActivity.getWorkspace();
+ Workspace<?> workspace = mActivity.getWorkspace();
// Start from a higher workspace scale, but only if we're invisible so we don't jump.
boolean isWorkspaceVisible = workspace.getVisibility() == VISIBLE;
if (isWorkspaceVisible) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index 86c42ca..34a6821 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -21,7 +21,8 @@
import static com.android.launcher3.LauncherAnimUtils.newCancelListener;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
+import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PULL_BACK_ALPHA;
+import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PULL_BACK_TRANSLATION;
import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_EDU;
@@ -40,16 +41,14 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.util.TouchController;
import com.android.quickstep.TaskUtils;
+import com.android.quickstep.TopTaskTracker;
import com.android.quickstep.util.AnimatorControllerWithResistance;
-import com.android.quickstep.util.AssistantUtilities;
import com.android.quickstep.util.OverviewToHomeAnim;
import com.android.quickstep.views.RecentsView;
@@ -112,7 +111,8 @@
return true;
}
if (FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS.get()
- && AssistantUtilities.isExcludedAssistantRunning()) {
+ && TopTaskTracker.INSTANCE.get(mLauncher).getCachedTopTask(false)
+ .isExcludedAssistant()) {
return true;
}
return false;
@@ -147,16 +147,10 @@
AbstractFloatingView.closeOpenContainer(mLauncher, AbstractFloatingView.TYPE_TASK_MENU);
} else if (mStartState == ALL_APPS) {
AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
- builder.setFloat(allAppsController, ALL_APPS_PROGRESS,
- -mPullbackDistance / allAppsController.getShiftRange(), PULLBACK_INTERPOLATOR);
-
- // Slightly fade out all apps content to further distinguish from scrolling.
- StateAnimationConfig config = new StateAnimationConfig();
- config.duration = accuracy;
- config.setInterpolator(StateAnimationConfig.ANIM_ALL_APPS_FADE, Interpolators
- .mapToProgress(PULLBACK_INTERPOLATOR, 0, 0.5f));
-
- allAppsController.setAlphas(mEndState, config, builder);
+ builder.setFloat(allAppsController, ALL_APPS_PULL_BACK_TRANSLATION,
+ -mPullbackDistance, PULLBACK_INTERPOLATOR);
+ builder.setFloat(allAppsController, ALL_APPS_PULL_BACK_ALPHA,
+ 0.5f, PULLBACK_INTERPOLATOR);
}
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mLauncher);
if (topView != null) {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 6e80402..b90e820 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -102,7 +102,6 @@
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.InputConsumerProxy;
import com.android.quickstep.util.InputProxyHandlerFactory;
-import com.android.quickstep.util.LauncherSplitScreenListener;
import com.android.quickstep.util.MotionPauseDetector;
import com.android.quickstep.util.ProtoTracer;
import com.android.quickstep.util.RecentsOrientedState;
@@ -114,6 +113,7 @@
import com.android.quickstep.util.VibratorWrapper;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputConsumerController;
@@ -564,24 +564,12 @@
}
protected void notifyGestureAnimationStartToRecents() {
- ActivityManager.RunningTaskInfo[] runningTasks;
+ Task[] runningTasks;
if (mIsSwipeForStagedSplit) {
- int[] splitTaskIds =
- LauncherSplitScreenListener.INSTANCE.getNoCreate().getRunningSplitTaskIds();
- runningTasks = new ActivityManager.RunningTaskInfo[splitTaskIds.length];
- for (int i = 0; i < splitTaskIds.length; i++) {
- int taskId = splitTaskIds[i];
- // Order matters here, we want first indexed RunningTaskInfo to be leftTop task
- for (ActivityManager.RunningTaskInfo rti : mGestureState.getRunningTasks()) {
- if (taskId == rti.taskId) {
- runningTasks[i] = rti;
- break;
- }
-
- }
- }
+ int[] splitTaskIds = TopTaskTracker.INSTANCE.get(mContext).getRunningSplitTaskIds();
+ runningTasks = mGestureState.getRunningTask().getPlaceholderTasks(splitTaskIds);
} else {
- runningTasks = new ActivityManager.RunningTaskInfo[]{mGestureState.getRunningTask()};
+ runningTasks = mGestureState.getRunningTask().getPlaceholderTasks();
}
mRecentsView.onGestureAnimationStart(runningTasks, mDeviceState.getRotationTouchHelper());
}
@@ -782,7 +770,7 @@
// We will handle the sysui flags based on the centermost task view.
mRecentsAnimationController.setUseLauncherSystemBarFlags(swipeUpThresholdPassed
|| (quickswitchThresholdPassed && centermostTaskFlags != 0));
- mRecentsAnimationController.setSplitScreenMinimized(swipeUpThresholdPassed);
+ mRecentsAnimationController.setSplitScreenMinimized(mContext, swipeUpThresholdPassed);
// Provide a hint to WM the direction that we will be settling in case the animation
// needs to be canceled
mRecentsAnimationController.setWillFinishToHome(swipeUpThresholdPassed);
@@ -801,7 +789,7 @@
RecentsAnimationTargets targets) {
super.onRecentsAnimationStart(controller, targets);
ActiveGestureLog.INSTANCE.addLog("startRecentsAnimationCallback", targets.apps.length);
- mRemoteTargetHandles = mTargetGluer.assignTargetsForSplitScreen(targets);
+ mRemoteTargetHandles = mTargetGluer.assignTargetsForSplitScreen(mContext, targets);
mRecentsAnimationController = controller;
mRecentsAnimationTargets = targets;
@@ -1018,35 +1006,41 @@
return false;
}
- private GestureEndTarget calculateEndTarget(PointF velocity, float endVelocity, boolean isFling,
- boolean isCancel) {
+ private GestureEndTarget calculateEndTarget(PointF velocity, float endVelocity,
+ boolean isFlingY, boolean isCancel) {
if (mGestureState.isHandlingAtomicEvent()) {
// Button mode, this is only used to go to recents
return RECENTS;
}
final GestureEndTarget endTarget;
- final boolean goingToNewTask;
+ final boolean canGoToNewTask;
if (mRecentsView != null) {
if (!hasTargets()) {
// If there are no running tasks, then we can assume that this is a continuation of
// the last gesture, but after the recents animation has finished
- goingToNewTask = true;
+ canGoToNewTask = true;
} else {
final int runningTaskIndex = mRecentsView.getRunningTaskIndex();
final int taskToLaunch = mRecentsView.getNextPage();
- goingToNewTask = runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex;
+ canGoToNewTask = runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex;
}
} else {
- goingToNewTask = false;
+ canGoToNewTask = false;
}
final boolean reachedOverviewThreshold = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW;
- if (!isFling) {
+ final boolean isFlingX = Math.abs(velocity.x) > mContext.getResources()
+ .getDimension(R.dimen.quickstep_fling_threshold_speed);
+ if (!isFlingY) {
if (isCancel) {
endTarget = LAST_TASK;
} else if (mDeviceState.isFullyGesturalNavMode()) {
- if (mIsMotionPaused) {
+ if (canGoToNewTask && isFlingX) {
+ // Flinging towards new task takes precedence over mIsMotionPaused (which only
+ // checks y-velocity).
+ endTarget = NEW_TASK;
+ } else if (mIsMotionPaused) {
endTarget = RECENTS;
- } else if (goingToNewTask) {
+ } else if (canGoToNewTask) {
endTarget = NEW_TASK;
} else {
endTarget = !reachedOverviewThreshold ? LAST_TASK : HOME;
@@ -1054,26 +1048,22 @@
} else {
endTarget = reachedOverviewThreshold && mGestureStarted
? RECENTS
- : goingToNewTask
+ : canGoToNewTask
? NEW_TASK
: LAST_TASK;
}
} else {
// If swiping at a diagonal, base end target on the faster velocity.
boolean isSwipeUp = endVelocity < 0;
- boolean willGoToNewTaskOnSwipeUp =
- goingToNewTask && Math.abs(velocity.x) > Math.abs(endVelocity);
+ boolean willGoToNewTask =
+ canGoToNewTask && Math.abs(velocity.x) > Math.abs(endVelocity);
- if (mDeviceState.isFullyGesturalNavMode() && isSwipeUp && !willGoToNewTaskOnSwipeUp) {
- endTarget = HOME;
- } else if (mDeviceState.isFullyGesturalNavMode() && isSwipeUp) {
- // If swiping at a diagonal, base end target on the faster velocity.
- endTarget = NEW_TASK;
+ if (mDeviceState.isFullyGesturalNavMode() && isSwipeUp) {
+ endTarget = willGoToNewTask ? NEW_TASK : HOME;
} else if (isSwipeUp) {
- endTarget = !reachedOverviewThreshold && willGoToNewTaskOnSwipeUp
- ? NEW_TASK : RECENTS;
+ endTarget = (!reachedOverviewThreshold && willGoToNewTask) ? NEW_TASK : RECENTS;
} else {
- endTarget = goingToNewTask ? NEW_TASK : LAST_TASK;
+ endTarget = willGoToNewTask ? NEW_TASK : LAST_TASK; // Swipe is downward.
}
}
@@ -1151,6 +1141,8 @@
duration = Math.max(duration, mRecentsView.getScroller().getDuration());
}
}
+ } else if (endTarget == LAST_TASK && mRecentsView != null) {
+ mRecentsView.snapToPage(mRecentsView.getCurrentPage(), Math.toIntExact(duration));
}
// Let RecentsView handle the scrolling to the task, which we launch in startNewTask()
@@ -1380,7 +1372,7 @@
private SwipePipToHomeAnimator createWindowAnimationToPip(HomeAnimationFactory homeAnimFactory,
RemoteAnimationTargetCompat runningTaskTarget, float startProgress) {
// Directly animate the app to PiP (picture-in-picture) mode
- final ActivityManager.RunningTaskInfo taskInfo = mGestureState.getRunningTask();
+ final ActivityManager.RunningTaskInfo taskInfo = runningTaskTarget.taskInfo;
final RecentsOrientedState orientationState = mRemoteTargetHandles[0].getTaskViewSimulator()
.getOrientationState();
final int windowRotation = calculateWindowRotation(runningTaskTarget, orientationState);
@@ -1782,8 +1774,7 @@
new PictureInPictureSurfaceTransaction.Builder()
.setAlpha(0f)
.build();
- int[] taskIds =
- LauncherSplitScreenListener.INSTANCE.getNoCreate().getRunningSplitTaskIds();
+ int[] taskIds = TopTaskTracker.INSTANCE.get(mContext).getRunningSplitTaskIds();
for (int taskId : taskIds) {
mRecentsAnimationController.setFinishTaskTransaction(taskId,
tx, null /* overlay */);
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index 9828467..ee5bb44 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -30,7 +30,7 @@
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
-import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
import android.content.Context;
@@ -69,7 +69,6 @@
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.TransformParams.BuilderProxy;
import com.android.systemui.shared.recents.model.Task.TaskKey;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
@@ -109,7 +108,7 @@
super(context, deviceState, taskAnimationManager, gestureState, touchTimeMs,
continuingLastGesture, inputConsumer);
- mRunningOverHome = ActivityManagerWrapper.isHomeTask(mGestureState.getRunningTask());
+ mRunningOverHome = mGestureState.getRunningTask().isHomeTask();
if (mRunningOverHome) {
runActionOnRemoteHandles(remoteTargetHandle ->
remoteTargetHandle.getTransformParams().setHomeBuilderProxy(
@@ -150,16 +149,17 @@
return new FallbackPipToHomeAnimationFactory();
}
mActiveAnimationFactory = new FallbackHomeAnimationFactory(duration);
- startHomeIntent(mActiveAnimationFactory);
+ startHomeIntent(mActiveAnimationFactory, runningTaskTarget);
return mActiveAnimationFactory;
}
private void startHomeIntent(
- @Nullable FallbackHomeAnimationFactory gestureContractAnimationFactory) {
+ @Nullable FallbackHomeAnimationFactory gestureContractAnimationFactory,
+ @Nullable RemoteAnimationTargetCompat runningTaskTarget) {
ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
Intent intent = new Intent(mGestureState.getHomeIntent());
- if (gestureContractAnimationFactory != null) {
- gestureContractAnimationFactory.addGestureContract(intent);
+ if (gestureContractAnimationFactory != null && runningTaskTarget != null) {
+ gestureContractAnimationFactory.addGestureContract(intent, runningTaskTarget.taskInfo);
}
try {
mContext.startActivity(intent, options.toBundle());
@@ -187,7 +187,8 @@
// the PiP task appearing.
recentsCallback = () -> {
callback.run();
- startHomeIntent(null /* gestureContractAnimationFactory */);
+ startHomeIntent(
+ null /* gestureContractAnimationFactory */, null /* runningTaskTarget */);
};
} else {
recentsCallback = callback;
@@ -212,7 +213,7 @@
if (mRunningOverHome) {
if (DisplayController.getNavigationMode(mContext).hasGestures) {
mRecentsView.onGestureAnimationStartOnHome(
- new ActivityManager.RunningTaskInfo[]{mGestureState.getRunningTask()},
+ mGestureState.getRunningTask().getPlaceholderTasks(),
mDeviceState.getRotationTouchHelper());
}
} else {
@@ -396,12 +397,12 @@
}
}
- private void addGestureContract(Intent intent) {
- if (mRunningOverHome || mGestureState.getRunningTask() == null) {
+ private void addGestureContract(Intent intent, RunningTaskInfo runningTaskInfo) {
+ if (mRunningOverHome || runningTaskInfo == null) {
return;
}
- TaskKey key = new TaskKey(mGestureState.getRunningTask());
+ TaskKey key = new TaskKey(runningTaskInfo);
if (key.getComponent() != null) {
if (sMessageReceiver == null) {
sMessageReceiver = new StaticMessageReceiver();
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index ed0623d..3b52e91 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -22,7 +22,6 @@
import android.annotation.Nullable;
import android.annotation.TargetApi;
-import android.app.ActivityManager;
import android.content.Intent;
import android.os.Build;
@@ -30,6 +29,7 @@
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.tracing.GestureStateProto;
import com.android.launcher3.tracing.SwipeHandlerProto;
+import com.android.quickstep.TopTaskTracker.CachedTaskInfo;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -135,8 +135,7 @@
private final MultiStateCallback mStateCallback;
private final int mGestureId;
- private ActivityManager.RunningTaskInfo mRunningTask;
- private ActivityManager.RunningTaskInfo[] mRunningTasks;
+ private CachedTaskInfo mRunningTask;
private GestureEndTarget mEndTarget;
private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
private Set<Integer> mPreviouslyAppearedTaskIds = new HashSet<>();
@@ -232,42 +231,25 @@
/**
* @return the running task for this gesture.
*/
- public ActivityManager.RunningTaskInfo getRunningTask() {
+ public CachedTaskInfo getRunningTask() {
return mRunningTask;
}
/**
- * This will array will contain the task returned by {@link #getRunningTask()}
- * @return the running tasks for this gesture.
- */
- public ActivityManager.RunningTaskInfo[] getRunningTasks() {
- return mRunningTasks;
- }
-
- /**
* @return the running task id for this gesture.
*/
public int getRunningTaskId() {
- return mRunningTask != null ? mRunningTask.taskId : -1;
+ return mRunningTask != null ? mRunningTask.getTaskId() : -1;
}
/**
* Updates the running task for the gesture to be the given {@param runningTask}.
*/
- public void updateRunningTask(ActivityManager.RunningTaskInfo runningTask) {
+ public void updateRunningTask(CachedTaskInfo runningTask) {
mRunningTask = runningTask;
}
/**
- * TODO(b/210903248) refactor to consolidate w/ method above
- * Updates the running task for the gesture to be the given {@param runningTask}.
- */
- public void updateRunningTasks(ActivityManager.RunningTaskInfo[] runningTasks) {
- mRunningTasks = runningTasks;
- updateRunningTask(runningTasks[0]);
- }
-
- /**
* Updates the last task that appeared during this gesture.
*/
public void updateLastAppearedTaskTarget(RemoteAnimationTargetCompat lastAppearedTaskTarget) {
@@ -339,7 +321,7 @@
* user controlled gesture.
*/
public void setHandlingAtomicEvent(boolean handlingAtomicEvent) {
- mHandlingAtomicEvent = true;
+ mHandlingAtomicEvent = handlingAtomicEvent;
}
/**
diff --git a/quickstep/src/com/android/quickstep/KtR.java b/quickstep/src/com/android/quickstep/KtR.java
index a768ef5..758c6e0 100644
--- a/quickstep/src/com/android/quickstep/KtR.java
+++ b/quickstep/src/com/android/quickstep/KtR.java
@@ -31,6 +31,7 @@
public static final class dimen {
public static int task_menu_spacing = R.dimen.task_menu_spacing;
public static int task_menu_horizontal_padding = R.dimen.task_menu_horizontal_padding;
+ public static int taskbar_ime_size = R.dimen.taskbar_ime_size;
}
public static final class layout {
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
index 7abcbdb..921674a 100644
--- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -25,19 +25,20 @@
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.graphics.Matrix;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
-import android.util.Log;
import android.util.MathUtils;
import android.util.Pair;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import android.window.BackEvent;
import android.window.IOnBackInvokedCallback;
import com.android.launcher3.BaseQuickstepLauncher;
-import com.android.launcher3.DeviceProfile;
import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -53,7 +54,7 @@
* the app window and plays the rest of app close transitions in one go.
*
* This animation is used only for apps that enable back dispatching via
- * {@link android.view.OnBackInvokedDispatcher}. The controller registers
+ * {@link android.window.OnBackInvokedDispatcher}. The controller registers
* an {@link IOnBackInvokedCallback} with WM Shell and receives back dispatches when a back
* navigation to launcher starts.
*
@@ -62,34 +63,35 @@
*
*/
public class LauncherBackAnimationController {
- private static final int CANCEL_TRANSITION_DURATION = 150;
- private static final String TAG = "LauncherBackAnimationController";
- private final DeviceProfile mDeviceProfile;
+ private static final int CANCEL_TRANSITION_DURATION = 233;
+ private static final float MIN_WINDOW_SCALE = 0.7f;
private final QuickstepTransitionManager mQuickstepTransitionManager;
private final Matrix mTransformMatrix = new Matrix();
- private final RectF mTargetRectF = new RectF();
- private final RectF mStartRectF = new RectF();
+ /** The window position at the beginning of the back animation. */
+ private final Rect mStartRect = new Rect();
+ /** The window position when the back gesture is cancelled. */
+ private final RectF mCancelRect = new RectF();
+ /** The current window position. */
private final RectF mCurrentRect = new RectF();
private final BaseQuickstepLauncher mLauncher;
private final int mWindowScaleMarginX;
- private final int mWindowScaleMarginY;
+ /** Max window translation in the Y axis. */
+ private final int mWindowMaxDeltaY;
private final float mWindowScaleEndCornerRadius;
private final float mWindowScaleStartCornerRadius;
+ private final Interpolator mCancelInterpolator;
+ private final PointF mInitialTouchPos = new PointF();
private RemoteAnimationTargetCompat mBackTarget;
private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
private boolean mSpringAnimationInProgress = false;
private boolean mAnimatorSetInProgress = false;
- @BackEvent.SwipeEdge
- private int mSwipeEdge;
private float mBackProgress = 0;
private boolean mBackInProgress = false;
public LauncherBackAnimationController(
- DeviceProfile deviceProfile,
BaseQuickstepLauncher launcher,
QuickstepTransitionManager quickstepTransitionManager) {
- mDeviceProfile = deviceProfile;
mLauncher = launcher;
mQuickstepTransitionManager = quickstepTransitionManager;
mWindowScaleEndCornerRadius = QuickStepContract.supportsRoundedCornersOnWindows(
@@ -100,8 +102,10 @@
mWindowScaleStartCornerRadius = QuickStepContract.getWindowCornerRadius(mLauncher);
mWindowScaleMarginX = mLauncher.getResources().getDimensionPixelSize(
R.dimen.swipe_back_window_scale_x_margin);
- mWindowScaleMarginY = mLauncher.getResources().getDimensionPixelSize(
- R.dimen.swipe_back_window_scale_y_margin);
+ mWindowMaxDeltaY = mLauncher.getResources().getDimensionPixelSize(
+ R.dimen.swipe_back_window_max_delta_y);
+ mCancelInterpolator =
+ AnimationUtils.loadInterpolator(mLauncher, R.interpolator.back_cancel);
}
/**
@@ -109,12 +113,7 @@
* @param handler Handler to the thread to run the animations on.
*/
public void registerBackCallbacks(Handler handler) {
- SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.getNoCreate();
- if (systemUiProxy == null) {
- Log.e(TAG, "SystemUiProxy is null. Skip registering back invocation callbacks");
- return;
- }
- systemUiProxy.setBackToLauncherCallback(
+ SystemUiProxy.INSTANCE.get(mLauncher).setBackToLauncherCallback(
new IOnBackInvokedCallback.Stub() {
@Override
public void onBackCancelled() {
@@ -136,7 +135,7 @@
if (!mBackInProgress) {
startBack(backEvent);
} else {
- updateBackProgress(mBackProgress);
+ updateBackProgress(mBackProgress, backEvent);
}
}
@@ -145,11 +144,13 @@
}
private void resetPositionAnimated() {
- ValueAnimator cancelAnimator = ValueAnimator.ofFloat(mBackProgress, 0);
+ ValueAnimator cancelAnimator = ValueAnimator.ofFloat(0, 1);
+ mCancelRect.set(mCurrentRect);
cancelAnimator.setDuration(CANCEL_TRANSITION_DURATION);
+ cancelAnimator.setInterpolator(mCancelInterpolator);
cancelAnimator.addUpdateListener(
animation -> {
- updateBackProgress((float) animation.getAnimatedValue());
+ updateCancelProgress((float) animation.getAnimatedValue());
});
cancelAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -162,10 +163,7 @@
/** Unregisters the back to launcher callback in shell. */
public void unregisterBackCallbacks() {
- SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.getNoCreate();
- if (systemUiProxy != null) {
- systemUiProxy.clearBackToLauncherCallback();
- }
+ SystemUiProxy.INSTANCE.get(mLauncher).clearBackToLauncherCallback();
}
private void startBack(BackEvent backEvent) {
@@ -179,50 +177,70 @@
mTransaction.show(appTarget.leash).apply();
mTransaction.setAnimationTransaction();
mBackTarget = new RemoteAnimationTargetCompat(appTarget);
- mSwipeEdge = backEvent.getSwipeEdge();
- float screenWidth = mDeviceProfile.widthPx;
- float screenHeight = mDeviceProfile.heightPx;
- float targetHeight = screenHeight - 2 * mWindowScaleMarginY;
- float targetWidth = targetHeight * screenWidth / screenHeight;
- float left;
- if (mSwipeEdge == BackEvent.EDGE_LEFT) {
- left = screenWidth - targetWidth - mWindowScaleMarginX;
- } else {
- left = mWindowScaleMarginX;
- }
- float top = mWindowScaleMarginY;
+ mInitialTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY());
+
// TODO(b/218916755): Offset start rectangle in multiwindow mode.
- mStartRectF.set(0, 0, screenWidth, screenHeight);
- mTargetRectF.set(left, top, targetWidth + left, targetHeight + top);
+ mStartRect.set(mBackTarget.windowConfiguration.getMaxBounds());
}
- private void updateBackProgress(float progress) {
+ private void updateBackProgress(float progress, BackEvent event) {
if (mBackTarget == null) {
return;
}
+ float screenWidth = mStartRect.width();
+ float screenHeight = mStartRect.height();
+ float dX = Math.abs(event.getTouchX() - mInitialTouchPos.x);
+ // The 'follow width' is the width of the window if it completely matches
+ // the gesture displacement.
+ float followWidth = screenWidth - dX;
+ // The 'progress width' is the width of the window if it strictly linearly interpolates
+ // to minimum scale base on progress.
+ float progressWidth = MathUtils.lerp(1, MIN_WINDOW_SCALE, progress) * screenWidth;
+ // The final width is derived from interpolating between the follow with and progress width
+ // using gesture progress.
+ float width = MathUtils.lerp(followWidth, progressWidth, progress);
+ float height = screenHeight / screenWidth * width;
+ float deltaYRatio = (event.getTouchY() - mInitialTouchPos.y) / screenHeight;
+ // Base the window movement in the Y axis on the touch movement in the Y axis.
+ float deltaY = (float) Math.sin(deltaYRatio * Math.PI * 0.5f) * mWindowMaxDeltaY;
+ // Move the window along the Y axis.
+ float top = (screenHeight - height) * 0.5f + deltaY;
+ // Move the window along the X axis.
+ float left = event.getSwipeEdge() == BackEvent.EDGE_RIGHT
+ ? progress * mWindowScaleMarginX
+ : screenWidth - progress * mWindowScaleMarginX - width;
- mCurrentRect.set(
- MathUtils.lerp(mStartRectF.left, mTargetRectF.left, progress),
- MathUtils.lerp(mStartRectF.top, mTargetRectF.top, progress),
- MathUtils.lerp(mStartRectF.right, mTargetRectF.right, progress),
- MathUtils.lerp(mStartRectF.bottom, mTargetRectF.bottom, progress));
- SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder builder =
- new SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder(mBackTarget.leash);
-
- Rect currentRect = new Rect();
- mCurrentRect.round(currentRect);
-
- // Scale the target window to match the currentRectF.
- final float scale = mCurrentRect.width() / mStartRectF.width();
- mTransformMatrix.reset();
- mTransformMatrix.setScale(scale, scale);
- mTransformMatrix.postTranslate(mCurrentRect.left, mCurrentRect.top);
- Rect startRect = new Rect();
- mStartRectF.round(startRect);
+ mCurrentRect.set(left, top, left + width, top + height);
float cornerRadius = Utilities.mapRange(
progress, mWindowScaleStartCornerRadius, mWindowScaleEndCornerRadius);
+ applyTransform(mCurrentRect, cornerRadius);
+ }
+
+ private void updateCancelProgress(float progress) {
+ if (mBackTarget == null) {
+ return;
+ }
+ mCurrentRect.set(
+ MathUtils.lerp(mCancelRect.left, mStartRect.left, progress),
+ MathUtils.lerp(mCancelRect.top, mStartRect.top, progress),
+ MathUtils.lerp(mCancelRect.right, mStartRect.right, progress),
+ MathUtils.lerp(mCancelRect.bottom, mStartRect.bottom, progress));
+
+ float cornerRadius = Utilities.mapRange(
+ progress, mWindowScaleEndCornerRadius, mWindowScaleStartCornerRadius);
+ applyTransform(mCurrentRect, cornerRadius);
+ }
+
+ /** Transform the target window to match the target rect. */
+ private void applyTransform(RectF targetRect, float cornerRadius) {
+ SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder builder =
+ new SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder(mBackTarget.leash);
+ final float scale = targetRect.width() / mStartRect.width();
+ mTransformMatrix.reset();
+ mTransformMatrix.setScale(scale, scale);
+ mTransformMatrix.postTranslate(targetRect.left, targetRect.top);
builder.withMatrix(mTransformMatrix)
- .withWindowCrop(startRect)
+ .withWindowCrop(mStartRect)
.withCornerRadius(cornerRadius);
SyncRtSurfaceTransactionApplierCompat.SurfaceParams surfaceParams = builder.build();
@@ -263,17 +281,14 @@
mBackTarget = null;
mBackInProgress = false;
mBackProgress = 0;
- mSwipeEdge = BackEvent.EDGE_LEFT;
mTransformMatrix.reset();
- mTargetRectF.setEmpty();
+ mCancelRect.setEmpty();
mCurrentRect.setEmpty();
- mStartRectF.setEmpty();
+ mStartRect.setEmpty();
+ mInitialTouchPos.set(0, 0);
mAnimatorSetInProgress = false;
mSpringAnimationInProgress = false;
- SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.getNoCreate();
- if (systemUiProxy != null) {
- SystemUiProxy.INSTANCE.getNoCreate().onBackToLauncherAnimationFinished();
- }
+ SystemUiProxy.INSTANCE.get(mLauncher).onBackToLauncherAnimationFinished();
}
private void startTransitionAnimations(RectFSpringAnim springAnim, AnimatorSet anim) {
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index c120b32..2007ee1 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -19,6 +19,7 @@
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
+import android.content.Context;
import android.os.RemoteException;
import android.util.Log;
import android.view.IRecentsAnimationController;
@@ -97,24 +98,20 @@
* Indicates that the gesture has crossed the window boundary threshold and we should minimize
* if we are in splitscreen.
*/
- public void setSplitScreenMinimized(boolean splitScreenMinimized) {
+ public void setSplitScreenMinimized(Context context, boolean splitScreenMinimized) {
if (!mAllowMinimizeSplitScreen) {
return;
}
if (mSplitScreenMinimized != splitScreenMinimized) {
mSplitScreenMinimized = splitScreenMinimized;
- UI_HELPER_EXECUTOR.execute(() -> {
- SystemUiProxy p = SystemUiProxy.INSTANCE.getNoCreate();
- if (p != null) {
- p.setSplitScreenMinimized(splitScreenMinimized);
- }
- });
+ UI_HELPER_EXECUTOR.execute(() -> SystemUiProxy.INSTANCE.get(context)
+ .setSplitScreenMinimized(splitScreenMinimized));
}
}
/**
* Remove task remote animation target from
- * {@link RecentsAnimationCallbacks#onTaskAppeared(RemoteAnimationTargetCompat)}}.
+ * {@link RecentsAnimationCallbacks#onTasksAppeared}}.
*/
@UiThread
public void removeTaskTarget(@NonNull RemoteAnimationTargetCompat target) {
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 7ad60bb..920ed71 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -45,14 +45,11 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
-import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.res.Resources;
import android.graphics.Region;
import android.inputmethodservice.InputMethodService;
import android.net.Uri;
@@ -61,18 +58,17 @@
import android.os.SystemProperties;
import android.os.UserManager;
import android.provider.Settings;
-import android.text.TextUtils;
import android.view.MotionEvent;
import androidx.annotation.BinderThread;
-import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.DisplayController.NavigationMode;
import com.android.launcher3.util.SettingsCache;
+import com.android.quickstep.TopTaskTracker.CachedTaskInfo;
import com.android.quickstep.util.NavBarPosition;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
@@ -83,7 +79,6 @@
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.List;
/**
* Manages the state of the system during a swipe up gesture.
@@ -97,7 +92,6 @@
private final int mDisplayId;
private final RotationTouchHelper mRotationTouchHelper;
private final TaskStackChangeListener mPipListener;
- private final List<ComponentName> mGestureBlockedActivities;
// Cache for better performance since it doesn't change at runtime.
private final boolean mCanImeRenderGesturalNavButtons =
InputMethodService.canImeRenderGesturalNavButtons();
@@ -129,6 +123,7 @@
}
};
+ private int mGestureBlockingTaskId = -1;
private Region mExclusionRegion;
private SystemGestureExclusionListenerCompat mExclusionListener;
@@ -178,22 +173,6 @@
onDisplayInfoChanged(context, mDisplayController.getInfo(), CHANGE_ALL);
runOnDestroy(() -> mDisplayController.removeChangeListener(this));
- // Add any blocked activities
- String[] blockingActivities;
- try {
- blockingActivities =
- context.getResources().getStringArray(R.array.gesture_blocking_activities);
- } catch (Resources.NotFoundException e) {
- blockingActivities = new String[0];
- }
- mGestureBlockedActivities = new ArrayList<>(blockingActivities.length);
- for (String blockingActivity : blockingActivities) {
- if (!TextUtils.isEmpty(blockingActivity)) {
- mGestureBlockedActivities.add(
- ComponentName.unflattenFromString(blockingActivity));
- }
- }
-
SettingsCache settingsCache = SettingsCache.INSTANCE.get(mContext);
if (mIsOneHandedModeSupported) {
Uri oneHandedUri = Settings.Secure.getUriFor(ONE_HANDED_ENABLED);
@@ -367,11 +346,17 @@
}
/**
- * @return whether the given running task info matches the gesture-blocked activity.
+ * Sets the task id where gestures should be blocked
*/
- public boolean isGestureBlockedActivity(ActivityManager.RunningTaskInfo runningTaskInfo) {
- return runningTaskInfo != null
- && mGestureBlockedActivities.contains(runningTaskInfo.topActivity);
+ public void setGestureBlockingTaskId(int taskId) {
+ mGestureBlockingTaskId = taskId;
+ }
+
+ /**
+ * @return whether the given running task info matches the gesture-blocked task.
+ */
+ public boolean isGestureBlockedTask(CachedTaskInfo taskInfo) {
+ return taskInfo != null && taskInfo.getTaskId() == mGestureBlockingTaskId;
}
/**
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 5d77a6e..d11d50b 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -54,7 +54,7 @@
* Singleton class to load and manage recents model.
*/
@TargetApi(Build.VERSION_CODES.O)
-public class RecentsModel extends TaskStackChangeListener implements IconChangeListener {
+public class RecentsModel implements IconChangeListener, TaskStackChangeListener {
// We do not need any synchronization for this variable as its only written on UI thread.
public static final MainThreadInitializedObject<RecentsModel> INSTANCE =
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index afb4d4d..c3ea256 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -22,7 +22,6 @@
import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
import com.android.quickstep.util.AnimatorControllerWithResistance;
-import com.android.quickstep.util.LauncherSplitScreenListener;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -50,8 +49,7 @@
* running tasks
*/
public RemoteTargetGluer(Context context, BaseActivityInterface sizingStrategy) {
- int[] splitIds = LauncherSplitScreenListener.INSTANCE.getNoCreate()
- .getRunningSplitTaskIds();
+ int[] splitIds = TopTaskTracker.INSTANCE.get(context).getRunningSplitTaskIds();
mRemoteTargetHandles = createHandles(context, sizingStrategy, splitIds.length == 2 ? 2 : 1);
}
@@ -73,7 +71,7 @@
* Length of targets.apps should match that of {@link #mRemoteTargetHandles}.
*
* If split screen may be active when this is called, you might want to use
- * {@link #assignTargetsForSplitScreen(RemoteAnimationTargets)}
+ * {@link #assignTargetsForSplitScreen(Context, RemoteAnimationTargets)}
*/
public RemoteTargetHandle[] assignTargets(RemoteAnimationTargets targets) {
for (int i = 0; i < mRemoteTargetHandles.length; i++) {
@@ -90,9 +88,9 @@
* apps in targets.apps to that of the _active_ split screened tasks.
* See {@link #assignTargetsForSplitScreen(RemoteAnimationTargets, int[])}
*/
- public RemoteTargetHandle[] assignTargetsForSplitScreen(RemoteAnimationTargets targets) {
- int[] splitIds = LauncherSplitScreenListener.INSTANCE.getNoCreate()
- .getRunningSplitTaskIds();
+ public RemoteTargetHandle[] assignTargetsForSplitScreen(
+ Context context, RemoteAnimationTargets targets) {
+ int[] splitIds = TopTaskTracker.INSTANCE.get(context).getRunningSplitTaskIds();
return assignTargetsForSplitScreen(targets, splitIds);
}
diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
index f952e0d..f1e20db 100644
--- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java
+++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
@@ -74,7 +74,6 @@
@Override
public void onActivityRotation(int displayId) {
- super.onActivityRotation(displayId);
// This always gets called before onDisplayInfoChanged() so we know how to process
// the rotation in that method. This is done to avoid having a race condition between
// the sensor readings and onDisplayInfoChanged() call
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index 8862073..088e1cf 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -37,7 +37,6 @@
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
import com.android.quickstep.util.AnimatorControllerWithResistance;
-import com.android.quickstep.util.LauncherSplitScreenListener;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
@@ -82,8 +81,7 @@
mGestureState = gestureState;
mIsSwipeForStagedSplit = ENABLE_SPLIT_SELECT.get() &&
- LauncherSplitScreenListener.INSTANCE.getNoCreate()
- .getRunningSplitTaskIds().length > 1;
+ TopTaskTracker.INSTANCE.get(context).getRunningSplitTaskIds().length > 1;
mTargetGluer = new RemoteTargetGluer(mContext, mGestureState.getActivityInterface());
mRemoteTargetHandles = mTargetGluer.getRemoteTargetHandles();
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 4bb2400..f094d71 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -35,6 +35,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
+import com.android.quickstep.TopTaskTracker.CachedTaskInfo;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -176,9 +177,8 @@
((RecentsActivity) activityInterface.getCreatedActivity()).startHome();
return;
}
- RemoteAnimationTarget[] nonAppTargets =
- SystemUiProxy.INSTANCE.getNoCreate()
- .onGoingToRecentsLegacy(false, nonHomeApps);
+ RemoteAnimationTarget[] nonAppTargets = SystemUiProxy.INSTANCE.get(mCtx)
+ .onGoingToRecentsLegacy(false, nonHomeApps);
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityInterface.isInLiveTileMode()
&& activityInterface.getCreatedActivity() != null) {
@@ -234,9 +234,8 @@
// Allowing to pause Home if Home is top activity and Recents is not Home. So when user
// start home when recents animation is playing, the home activity can be resumed again
// to let the transition controller collect Home activity.
- ActivityManager.RunningTaskInfo rti = gestureState.getRunningTask();
- boolean homeIsOnTop = rti != null && rti.topActivity != null
- && rti.topActivity.equals(gestureState.getHomeIntent().getComponent());
+ CachedTaskInfo cti = gestureState.getRunningTask();
+ boolean homeIsOnTop = cti != null && cti.isHomeTask();
if (!homeIsOnTop) {
options.setTransientLaunch();
}
diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java
new file mode 100644
index 0000000..80bc329
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2022 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.quickstep;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.content.Intent.ACTION_CHOOSER;
+import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+
+import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT;
+
+import android.app.ActivityManager.RunningTaskInfo;
+import android.content.Context;
+
+import androidx.annotation.UiThread;
+
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SplitConfigurationOptions;
+import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
+import com.android.launcher3.util.SplitConfigurationOptions.StageType;
+import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitTaskPosition;
+import com.android.launcher3.util.TraceHelper;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
+import com.android.wm.shell.splitscreen.ISplitScreenListener;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This class tracked the top-most task and some 'approximate' task history to allow faster
+ * system state estimation during touch interaction
+ */
+public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskStackChangeListener {
+
+ public static MainThreadInitializedObject<TopTaskTracker> INSTANCE =
+ new MainThreadInitializedObject<>(TopTaskTracker::new);
+
+ private static final int HISTORY_SIZE = 5;
+
+ // Ordered list with first item being the most recent task.
+ private final LinkedList<RunningTaskInfo> mOrderedTaskList = new LinkedList<>();
+
+ private final StagedSplitTaskPosition mMainStagePosition = new StagedSplitTaskPosition();
+ private final StagedSplitTaskPosition mSideStagePosition = new StagedSplitTaskPosition();
+
+ private TopTaskTracker(Context context) {
+ mMainStagePosition.stageType = SplitConfigurationOptions.STAGE_TYPE_MAIN;
+ mSideStagePosition.stageType = SplitConfigurationOptions.STAGE_TYPE_SIDE;
+
+ TaskStackChangeListeners.getInstance().registerTaskStackListener(this);
+ SystemUiProxy.INSTANCE.get(context).registerSplitScreenListener(this);
+ }
+
+ @Override
+ public void onTaskRemoved(int taskId) {
+ mOrderedTaskList.removeIf(rto -> rto.taskId == taskId);
+ }
+
+ @Override
+ public void onTaskMovedToFront(RunningTaskInfo taskInfo) {
+ mOrderedTaskList.removeIf(rto -> rto.taskId == taskInfo.taskId);
+ mOrderedTaskList.addFirst(taskInfo);
+ if (mOrderedTaskList.size() >= HISTORY_SIZE) {
+ // If we grow in size, remove the last taskInfo which is not part of the split task.
+ Iterator<RunningTaskInfo> itr = mOrderedTaskList.descendingIterator();
+ while (itr.hasNext()) {
+ RunningTaskInfo info = itr.next();
+ if (info.taskId != taskInfo.taskId
+ && info.taskId != mMainStagePosition.taskId
+ && info.taskId != mSideStagePosition.taskId) {
+ itr.remove();
+ return;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onStagePositionChanged(@StageType int stage, @StagePosition int position) {
+ if (stage == SplitConfigurationOptions.STAGE_TYPE_MAIN) {
+ mMainStagePosition.stagePosition = position;
+ } else {
+ mSideStagePosition.stagePosition = position;
+ }
+ }
+
+ @Override
+ public void onTaskStageChanged(int taskId, @StageType int stage, boolean visible) {
+ // If task is not visible but we are tracking it, stop tracking it
+ if (!visible) {
+ if (mMainStagePosition.taskId == taskId) {
+ resetTaskId(mMainStagePosition);
+ } else if (mSideStagePosition.taskId == taskId) {
+ resetTaskId(mSideStagePosition);
+ } // else it's an un-tracked child
+ return;
+ }
+
+ // If stage has moved to undefined, stop tracking the task
+ if (stage == SplitConfigurationOptions.STAGE_TYPE_UNDEFINED) {
+ resetTaskId(taskId == mMainStagePosition.taskId
+ ? mMainStagePosition : mSideStagePosition);
+ return;
+ }
+
+ if (stage == SplitConfigurationOptions.STAGE_TYPE_MAIN) {
+ mMainStagePosition.taskId = taskId;
+ } else {
+ mSideStagePosition.taskId = taskId;
+ }
+ }
+
+ private void resetTaskId(StagedSplitTaskPosition taskPosition) {
+ taskPosition.taskId = -1;
+ }
+
+ /**
+ * @return index 0 will be task in left/top position, index 1 in right/bottom position.
+ * Will return empty array if device is not in staged split
+ */
+ public int[] getRunningSplitTaskIds() {
+ if (mMainStagePosition.taskId == -1 || mSideStagePosition.taskId == -1) {
+ return new int[]{};
+ }
+ int[] out = new int[2];
+ if (mMainStagePosition.stagePosition == STAGE_POSITION_TOP_OR_LEFT) {
+ out[0] = mMainStagePosition.taskId;
+ out[1] = mSideStagePosition.taskId;
+ } else {
+ out[1] = mMainStagePosition.taskId;
+ out[0] = mSideStagePosition.taskId;
+ }
+ return out;
+ }
+
+
+ /**
+ * Returns the CachedTaskInfo for the top most task
+ */
+ @UiThread
+ public CachedTaskInfo getCachedTopTask(boolean filterOnlyVisibleRecents) {
+ if (filterOnlyVisibleRecents) {
+ // Since we only know about the top most task, any filtering may not be applied on the
+ // cache. The second to top task may change while the top task is still the same.
+ RunningTaskInfo[] tasks = TraceHelper.allowIpcs("getCachedTopTask.true", () ->
+ ActivityManagerWrapper.getInstance().getRunningTasks(true));
+ return new CachedTaskInfo(Arrays.asList(tasks));
+ }
+
+ if (mOrderedTaskList.isEmpty()) {
+ RunningTaskInfo[] tasks = TraceHelper.allowIpcs("getCachedTopTask.false", () ->
+ ActivityManagerWrapper.getInstance().getRunningTasks(
+ false /* filterOnlyVisibleRecents */));
+ Collections.addAll(mOrderedTaskList, tasks);
+ }
+ return new CachedTaskInfo(new ArrayList<>(mOrderedTaskList));
+ }
+
+ /**
+ * Class to provide information about a task which can be safely cached and do not change
+ * during the lifecycle of the task.
+ */
+ public static class CachedTaskInfo {
+
+ private final RunningTaskInfo mTopTask;
+ private final List<RunningTaskInfo> mAllCachedTasks;
+
+ CachedTaskInfo(List<RunningTaskInfo> allCachedTasks) {
+ mAllCachedTasks = allCachedTasks;
+ mTopTask = allCachedTasks.get(0);
+ }
+
+ public int getTaskId() {
+ return mTopTask.taskId;
+ }
+
+ /**
+ * Returns true if the root of the task chooser activity
+ */
+ public boolean isRootChooseActivity() {
+ return ACTION_CHOOSER.equals(mTopTask.baseIntent.getAction());
+ }
+
+ /**
+ * Returns true if the given task holds an Assistant activity that is excluded from recents
+ */
+ public boolean isExcludedAssistant() {
+ return mTopTask.configuration.windowConfiguration
+ .getActivityType() == ACTIVITY_TYPE_ASSISTANT
+ && (mTopTask.baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0;
+ }
+
+ /**
+ * Returns true if this represents the HOME task
+ */
+ public boolean isHomeTask() {
+ return mTopTask.configuration.windowConfiguration
+ .getActivityType() == ACTIVITY_TYPE_HOME;
+ }
+
+ /**
+ * Returns {@link Task} array which can be used as a placeholder until the true object
+ * is loaded by the model
+ */
+ public Task[] getPlaceholderTasks() {
+ return new Task[] {Task.from(new TaskKey(mTopTask), mTopTask, false)};
+ }
+
+ /**
+ * Returns {@link Task} array corresponding to the provided task ids which can be used as a
+ * placeholder until the true object is loaded by the model
+ */
+ public Task[] getPlaceholderTasks(int[] taskIds) {
+ Task[] result = new Task[taskIds.length];
+ for (int i = 0; i < taskIds.length; i++) {
+ final int index = i;
+ int taskId = taskIds[i];
+ mAllCachedTasks.forEach(rti -> {
+ if (rti.taskId == taskId) {
+ result[index] = Task.from(new TaskKey(rti), rti, false);
+ }
+ });
+ }
+ return result;
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 3206825..0078d55 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -15,7 +15,6 @@
*/
package com.android.quickstep;
-import static android.content.Intent.ACTION_CHOOSER;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
@@ -41,7 +40,6 @@
import android.app.PendingIntent;
import android.app.RemoteAction;
import android.app.Service;
-import android.content.ComponentName;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
@@ -95,8 +93,6 @@
import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer;
import com.android.quickstep.inputconsumers.TaskbarStashInputConsumer;
import com.android.quickstep.util.ActiveGestureLog;
-import com.android.quickstep.util.AssistantUtilities;
-import com.android.quickstep.util.LauncherSplitScreenListener;
import com.android.quickstep.util.ProtoTracer;
import com.android.quickstep.util.ProxyScreenStatusProvider;
import com.android.quickstep.util.SplitScreenBounds;
@@ -314,6 +310,13 @@
public void setSwipeUpProxy(Function<GestureState, AnimatedFloat> proxy) {
mSwipeUpProxyProvider = proxy != null ? proxy : (i -> null);
}
+
+ /**
+ * Sets the task id where gestures should be blocked
+ */
+ public void setGestureBlockedTaskId(int taskId) {
+ mDeviceState.setGestureBlockingTaskId(taskId);
+ }
}
private static boolean sConnected = false;
@@ -369,7 +372,6 @@
mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
ProtoTracer.INSTANCE.get(this).add(this);
- LauncherSplitScreenListener.INSTANCE.get(this).init();
sConnected = true;
}
@@ -419,6 +421,9 @@
onSystemUiFlagsChanged(mDeviceState.getSystemUiStateFlags());
onAssistantVisibilityChanged();
+ // Initialize the task tracker
+ TopTaskTracker.INSTANCE.get(this);
+
// Temporarily disable model preload
// new ModelPreload().start(this);
mBackGestureNotificationCounter = Math.max(0, Utilities.getDevicePrefs(this)
@@ -531,7 +536,6 @@
getSystemService(AccessibilityManager.class)
.unregisterSystemAction(SYSTEM_ACTION_ID_ALL_APPS);
- LauncherSplitScreenListener.INSTANCE.get(this).destroy();
mTaskbarManager.destroy();
sConnected = false;
super.onDestroy();
@@ -633,7 +637,7 @@
private InputConsumer tryCreateAssistantInputConsumer(InputConsumer base,
GestureState gestureState, MotionEvent motionEvent) {
- return mDeviceState.isGestureBlockedActivity(gestureState.getRunningTask())
+ return mDeviceState.isGestureBlockedTask(gestureState.getRunningTask())
? base
: new AssistantInputConsumer(this, gestureState, base, mInputMonitorCompat,
mDeviceState, motionEvent);
@@ -648,8 +652,8 @@
gestureState.updatePreviouslyAppearedTaskIds(
previousGestureState.getPreviouslyAppearedTaskIds());
} else {
- gestureState.updateRunningTasks(TraceHelper.allowIpcs("getRunningTask.0",
- () -> mAM.getRunningTasks(false /* filterOnlyVisibleRecents */)));
+ gestureState.updateRunningTask(
+ TopTaskTracker.INSTANCE.get(this).getCachedTopTask(false));
}
return gestureState;
}
@@ -743,17 +747,14 @@
// Use overview input consumer for sharesheets on top of home.
boolean forceOverviewInputConsumer = gestureState.getActivityInterface().isStarted()
&& gestureState.getRunningTask() != null
- && ACTION_CHOOSER.equals(gestureState.getRunningTask().baseIntent.getAction());
- if (AssistantUtilities.isExcludedAssistant(gestureState.getRunningTask())) {
+ && gestureState.getRunningTask().isRootChooseActivity();
+ if (gestureState.getRunningTask() != null
+ && gestureState.getRunningTask().isExcludedAssistant()) {
// In the case where we are in the excluded assistant state, ignore it and treat the
// running activity as the task behind the assistant
- gestureState.updateRunningTask(TraceHelper.allowIpcs("getRunningTask.assistant",
- () -> mAM.getRunningTask(true /* filterOnlyVisibleRecents */)));
- ComponentName homeComponent = mOverviewComponentObserver.getHomeIntent().getComponent();
- ComponentName runningComponent =
- gestureState.getRunningTask().baseIntent.getComponent();
- forceOverviewInputConsumer =
- runningComponent != null && runningComponent.equals(homeComponent);
+ gestureState.updateRunningTask(TopTaskTracker.INSTANCE.get(this)
+ .getCachedTopTask(true /* filterOnlyVisibleRecents */));
+ forceOverviewInputConsumer = gestureState.getRunningTask().isHomeTask();
}
if (ENABLE_QUICKSTEP_LIVE_TILE.get()
@@ -770,7 +771,7 @@
|| forceOverviewInputConsumer) {
return createOverviewInputConsumer(
previousGestureState, gestureState, event, forceOverviewInputConsumer);
- } else if (mDeviceState.isGestureBlockedActivity(gestureState.getRunningTask())) {
+ } else if (mDeviceState.isGestureBlockedTask(gestureState.getRunningTask())) {
return getDefaultInputConsumer();
} else {
return createOtherActivityInputConsumer(gestureState, event);
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index eda2c5a..c9ee2db 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -24,7 +24,6 @@
import android.animation.AnimatorSet;
import android.annotation.TargetApi;
-import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
@@ -50,7 +49,6 @@
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.Task.TaskKey;
import java.util.ArrayList;
@@ -58,7 +56,7 @@
public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsState>
implements StateListener<RecentsState> {
- private RunningTaskInfo mHomeTaskInfo;
+ private Task mHomeTask;
public FallbackRecentsView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -87,12 +85,12 @@
* to the home task. This allows us to handle quick-switch similarly to a quick-switching
* from a foreground task.
*/
- public void onGestureAnimationStartOnHome(RunningTaskInfo[] homeTaskInfo,
+ public void onGestureAnimationStartOnHome(Task[] homeTask,
RotationTouchHelper rotationTouchHelper) {
// TODO(b/195607777) General fallback love, but this might be correct
// Home task should be defined as the front-most task info I think?
- mHomeTaskInfo = homeTaskInfo[0];
- onGestureAnimationStart(homeTaskInfo, rotationTouchHelper);
+ mHomeTask = homeTask[0];
+ onGestureAnimationStart(homeTask, rotationTouchHelper);
}
/**
@@ -105,8 +103,8 @@
@Nullable AnimatorSet animatorSet, GestureState.GestureEndTarget endTarget,
TaskViewSimulator[] taskViewSimulators) {
super.onPrepareGestureEndAnimation(animatorSet, endTarget, taskViewSimulators);
- if (mHomeTaskInfo != null && endTarget == RECENTS && animatorSet != null) {
- TaskView tv = getTaskViewByTaskId(mHomeTaskInfo.taskId);
+ if (mHomeTask != null && endTarget == RECENTS && animatorSet != null) {
+ TaskView tv = getTaskViewByTaskId(mHomeTask.key.id);
if (tv != null) {
PendingAnimation pa = createTaskDismissAnimation(tv, true, false, 150,
false /* dismissingForSplitSelection*/);
@@ -131,8 +129,8 @@
public void setCurrentTask(int runningTaskViewId) {
super.setCurrentTask(runningTaskViewId);
int runningTaskId = getTaskIdsForRunningTaskView()[0];
- if (mHomeTaskInfo != null && mHomeTaskInfo.taskId != runningTaskId) {
- mHomeTaskInfo = null;
+ if (mHomeTask != null && mHomeTask.key.id != runningTaskId) {
+ mHomeTask = null;
setRunningTaskHidden(false);
}
}
@@ -140,26 +138,26 @@
@Nullable
@Override
protected TaskView getHomeTaskView() {
- return mHomeTaskInfo != null ? getTaskViewByTaskId(mHomeTaskInfo.taskId) : null;
+ return mHomeTask != null ? getTaskViewByTaskId(mHomeTask.key.id) : null;
}
@Override
- protected boolean shouldAddStubTaskView(RunningTaskInfo[] runningTaskInfos) {
- if (runningTaskInfos.length > 1) {
+ protected boolean shouldAddStubTaskView(Task[] runningTasks) {
+ if (runningTasks.length > 1) {
// can't be in split screen w/ home task
- return super.shouldAddStubTaskView(runningTaskInfos);
+ return super.shouldAddStubTaskView(runningTasks);
}
- RunningTaskInfo runningTaskInfo = runningTaskInfos[0];
- if (mHomeTaskInfo != null && runningTaskInfo != null &&
- mHomeTaskInfo.taskId == runningTaskInfo.taskId
+ Task runningTask = runningTasks[0];
+ if (mHomeTask != null && runningTask != null
+ && mHomeTask.key.id == runningTask.key.id
&& getTaskViewCount() == 0 && mLoadPlanEverApplied) {
// Do not add a stub task if we are running over home with empty recents, so that we
// show the empty recents message instead of showing a stub task and later removing it.
// Ignore empty task signal if applyLoadPlan has never run.
return false;
}
- return super.shouldAddStubTaskView(runningTaskInfos);
+ return super.shouldAddStubTaskView(runningTasks);
}
@Override
@@ -169,7 +167,7 @@
// track the index of the next task appropriately, as if we are switching on any other app.
// TODO(b/195607777) Confirm home task info is front-most task and not mixed in with others
int runningTaskId = getTaskIdsForRunningTaskView()[0];
- if (mHomeTaskInfo != null && mHomeTaskInfo.taskId == runningTaskId
+ if (mHomeTask != null && mHomeTask.key.id == runningTaskId
&& !taskGroups.isEmpty()) {
// Check if the task list has running task
boolean found = false;
@@ -182,9 +180,7 @@
if (!found) {
ArrayList<GroupTask> newList = new ArrayList<>(taskGroups.size() + 1);
newList.addAll(taskGroups);
- newList.add(new GroupTask(
- Task.from(new TaskKey(mHomeTaskInfo), mHomeTaskInfo, false),
- null, null));
+ newList.add(new GroupTask(mHomeTask, null, null));
taskGroups = newList;
}
}
@@ -193,7 +189,7 @@
@Override
public void setRunningTaskHidden(boolean isHidden) {
- if (mHomeTaskInfo != null) {
+ if (mHomeTask != null) {
// Always keep the home task hidden
isHidden = true;
}
@@ -268,4 +264,9 @@
super.initiateSplitSelect(splitSelectSource);
mActivity.getStateManager().goToState(OVERVIEW_SPLIT_SELECT);
}
+
+ @Override
+ protected boolean canLaunchFullscreenTask() {
+ return !mActivity.isInState(OVERVIEW_SPLIT_SELECT);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index dd459f5..11f0ff3 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -84,6 +84,9 @@
public static final float QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON = 9;
public static final float QUICKSTEP_TOUCH_SLOP_RATIO_GESTURAL = 2;
+ // Minimum angle of a gesture's coordinate where a release goes to overview.
+ public static final int OVERVIEW_MIN_DEGREES = 15;
+
private final RecentsAnimationDeviceState mDeviceState;
private final NavBarPosition mNavBarPosition;
private final TaskAnimationManager mTaskAnimationManager;
@@ -291,8 +294,9 @@
// the gesture (in which case mPassedPilferInputSlop starts as true).
boolean haveNotPassedSlopOnContinuedGesture =
!mPassedSlopOnThisGesture && mPassedPilferInputSlop;
+ double degrees = Math.toDegrees(Math.atan(upDist / horizontalDist));
boolean isLikelyToStartNewTask = haveNotPassedSlopOnContinuedGesture
- || horizontalDist > upDist;
+ || degrees <= OVERVIEW_MIN_DEGREES;
if (!mPassedPilferInputSlop) {
if (passedSlop) {
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index 5ef9a9b..db19c45 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -21,7 +21,6 @@
import android.animation.Animator;
import android.app.Activity;
-import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
@@ -224,8 +223,7 @@
if (!state.getHomeIntent().getComponent().getPackageName().equals(getPackageName())) {
return null;
}
- RunningTaskInfo rti = state.getRunningTask();
- if (rti == null || !rti.topActivity.equals(getComponentName())) {
+ if (state.getRunningTaskId() != getTaskId()) {
return null;
}
mSwipeProgress.updateValue(0);
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index b686505..9ba5577 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -117,7 +117,22 @@
mTutorialFragment.closeTutorial();
}
} else if (mTutorialType == BACK_NAVIGATION) {
- showFeedback(R.string.back_gesture_feedback_swipe_in_nav_bar);
+ switch (result) {
+ case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
+ case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE:
+ case HOME_OR_OVERVIEW_CANCELLED:
+ showFeedback(R.string.back_gesture_feedback_swipe_too_far_from_edge);
+ break;
+ case HOME_GESTURE_COMPLETED:
+ case OVERVIEW_GESTURE_COMPLETED:
+ case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
+ case ASSISTANT_COMPLETED:
+ case ASSISTANT_NOT_STARTED_BAD_ANGLE:
+ case ASSISTANT_NOT_STARTED_SWIPE_TOO_SHORT:
+ default:
+ showFeedback(R.string.back_gesture_feedback_swipe_in_nav_bar);
+
+ }
}
}
}
diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
index 7daac81..bf7023c 100644
--- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
@@ -31,9 +31,11 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.logging.StatsLogManager;
+import com.android.quickstep.TouchInteractionService.TISBinder;
import com.android.quickstep.interaction.TutorialController.TutorialType;
+import com.android.quickstep.util.TISBindHelper;
-import java.util.List;
+import java.util.Arrays;
/** Shows the gesture interactive sandbox in full screen mode. */
public class GestureSandboxActivity extends FragmentActivity {
@@ -52,6 +54,9 @@
private SharedPreferences mSharedPrefs;
private StatsLogManager mStatsLogManager;
+ private TISBindHelper mTISBindHelper;
+ private TISBinder mBinder;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -69,6 +74,8 @@
getSupportFragmentManager().beginTransaction()
.add(R.id.gesture_tutorial_fragment_container, mFragment)
.commit();
+
+ mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
}
@Override
@@ -206,7 +213,37 @@
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
getWindow().setSystemGestureExclusionRects(
- List.of(new Rect(0, 0, metrics.widthPixels, metrics.heightPixels)));
+ Arrays.asList(new Rect(0, 0, metrics.widthPixels, metrics.heightPixels)));
}
}
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ updateServiceState(true);
+ }
+
+ private void onTISConnected(TISBinder binder) {
+ mBinder = binder;
+ updateServiceState(isResumed());
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ updateServiceState(false);
+ }
+
+ private void updateServiceState(boolean isEnabled) {
+ if (mBinder != null) {
+ mBinder.setGestureBlockedTaskId(isEnabled ? getTaskId() : -1);
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mTISBindHelper.onDestroy();
+ updateServiceState(false);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index 13007ea..10c56c9 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -20,6 +20,7 @@
import static androidx.core.util.Preconditions.checkState;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_NON_ACTIONABLE;
+import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.ALL_APPS_CONTAINER;
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.EXTENDED_CONTAINERS;
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.FOLDER;
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.SEARCH_RESULT_CONTAINER;
@@ -92,6 +93,7 @@
private static final int FOLDER_HIERARCHY_OFFSET = 100;
private static final int SEARCH_RESULT_HIERARCHY_OFFSET = 200;
private static final int EXTENDED_CONTAINERS_HIERARCHY_OFFSET = 300;
+ private static final int ALL_APPS_HIERARCHY_OFFSET = 400;
/**
* Flags for converting SearchAttribute to integer value.
@@ -632,6 +634,9 @@
} else if (info.getContainerInfo().getContainerCase() == EXTENDED_CONTAINERS) {
return info.getContainerInfo().getExtendedContainers().getContainerCase().getNumber()
+ EXTENDED_CONTAINERS_HIERARCHY_OFFSET;
+ } else if (info.getContainerInfo().getContainerCase() == ALL_APPS_CONTAINER) {
+ return info.getContainerInfo().getAllAppsContainer().getParentContainerCase()
+ .getNumber() + ALL_APPS_HIERARCHY_OFFSET;
} else {
return info.getContainerInfo().getContainerCase().getNumber();
}
diff --git a/quickstep/src/com/android/quickstep/util/AssistantUtilities.java b/quickstep/src/com/android/quickstep/util/AssistantUtilities.java
deleted file mode 100644
index 336f7d1..0000000
--- a/quickstep/src/com/android/quickstep/util/AssistantUtilities.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2019 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.quickstep.util;
-
-import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT;
-
-import android.annotation.TargetApi;
-import android.app.TaskInfo;
-import android.content.Intent;
-import android.os.Build;
-
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-
-/**
- * Utility class for interacting with the Assistant.
- */
-@TargetApi(Build.VERSION_CODES.Q)
-public final class AssistantUtilities {
-
- /** Returns true if an Assistant activity that is excluded from recents is running. */
- public static boolean isExcludedAssistantRunning() {
- return isExcludedAssistant(ActivityManagerWrapper.getInstance().getRunningTask());
- }
-
- /** Returns true if the given task holds an Assistant activity that is excluded from recents. */
- public static boolean isExcludedAssistant(TaskInfo info) {
- return info != null
- && info.configuration.windowConfiguration.getActivityType() == ACTIVITY_TYPE_ASSISTANT
- && (info.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0;
- }
-
- private AssistantUtilities() {}
-}
diff --git a/quickstep/src/com/android/quickstep/util/LauncherSplitScreenListener.java b/quickstep/src/com/android/quickstep/util/LauncherSplitScreenListener.java
deleted file mode 100644
index affe625..0000000
--- a/quickstep/src/com/android/quickstep/util/LauncherSplitScreenListener.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package com.android.quickstep.util;
-
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
-
-import android.content.Context;
-import android.os.IBinder;
-
-import com.android.launcher3.util.MainThreadInitializedObject;
-import com.android.launcher3.util.SplitConfigurationOptions;
-import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
-import com.android.launcher3.util.SplitConfigurationOptions.StageType;
-import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitTaskPosition;
-import com.android.quickstep.SystemUiProxy;
-import com.android.wm.shell.splitscreen.ISplitScreenListener;
-
-/**
- * Listeners for system wide split screen position and stage changes.
- *
- * Use {@link #getRunningSplitTaskIds()} to determine which tasks, if any, are actively in
- * staged split.
- */
-public class LauncherSplitScreenListener extends ISplitScreenListener.Stub {
-
- public static final MainThreadInitializedObject<LauncherSplitScreenListener> INSTANCE =
- new MainThreadInitializedObject<>(LauncherSplitScreenListener::new);
-
- private static final int[] EMPTY_ARRAY = {};
-
- private final StagedSplitTaskPosition mMainStagePosition = new StagedSplitTaskPosition();
- private final StagedSplitTaskPosition mSideStagePosition = new StagedSplitTaskPosition();
-
- /**
- * Gets set to current split taskIDs whenever the task list is frozen, and set to empty array
- * whenever task list unfreezes. This also gets set to empty array whenever the user swipes to
- * home - in that case the task list does not unfreeze immediately after the gesture, so it's
- * done via {@link #notifySwipingToHome()}.
- *
- * When not empty, this indicates that we need to load a GroupedTaskView as the most recent
- * page, so user can quickswitch back to a grouped task.
- */
- private int[] mPersistentGroupedIds;
-
- public LauncherSplitScreenListener(Context context) {
- mMainStagePosition.stageType = SplitConfigurationOptions.STAGE_TYPE_MAIN;
- mSideStagePosition.stageType = SplitConfigurationOptions.STAGE_TYPE_SIDE;
- }
-
- /** Also call {@link #destroy()} when done. */
- public void init() {
- SystemUiProxy.INSTANCE.getNoCreate().registerSplitScreenListener(this);
- }
-
- public void destroy() {
- SystemUiProxy.INSTANCE.getNoCreate().unregisterSplitScreenListener(this);
- }
-
- /**
- * @return index 0 will be task in left/top position, index 1 in right/bottom position.
- * Will return empty array if device is not in staged split
- */
- public int[] getRunningSplitTaskIds() {
- if (mMainStagePosition.taskId == -1 || mSideStagePosition.taskId == -1) {
- return new int[]{};
- }
- int[] out = new int[2];
- if (mMainStagePosition.stagePosition == STAGE_POSITION_TOP_OR_LEFT) {
- out[0] = mMainStagePosition.taskId;
- out[1] = mSideStagePosition.taskId;
- } else {
- out[1] = mMainStagePosition.taskId;
- out[0] = mSideStagePosition.taskId;
- }
- return out;
- }
-
- @Override
- public void onStagePositionChanged(@StageType int stage, @StagePosition int position) {
- if (stage == SplitConfigurationOptions.STAGE_TYPE_MAIN) {
- mMainStagePosition.stagePosition = position;
- } else {
- mSideStagePosition.stagePosition = position;
- }
- }
-
- @Override
- public void onTaskStageChanged(int taskId, @StageType int stage, boolean visible) {
- // If task is not visible but we are tracking it, stop tracking it
- if (!visible) {
- if (mMainStagePosition.taskId == taskId) {
- resetTaskId(mMainStagePosition);
- } else if (mSideStagePosition.taskId == taskId) {
- resetTaskId(mSideStagePosition);
- } // else it's an un-tracked child
- return;
- }
-
- // If stage has moved to undefined, stop tracking the task
- if (stage == SplitConfigurationOptions.STAGE_TYPE_UNDEFINED) {
- resetTaskId(taskId == mMainStagePosition.taskId ?
- mMainStagePosition : mSideStagePosition);
- return;
- }
-
- if (stage == SplitConfigurationOptions.STAGE_TYPE_MAIN) {
- mMainStagePosition.taskId = taskId;
- } else {
- mSideStagePosition.taskId = taskId;
- }
- }
-
- private void resetTaskId(StagedSplitTaskPosition taskPosition) {
- taskPosition.taskId = -1;
- }
-
- @Override
- public IBinder asBinder() {
- return this;
- }
-}
diff --git a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
index 6f171f9..97be437 100644
--- a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
+++ b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
@@ -45,7 +45,7 @@
// Percentage of the width of the quick search bar that will be reduced
// from the both sides of the bar when progress is 0
private static final float MAX_WIDTH_INSET_FRACTION = 0.15f;
- private static final FloatProperty<Workspace> WORKSPACE_SCALE_PROPERTY =
+ private static final FloatProperty<Workspace<?>> WORKSPACE_SCALE_PROPERTY =
WORKSPACE_SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_UNFOLD_ANIMATION);
private static final FloatProperty<Hotseat> HOTSEAT_SCALE_PROPERTY =
HOTSEAT_SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_UNFOLD_ANIMATION);
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index 1631be0..6038a22 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -307,6 +307,7 @@
private void initMultipleOrientationListeners() {
mSharedPrefs.registerOnSharedPreferenceChangeListener(this);
mSettingsCache.register(ROTATION_SETTING_URI, mRotationChangeListener);
+ updateAutoRotateSetting();
}
private void destroyMultipleOrientationListeners() {
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index ee69fc3..2502359 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -73,6 +73,7 @@
private Intent mInitialTaskIntent;
private int mInitialTaskId = INVALID_TASK_ID;
private int mSecondTaskId = INVALID_TASK_ID;
+ private String mSecondTaskPackageName;
private boolean mRecentsAnimationRunning;
/** If not null, this is the TaskView we want to launch from */
@Nullable
@@ -103,15 +104,15 @@
}
/**
- * To be called after second task selected
+ * To be called when the actual tasks ({@link #mInitialTaskId}, {@link #mSecondTaskId}) are
+ * to be launched. Call after launcher side animations are complete.
*/
- public void setSecondTask(Task task, Consumer<Boolean> callback) {
- mSecondTaskId = task.key.id;
+ public void launchSplitTasks(Consumer<Boolean> callback) {
final Intent fillInIntent;
if (mInitialTaskIntent != null) {
fillInIntent = new Intent();
if (TextUtils.equals(mInitialTaskIntent.getComponent().getPackageName(),
- task.getTopComponent().getPackageName())) {
+ mSecondTaskPackageName)) {
fillInIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
}
} else {
@@ -124,6 +125,18 @@
callback, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO);
}
+
+ /**
+ * To be called as soon as user selects the second task (even if animations aren't complete)
+ * @param task The second task that will be launched.
+ */
+ public void setSecondTask(Task task) {
+ mSecondTaskId = task.key.id;
+ if (mInitialTaskIntent != null) {
+ mSecondTaskPackageName = task.getTopComponent().getPackageName();
+ }
+ }
+
/**
* To be called when we want to launch split pairs from an existing GroupedTaskView.
*/
@@ -303,7 +316,18 @@
* chosen
*/
public boolean isSplitSelectActive() {
- return (mInitialTaskId != INVALID_TASK_ID || mInitialTaskIntent != null)
- && mSecondTaskId == INVALID_TASK_ID;
+ return isInitialTaskIntentSet() && mSecondTaskId == INVALID_TASK_ID;
+ }
+
+ /**
+ * @return {@code true} if the first and second task have been chosen and split is waiting to
+ * be launched
+ */
+ public boolean isBothSplitAppsConfirmed() {
+ return isInitialTaskIntentSet() && mSecondTaskId != INVALID_TASK_ID;
+ }
+
+ private boolean isInitialTaskIntentSet() {
+ return (mInitialTaskId != INVALID_TASK_ID || mInitialTaskIntent != null);
}
}
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 44396fa..b1e2eac 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -92,7 +92,7 @@
if (staggerWorkspace) {
DeviceProfile grid = launcher.getDeviceProfile();
- Workspace workspace = launcher.getWorkspace();
+ Workspace<?> workspace = launcher.getWorkspace();
Hotseat hotseat = launcher.getHotseat();
// Hotseat and QSB takes up two additional rows.
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 70fde1d..b222f51 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -56,6 +56,7 @@
private final int mTaskId;
private final ComponentName mComponentName;
private final SurfaceControl mLeash;
+ private final Rect mSourceRectHint = new Rect();
private final Rect mAppBounds = new Rect();
private final Matrix mHomeToWindowPositionMap = new Matrix();
private final Rect mStartBounds = new Rect();
@@ -140,6 +141,7 @@
}
if (sourceRectHint == null) {
+ mSourceRectHint.setEmpty();
mSourceHintRectInsets = null;
// Create a new overlay layer
@@ -169,6 +171,7 @@
t.apply();
});
} else {
+ mSourceRectHint.set(sourceRectHint);
mSourceHintRectInsets = new Rect(sourceRectHint.left - appBounds.left,
sourceRectHint.top - appBounds.top,
appBounds.right - sourceRectHint.right,
@@ -249,7 +252,8 @@
return mSurfaceTransactionHelper.scaleAndRotate(tx, mLeash, mAppBounds, bounds, insets,
rotatedPosition.degree, rotatedPosition.positionX, rotatedPosition.positionY);
} else {
- return mSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mAppBounds, bounds, insets);
+ return mSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mSourceRectHint, mAppBounds,
+ bounds, insets);
}
}
diff --git a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
index 3d72398..354d157 100644
--- a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
@@ -37,7 +37,7 @@
@Override
protected void onPrepareViewsForAnimation() {
- Workspace workspace = mLauncher.getWorkspace();
+ Workspace<?> workspace = mLauncher.getWorkspace();
// App icons and widgets
workspace
diff --git a/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java b/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java
index 5326d2b..5eb543e 100644
--- a/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java
+++ b/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java
@@ -53,7 +53,7 @@
// Should be used for animations running alongside this WorkspaceRevealAnim.
public static final int DURATION_MS = 350;
- private static final FloatProperty<Workspace> WORKSPACE_SCALE_PROPERTY =
+ private static final FloatProperty<Workspace<?>> WORKSPACE_SCALE_PROPERTY =
WORKSPACE_SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_REVEAL_ANIM);
private static final FloatProperty<Hotseat> HOTSEAT_SCALE_PROPERTY =
@@ -68,7 +68,7 @@
ResourceProvider rp = DynamicResource.provider(launcher);
mScaleStart = rp.getFloat(R.dimen.swipe_up_scale_start);
- Workspace workspace = launcher.getWorkspace();
+ Workspace<?> workspace = launcher.getWorkspace();
workspace.setPivotToScaleWithSelf(launcher.getHotseat());
// Add reveal animations.
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index 332cbeb..50be5ea 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -141,7 +141,10 @@
}
applyPrimaryTranslation();
applySecondaryTranslation();
- mScrollAlpha = 1 - shift / orientationSize;
+ float clearAllSpacing =
+ recentsView.getPageSpacing() + recentsView.getClearAllExtraPageSpacing();
+ clearAllSpacing = mIsRtl ? -clearAllSpacing : clearAllSpacing;
+ mScrollAlpha = Math.max((clearAllScroll + clearAllSpacing - scroll) / clearAllSpacing, 0);
updateAlpha();
}
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 955fffc..244a794 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -26,6 +26,7 @@
import com.android.quickstep.util.RecentsOrientedState;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import java.util.HashMap;
import java.util.function.Consumer;
@@ -171,8 +172,14 @@
RunnableList endCallback = new RunnableList();
RecentsView recentsView = getRecentsView();
// Callbacks run from remote animation when recents animation not currently running
+ InteractionJankMonitorWrapper.begin(this,
+ InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER, "Enter form GroupedTaskView");
recentsView.getSplitPlaceholder().launchTasks(this /*groupedTaskView*/,
- success -> endCallback.executeAllAndDestroy(),
+ success -> {
+ endCallback.executeAllAndDestroy();
+ InteractionJankMonitorWrapper.end(
+ InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
+ },
false /* freezeTaskList */);
// Callbacks get run from recentsView for case when recents animation already running
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 8d717d2..45aaf35 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -181,4 +181,9 @@
super.initiateSplitSelect(splitSelectSource);
mActivity.getStateManager().goToState(LauncherState.OVERVIEW_SPLIT_SELECT);
}
+
+ @Override
+ protected boolean canLaunchFullscreenTask() {
+ return !mActivity.isInState(OVERVIEW_SPLIT_SELECT);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 6b15807..99a2d6f 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -155,7 +155,7 @@
public void setInsets(Rect insets) {
mInsets.set(insets);
updateVerticalMargin(DisplayController.getNavigationMode(getContext()));
- updatePaddingAndTranslations();
+ updatePadding();
}
public void updateHiddenFlags(@ActionsHiddenFlags int visibilityFlags, boolean enable) {
@@ -199,10 +199,9 @@
}
/**
- * Aligns OverviewActionsView vertically with and offsets horizontal position based on
- * 3 button nav container in taskbar.
+ * Offsets OverviewActionsView horizontal position based on 3 button nav container in taskbar.
*/
- private void updatePaddingAndTranslations() {
+ private void updatePadding() {
boolean alignFor3ButtonTaskbar = mDp.isTaskbarPresent &&
DisplayController.getNavigationMode(getContext()) == THREE_BUTTONS;
if (alignFor3ButtonTaskbar) {
@@ -213,20 +212,8 @@
} else {
setPadding(mInsets.left, 0, mInsets.right + additionalPadding, 0);
}
-
- // Align vertically, using taskbar height + mDp.taskbarOffsetY() to estimate where
- // the button nav top is.
- int marginBottom = getOverviewActionsBottomMarginPx(
- DisplayController.getNavigationMode(getContext()), mDp);
- int actionsTop =
- (mDp.heightPx - marginBottom - mInsets.bottom) - mDp.overviewActionsHeight;
- int navTop = mDp.heightPx - (mDp.taskbarSize + mDp.getTaskbarOffsetY());
- int transY = navTop - actionsTop + ((mDp.taskbarSize - mDp.overviewActionsHeight) / 2);
- setTranslationY(transY);
} else {
setPadding(mInsets.left, 0, mInsets.right, 0);
- setTranslationX(0);
- setTranslationY(0);
}
}
@@ -287,19 +274,28 @@
/** Get the bottom margin associated with the action buttons in Overview. */
public static int getOverviewActionsBottomMarginPx(NavigationMode mode, DeviceProfile dp) {
- int inset = dp.getInsets().bottom;
+ int bottomInset = dp.getInsets().bottom;
if (dp.isVerticalBarLayout()) {
- return inset;
+ return bottomInset;
}
- // Actions button will be aligned with nav buttons in updatePaddingAndTranslations().
if (mode == NavigationMode.THREE_BUTTONS) {
- return dp.overviewActionsMarginThreeButtonPx + inset;
+ int bottomMargin = dp.overviewActionsMarginThreeButtonPx + bottomInset;
+ if (dp.isTaskbarPresent) {
+ // Align vertically, using taskbar height + mDp.taskbarOffsetY() to estimate where
+ // the button nav top is.
+ int actionsTop = (dp.heightPx - bottomMargin - bottomInset)
+ - dp.overviewActionsHeight;
+ int navTop = dp.heightPx - (dp.taskbarSize + dp.getTaskbarOffsetY());
+ bottomMargin -=
+ navTop - actionsTop + ((dp.taskbarSize - dp.overviewActionsHeight) / 2);
+ }
+ return bottomMargin;
}
// There is no bottom inset when taskbar is present, use stashed taskbar as padding instead.
return dp.overviewActionsBottomMarginGesturePx
- + (dp.isTaskbarPresent ? dp.stashedTaskbarSize : inset);
+ + (dp.isTaskbarPresent ? dp.stashedTaskbarSize : bottomInset);
}
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index e64e439..49bf827 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -64,8 +64,8 @@
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
+import android.annotation.SuppressLint;
import android.annotation.TargetApi;
-import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.content.LocusId;
import android.content.res.Configuration;
@@ -106,6 +106,7 @@
import android.widget.ListView;
import android.widget.OverScroller;
import android.widget.Toast;
+import android.window.PictureInPictureSurfaceTransaction;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -159,6 +160,7 @@
import com.android.quickstep.TaskOverlayFactory;
import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.TaskViewUtils;
+import com.android.quickstep.TopTaskTracker;
import com.android.quickstep.ViewUtils;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.LayoutUtils;
@@ -171,9 +173,9 @@
import com.android.quickstep.util.VibratorWrapper;
import com.android.systemui.plugins.ResourceProvider;
import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.Task.TaskKey;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
@@ -383,7 +385,7 @@
private static final float ANIMATION_DISMISS_PROGRESS_MIDPOINT = 0.5f;
private static final float END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET = 0.75f;
- private static final float SIGNIFICANT_MOVE_THRESHOLD_TABLET = 0.15f;
+ private static final float SIGNIFICANT_MOVE_SCREEN_WIDTH_PERCENTAGE = 0.15f;
protected final RecentsOrientedState mOrientationState;
protected final BaseActivityInterface<STATE_TYPE, ACTIVITY_TYPE> mSizeStrategy;
@@ -878,6 +880,14 @@
return mSplitSelectStateController.isSplitSelectActive();
}
+ /**
+ * See overridden implementations
+ * @return {@code true} if child TaskViews can be launched when user taps on them
+ */
+ protected boolean canLaunchFullscreenTask() {
+ return true;
+ }
+
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
@@ -1195,9 +1205,14 @@
}
@Override
- protected float getSignificantMoveThreshold() {
- return mActivity.getDeviceProfile().isTablet ? SIGNIFICANT_MOVE_THRESHOLD_TABLET
- : super.getSignificantMoveThreshold();
+ protected boolean isSignificantMove(float absoluteDelta, int pageOrientedSize) {
+ DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+ if (!deviceProfile.isTablet) {
+ return super.isSignificantMove(absoluteDelta, pageOrientedSize);
+ }
+
+ return absoluteDelta
+ > deviceProfile.availableWidthPx * SIGNIFICANT_MOVE_SCREEN_WIDTH_PERCENTAGE;
}
@Override
@@ -1289,10 +1304,11 @@
return;
}
TaskView taskView = getTaskViewAt(mNextPage);
- // Only snap to fully visible focused task.
- if (taskView == null
- || !taskView.isFocusedTask()
- || !isTaskViewFullyVisible(taskView)) {
+ // Snap to fully visible focused task and clear all button.
+ boolean shouldSnapToFocusedTask = taskView != null && taskView.isFocusedTask()
+ && isTaskViewFullyVisible(taskView);
+ boolean shouldSnapToClearAll = mNextPage == indexOfChild(mClearAllButton);
+ if (!shouldSnapToFocusedTask && !shouldSnapToClearAll) {
return;
}
}
@@ -1380,6 +1396,9 @@
if (taskGroups == null || taskGroups.isEmpty()) {
removeTasksViewsAndClearAllButton();
onTaskStackUpdated();
+ // With all tasks removed, touch handling in PagedView is disabled and we need to reset
+ // touch state or otherwise values will be obsolete.
+ resetTouchState();
return;
}
@@ -2066,8 +2085,8 @@
/**
* Called when a gesture from an app is starting.
*/
- public void onGestureAnimationStart(RunningTaskInfo[] runningTaskInfo,
- RotationTouchHelper rotationTouchHelper) {
+ public void onGestureAnimationStart(
+ Task[] runningTasks, RotationTouchHelper rotationTouchHelper) {
mGestureActive = true;
// This needs to be called before the other states are set since it can create the task view
if (mOrientationState.setGestureActive(true)) {
@@ -2078,7 +2097,7 @@
updateSizeAndPadding();
}
- showCurrentTask(runningTaskInfo);
+ showCurrentTask(runningTasks);
setEnableFreeScroll(false);
setEnableDrawingLiveTile(false);
setRunningTaskHidden(true);
@@ -2194,10 +2213,10 @@
/**
* Returns true if we should add a stub taskView for the running task id
*/
- protected boolean shouldAddStubTaskView(RunningTaskInfo[] runningTaskInfos) {
- if (runningTaskInfos.length > 1) {
- TaskView primaryTaskView = getTaskViewByTaskId(runningTaskInfos[0].taskId);
- TaskView secondaryTaskView = getTaskViewByTaskId(runningTaskInfos[1].taskId);
+ protected boolean shouldAddStubTaskView(Task[] runningTasks) {
+ if (runningTasks.length > 1) {
+ TaskView primaryTaskView = getTaskViewByTaskId(runningTasks[0].key.id);
+ TaskView secondaryTaskView = getTaskViewByTaskId(runningTasks[1].key.id);
int leftTopTaskViewId =
(primaryTaskView == null) ? -1 : primaryTaskView.getTaskViewId();
int rightBottomTaskViewId =
@@ -2205,8 +2224,8 @@
// Add a new stub view if both taskIds don't match any taskViews
return leftTopTaskViewId != rightBottomTaskViewId || leftTopTaskViewId == -1;
}
- RunningTaskInfo runningTaskInfo = runningTaskInfos[0];
- return runningTaskInfo != null && getTaskViewByTaskId(runningTaskInfo.taskId) == null;
+ Task runningTaskInfo = runningTasks[0];
+ return runningTaskInfo != null && getTaskViewByTaskId(runningTaskInfo.key.id) == null;
}
/**
@@ -2215,21 +2234,16 @@
* All subsequent calls to reload will keep the task as the first item until {@link #reset()}
* is called. Also scrolls the view to this task.
*/
- private void showCurrentTask(RunningTaskInfo[] runningTaskInfo) {
+ private void showCurrentTask(Task[] runningTasks) {
int runningTaskViewId = -1;
- boolean needGroupTaskView = runningTaskInfo.length > 1;
- RunningTaskInfo taskInfo = runningTaskInfo[0];
- if (shouldAddStubTaskView(runningTaskInfo)) {
+ boolean needGroupTaskView = runningTasks.length > 1;
+ if (shouldAddStubTaskView(runningTasks)) {
boolean wasEmpty = getChildCount() == 0;
// Add an empty view for now until the task plan is loaded and applied
final TaskView taskView;
if (needGroupTaskView) {
taskView = getTaskViewFromPool(true);
- RunningTaskInfo secondaryTaskInfo = runningTaskInfo[1];
- mTmpRunningTasks = new Task[]{
- Task.from(new TaskKey(taskInfo), taskInfo, false),
- Task.from(new TaskKey(secondaryTaskInfo), secondaryTaskInfo, false)
- };
+ mTmpRunningTasks = new Task[]{runningTasks[0], runningTasks[1]};
addView(taskView, 0);
// When we create a placeholder task view mSplitBoundsConfig will be null, but with
// the actual app running we won't need to show the thumbnail until all the tasks
@@ -2241,7 +2255,7 @@
addView(taskView, 0);
// The temporary running task is only used for the duration between the start of the
// gesture and the task list is loaded and applied
- mTmpRunningTasks = new Task[]{Task.from(new TaskKey(taskInfo), taskInfo, false)};
+ mTmpRunningTasks = new Task[]{runningTasks[0]};
taskView.bind(mTmpRunningTasks[0], mOrientationState);
}
runningTaskViewId = taskView.getTaskViewId();
@@ -2254,8 +2268,8 @@
measure(makeMeasureSpec(getMeasuredWidth(), EXACTLY),
makeMeasureSpec(getMeasuredHeight(), EXACTLY));
layout(getLeft(), getTop(), getRight(), getBottom());
- } else if (getTaskViewByTaskId(taskInfo.taskId) != null) {
- runningTaskViewId = getTaskViewByTaskId(taskInfo.taskId).getTaskViewId();
+ } else if (getTaskViewByTaskId(runningTasks[0].key.id) != null) {
+ runningTaskViewId = getTaskViewByTaskId(runningTasks[0].key.id).getTaskViewId();
}
boolean runningTaskTileHidden = mRunningTaskTileHidden;
@@ -2734,9 +2748,16 @@
mFirstFloatingTaskView.addAnimation(anim, startingTaskRect,
mTempRect, true /* fadeWithThumbnail */, true /* isStagedTask */);
}
+ InteractionJankMonitorWrapper.begin(this,
+ InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER, "First tile selected");
anim.addEndListener(success -> {
if (success) {
mSplitToast.show();
+ InteractionJankMonitorWrapper.end(
+ InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
+ } else {
+ InteractionJankMonitorWrapper.cancel(
+ InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
}
});
}
@@ -3985,15 +4006,25 @@
/**
* Confirms the selection of the next split task. The extra data is passed through because the
* user may be selecting a subtask in a group.
+ *
+ * @return true if waiting for confirmation of second app or if split animations are running,
+ * false otherwise
*/
- public void confirmSplitSelect(TaskView containerTaskView, Task task, IconView iconView,
+ public boolean confirmSplitSelect(TaskView containerTaskView, Task task, IconView iconView,
TaskThumbnailView thumbnailView) {
+ if (canLaunchFullscreenTask()) {
+ return false;
+ }
+ if (mSplitSelectStateController.isBothSplitAppsConfirmed()) {
+ return true;
+ }
mSplitToast.cancel();
if (!task.isDockable) {
// Task not split screen supported
mSplitUnsupportedToast.show();
- return;
+ return true;
}
+ mSplitSelectStateController.setSecondTask(task);
RectF secondTaskStartingBounds = new RectF();
Rect secondTaskEndingBounds = new Rect();
// TODO(194414938) starting bounds seem slightly off, investigate
@@ -4020,9 +4051,11 @@
mSecondFloatingTaskView.setAlpha(1);
mSecondFloatingTaskView.addAnimation(pendingAnimation, secondTaskStartingBounds,
secondTaskEndingBounds, true /* fadeWithThumbnail */, false /* isStagedTask */);
- pendingAnimation.addEndListener(aBoolean ->
- mSplitSelectStateController.setSecondTask(
- task, aBoolean1 -> RecentsView.this.resetFromSplitSelectionState()));
+ pendingAnimation.addEndListener(aBoolean -> {
+ mSplitSelectStateController.launchSplitTasks(
+ aBoolean1 -> RecentsView.this.resetFromSplitSelectionState());
+ InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
+ });
if (containerTaskView.containsMultipleTasks()) {
// If we are launching from a child task, then only hide the thumbnail itself
mSecondSplitHiddenView = thumbnailView;
@@ -4030,10 +4063,14 @@
mSecondSplitHiddenView = containerTaskView;
}
mSecondSplitHiddenView.setVisibility(INVISIBLE);
+ InteractionJankMonitorWrapper.begin(this,
+ InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER, "Second tile selected");
pendingAnimation.buildAnim().start();
+ return true;
}
/** TODO(b/181707736) More gracefully handle exiting split selection state */
+ @SuppressLint("WrongCall")
protected void resetFromSplitSelectionState() {
if (mSplitSelectSource != null || mSplitHiddenTaskViewIndex != -1) {
if (mFirstFloatingTaskView != null) {
@@ -4408,7 +4445,8 @@
}
RemoteTargetGluer gluer = new RemoteTargetGluer(getContext(), getSizeStrategy());
- mRemoteTargetHandles = gluer.assignTargetsForSplitScreen(recentsAnimationTargets);
+ mRemoteTargetHandles = gluer.assignTargetsForSplitScreen(
+ getContext(), recentsAnimationTargets);
mSplitBoundsConfig = gluer.getStagedSplitBounds();
// Add release check to the targets from the RemoteTargetGluer and not the targets
// passed in because in the event we're in split screen, we use the passed in targets
@@ -4463,10 +4501,7 @@
// Reset the minimized state since we force-toggled the minimized state when entering
// overview, but never actually finished the recents animation. This is a catch all for
// cases where we haven't already reset it.
- SystemUiProxy p = SystemUiProxy.INSTANCE.getNoCreate();
- if (p != null) {
- p.setSplitScreenMinimized(false);
- }
+ SystemUiProxy.INSTANCE.get(getContext()).setSplitScreenMinimized(false);
}
if (mRecentsAnimationController == null) {
@@ -4482,6 +4517,17 @@
final SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.get(getContext());
systemUiProxy.notifySwipeToHomeFinished();
systemUiProxy.setShelfHeight(true, mActivity.getDeviceProfile().hotseatBarSizePx);
+ // Transaction to hide the task to avoid flicker for entering PiP from split-screen.
+ // See also {@link AbsSwipeUpHandler#maybeFinishSwipeToHome}.
+ PictureInPictureSurfaceTransaction tx =
+ new PictureInPictureSurfaceTransaction.Builder()
+ .setAlpha(0f)
+ .build();
+ int[] taskIds = TopTaskTracker.INSTANCE.get(getContext()).getRunningSplitTaskIds();
+ for (int taskId : taskIds) {
+ mRecentsAnimationController.setFinishTaskTransaction(taskId,
+ tx, null /* overlay */);
+ }
}
mRecentsAnimationController.finish(toRecents, () -> {
if (onFinishComplete != null) {
@@ -4519,6 +4565,7 @@
/**
* Updates page scroll synchronously after measure and layout child views.
*/
+ @SuppressLint("WrongCall")
public void updateScrollSynchronously() {
// onMeasure is needed to update child's measured width which is used in scroll calculation,
// in case TaskView sizes has changed when being focused/unfocused.
@@ -4535,7 +4582,7 @@
? getClearAllExtraPageSpacing() : 0;
}
- private int getClearAllExtraPageSpacing() {
+ protected int getClearAllExtraPageSpacing() {
return showAsGrid()
? Math.max(mActivity.getDeviceProfile().overviewGridSideMargin - mPageSpacing, 0)
: 0;
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index ce033e5..8869ff1 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -20,7 +20,6 @@
import static android.widget.Toast.LENGTH_SHORT;
import static com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU;
-import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
import static com.android.launcher3.Utilities.comp;
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
@@ -628,10 +627,7 @@
// Reset the minimized state since we force-toggled the minimized state when entering
// overview, but never actually finished the recents animation
- SystemUiProxy p = SystemUiProxy.INSTANCE.getNoCreate();
- if (p != null) {
- p.setSplitScreenMinimized(false);
- }
+ SystemUiProxy.INSTANCE.get(getContext()).setSplitScreenMinimized(false);
mIsClickableAsLiveTile = false;
RemoteAnimationTargets targets;
@@ -698,14 +694,10 @@
* second app. {@code false} otherwise
*/
private boolean confirmSecondSplitSelectApp() {
- boolean isSelectingSecondSplitApp = getRecentsView().isSplitSelectionActive();
- if (isSelectingSecondSplitApp) {
- int index = getChildTaskIndexAtPosition(mLastTouchDownPosition);
- TaskIdAttributeContainer container = mTaskIdAttributeContainer[index];
- getRecentsView().confirmSplitSelect(this, container.getTask(), container.getIconView(),
- container.getThumbnailView());
- }
- return isSelectingSecondSplitApp;
+ int index = getChildTaskIndexAtPosition(mLastTouchDownPosition);
+ TaskIdAttributeContainer container = mTaskIdAttributeContainer[index];
+ return getRecentsView().confirmSplitSelect(this, container.getTask(),
+ container.getIconView(), container.getThumbnailView());
}
/**
@@ -855,7 +847,7 @@
}
private boolean showTaskMenu(IconView iconView) {
- if (getRecentsView().mActivity.isInState(OVERVIEW_SPLIT_SELECT)) {
+ if (!getRecentsView().canLaunchFullscreenTask()) {
// Don't show menu when selecting second split screen app
return true;
}
diff --git a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
index 3bd3722..5c2e14f 100644
--- a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
+++ b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
@@ -46,7 +46,8 @@
runWithShellPermission(() ->
usageStatsManager.registerAppUsageLimitObserver(observerId, packages,
Duration.ofSeconds(600), Duration.ofSeconds(300),
- PendingIntent.getActivity(mTargetContext, -1, new Intent(), 0)));
+ PendingIntent.getActivity(mTargetContext, -1, new Intent(),
+ PendingIntent.FLAG_MUTABLE)));
mLauncher.goHome();
final DigitalWellBeingToast toast = getToast();
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index ca6712f..f7600ff 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -57,6 +57,7 @@
import com.android.launcher3.testcomponent.TestCommandReceiver;
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.FailureWatcher;
+import com.android.launcher3.util.rule.SamplerRule;
import com.android.launcher3.util.rule.ScreenRecordRule;
import com.android.quickstep.views.RecentsView;
@@ -111,7 +112,8 @@
}
mOrderSensitiveRules = RuleChain
- .outerRule(new NavigationModeSwitchRule(mLauncher))
+ .outerRule(new SamplerRule())
+ .around(new NavigationModeSwitchRule(mLauncher))
.around(new FailureWatcher(mDevice, mLauncher));
mOtherLauncherActivity = context.getPackageManager().queryIntentActivities(
diff --git a/res/anim-v33/shared_x_axis_activity_close_enter.xml b/res/anim-v33/shared_x_axis_activity_close_enter.xml
new file mode 100644
index 0000000..94ef06c
--- /dev/null
+++ b/res/anim-v33/shared_x_axis_activity_close_enter.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false"
+ android:showBackdrop="true">
+
+ <alpha
+ android:fromAlpha="0.0"
+ android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/standard_decelerate"
+ android:startOffset="100"
+ android:duration="350" />
+
+ <translate
+ android:fromXDelta="-25%"
+ android:toXDelta="0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="450" />
+
+</set>
\ No newline at end of file
diff --git a/res/anim-v33/shared_x_axis_activity_close_exit.xml b/res/anim-v33/shared_x_axis_activity_close_exit.xml
new file mode 100644
index 0000000..19eb09e
--- /dev/null
+++ b/res/anim-v33/shared_x_axis_activity_close_exit.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/standard_accelerate"
+ android:startOffset="0"
+ android:duration="100" />
+
+ <translate
+ android:fromXDelta="0"
+ android:toXDelta="25%"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="450" />
+
+</set>
\ No newline at end of file
diff --git a/res/anim-v33/shared_x_axis_activity_open_enter.xml b/res/anim-v33/shared_x_axis_activity_open_enter.xml
new file mode 100644
index 0000000..f699cec
--- /dev/null
+++ b/res/anim-v33/shared_x_axis_activity_open_enter.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false"
+ android:showBackdrop="true">
+
+ <alpha
+ android:fromAlpha="0.0"
+ android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/standard_decelerate"
+ android:startOffset="100"
+ android:duration="350" />
+
+ <translate
+ android:fromXDelta="25%"
+ android:toXDelta="0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="450" />
+
+</set>
\ No newline at end of file
diff --git a/res/anim-v33/shared_x_axis_activity_open_exit.xml b/res/anim-v33/shared_x_axis_activity_open_exit.xml
new file mode 100644
index 0000000..85988ec
--- /dev/null
+++ b/res/anim-v33/shared_x_axis_activity_open_exit.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/standard_accelerate"
+ android:startOffset="0"
+ android:duration="100" />
+
+ <translate
+ android:fromXDelta="0"
+ android:toXDelta="-25%"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="450" />
+
+</set>
\ No newline at end of file
diff --git a/res/drawable/gm_edit_24.xml b/res/drawable/gm_edit_24.xml
index 59a0dc2..f741333 100644
--- a/res/drawable/gm_edit_24.xml
+++ b/res/drawable/gm_edit_24.xml
@@ -5,6 +5,6 @@
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
- android:fillColor="@android:color/white"
+ android:fillColor="?android:attr/textColorPrimaryInverse"
android:pathData="M20.41,4.94l-1.35,-1.35c-0.78,-0.78 -2.05,-0.78 -2.83,0L3,16.82L3,21h4.18L20.41,7.77c0.79,-0.78 0.79,-2.05 0,-2.83zM6.41,19.06L5,19v-1.36l9.82,-9.82 1.41,1.41 -9.82,9.83z"/>
</vector>
diff --git a/res/interpolator/back_cancel.xml b/res/interpolator/back_cancel.xml
new file mode 100644
index 0000000..2165457
--- /dev/null
+++ b/res/interpolator/back_cancel.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2022, 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.
+*/
+-->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0.2"
+ android:controlY1="0"
+ android:controlX2="0"
+ android:controlY2="1"/>
\ No newline at end of file
diff --git a/res/interpolator/fast_out_extra_slow_in.xml b/res/interpolator/fast_out_extra_slow_in.xml
new file mode 100644
index 0000000..f296a82
--- /dev/null
+++ b/res/interpolator/fast_out_extra_slow_in.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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
+ -->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0,0 C 0.05, 0, 0.133333, 0.06, 0.166666, 0.4 C 0.208333, 0.82, 0.25, 1, 1, 1"/>
\ No newline at end of file
diff --git a/res/interpolator/standard_accelerate.xml b/res/interpolator/standard_accelerate.xml
new file mode 100644
index 0000000..394393d
--- /dev/null
+++ b/res/interpolator/standard_accelerate.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0.3"
+ android:controlY1="0"
+ android:controlX2="1"
+ android:controlY2="1"/>
\ No newline at end of file
diff --git a/res/interpolator/standard_decelerate.xml b/res/interpolator/standard_decelerate.xml
new file mode 100644
index 0000000..579f4f5
--- /dev/null
+++ b/res/interpolator/standard_decelerate.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0"
+ android:controlY1="0"
+ android:controlX2="0"
+ android:controlY2="1"/>
\ No newline at end of file
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 2ac7e63..d0d82d4 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -30,6 +30,10 @@
android:visibility="gone" />
<include
+ layout="@layout/search_results_rv_layout"
+ android:visibility="gone" />
+
+ <include
layout="@layout/all_apps_rv_layout"
android:visibility="gone" />
diff --git a/res/layout/search_results_rv_layout.xml b/res/layout/search_results_rv_layout.xml
new file mode 100644
index 0000000..567cb5f
--- /dev/null
+++ b/res/layout/search_results_rv_layout.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+<com.android.launcher3.allapps.SearchRecyclerView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/search_results_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipToPadding="false"
+ android:descendantFocusability="afterDescendants"
+ android:focusable="true" />
diff --git a/res/layout/secondary_launcher.xml b/res/layout/secondary_launcher.xml
index 0fe05ee..635db14 100644
--- a/res/layout/secondary_launcher.xml
+++ b/res/layout/secondary_launcher.xml
@@ -60,6 +60,10 @@
android:visibility="gone" />
<include
+ layout="@layout/search_results_rv_layout"
+ android:visibility="gone" />
+
+ <include
layout="@layout/all_apps_rv_layout"
android:visibility="gone" />
diff --git a/res/layout/widgets_full_sheet.xml b/res/layout/widgets_full_sheet.xml
index e867405..e3f1fca 100644
--- a/res/layout/widgets_full_sheet.xml
+++ b/res/layout/widgets_full_sheet.xml
@@ -38,12 +38,13 @@
android:background="@drawable/bg_rounded_corner_bottom_sheet_handle"/>
<TextView
+ style="@style/PrimaryHeadline"
android:id="@+id/no_widgets_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:visibility="gone"
- android:textSize="20sp"
+ android:textSize="18sp"
android:layout_below="@id/search_and_recommendations_container"
tools:text="No widgets available" />
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 4c63af2..471bcc5 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installeer tans; <xliff:g id="PROGRESS">%2$s</xliff:g> voltooi"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> laai tans af, <xliff:g id="PROGRESS">%2$s</xliff:g> voltooid"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> wag tans om te installeer"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Legstukkelys"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Legstukkelys is toegemaak"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Voeg by tuisskerm"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index e59ad1b..73bbdd1 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> በመጫን ላይ፣ <xliff:g id="PROGRESS">%2$s</xliff:g> ተጠናቅቋል"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> በመውረድ ላይ፣ <xliff:g id="PROGRESS">%2$s</xliff:g> ተጠናቋል"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ለመጫን በመጠበቅ ላይ"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"የመግብሮች ዝርዝር"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"የመግብሮች ዝርዝር ተዘግቷል"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"ወደ መነሻ ማያ ገጽ አክል"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 681fa2f..774977c 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -32,7 +32,7 @@
<string name="split_screen_position_left" msgid="7537793098851830883">"تقسيم لليسار"</string>
<string name="split_screen_position_right" msgid="1569377524925193369">"تقسيم لليمين"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"معلومات تطبيق %1$s"</string>
- <string name="long_press_widget_to_add" msgid="3587712543577675817">"انقر مع الاستمرار لنقل أداة"</string>
+ <string name="long_press_widget_to_add" msgid="3587712543577675817">"انقر مع الاستمرار لنقل أداة."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"انقر مرتين مع تثبيت إصبعك لنقل أداة أو استخدام الإجراءات المخصّصة."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"العرض %1$d الطول %2$d"</string>
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"جارٍ تثبيت <xliff:g id="NAME">%1$s</xliff:g>، مستوى التقدم: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"جارٍ تنزيل <xliff:g id="NAME">%1$s</xliff:g>، اكتمل <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> في انتظار التثبيت"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"قائمة الأدوات"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"تم إغلاق قائمة الأدوات."</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"إضافة تطبيق للشاشة الرئيسية"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 4c21093..cb1581f 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ইনষ্টল কৰি থকা হৈছে, <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পূৰ্ণ হৈছে"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ডাউনল’ড কৰি থকা হৈছে, <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পূৰ্ণ হ’ল"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ইনষ্টল হোৱালৈ অপেক্ষা কৰি থকা হৈছে"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"ৱিজেটৰ তালিকা"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"ৱিজেটৰ তালিকা বন্ধ কৰা হ’ল"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"গৃহ স্ক্ৰীনত যোগ কৰক"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index ec644a1..aa19e28 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> quraşdırır, <xliff:g id="PROGRESS">%2$s</xliff:g> tamamlanıb"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> endirilir, <xliff:g id="PROGRESS">%2$s</xliff:g> tamamlandı"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> yüklənmək üçün gözləyir"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Vidcet siyahısı"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Vidcet siyahısı bağlandı"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Əsas ekrana əlavə edin"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 38c2667..ddcb256 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -47,7 +47,7 @@
<string name="widgets_full_sheet_search_bar_hint" msgid="8484659090860596457">"Pretražite"</string>
<string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"Obrišite tekst iz okvira za pretragu"</string>
<string name="no_widgets_available" msgid="4337693382501046170">"Vidžeti i prečice nisu dostupni"</string>
- <string name="no_search_results" msgid="3787956167293097509">"Nije pronađen nijedan vidžet ili prečica"</string>
+ <string name="no_search_results" msgid="3787956167293097509">"Nije pronađen nijedan vidžet ni prečica"</string>
<string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Lično"</string>
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Posao"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Konverzacije"</string>
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> se instalira, <xliff:g id="PROGRESS">%2$s</xliff:g> gotovo"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> se preuzima, završeno je <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> čeka na instaliranje"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Lista vidžeta"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Lista vidžeta je zatvorena"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Dodajte na početni ekran"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index cc0c40d..43e5e90 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Усталёўваецца праграма \"<xliff:g id="NAME">%1$s</xliff:g>\", завершана <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Ідзе спампоўка <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> завершана"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> чакае ўсталёўкі"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Спіс віджэтаў"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Спіс віджэтаў закрыты"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Дадаць на галоўны экран"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 5601c26..9c65708 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> се инсталира, <xliff:g id="PROGRESS">%2$s</xliff:g> завършено"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> се изтегля. Завършено: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> изчаква инсталиране"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Списък с приспособления"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Списъкът с приспособления е затворен"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Добавяне към началния екран"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 8b4cd72..38be6e2 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ইনস্টল করা হচ্ছে, <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পূর্ণ হয়েছে"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ডাউনলোড হচ্ছে <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পন্ন হয়েছে"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ইনস্টলের অপেক্ষায় রয়েছে"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"উইজেটের তালিকা"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"উইজেটের তালিকা বন্ধ করা হয়েছে"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"হোম স্ক্রিনে যোগ করুন"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index cf3163b..fbf9fce 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Instaliranje aplikacije <xliff:g id="NAME">%1$s</xliff:g>, završeno je <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> se preuzima, završeno <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> čeka da se instalira"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Spisak vidžeta"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Spisak vidžeta je zatvoren"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Dodavanje na početni ekran"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 1f3315a..9eba6b8 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"S\'està instal·lant <xliff:g id="NAME">%1$s</xliff:g>; s\'ha completat un <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"S\'està baixant <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> completat"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"S\'està esperant per instal·lar <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Llista de widgets"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"S\'ha tancat la llista de widgets"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Afegeix a la pantalla d\'inici"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 225d7ee..3b38e62 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -32,7 +32,7 @@
<string name="split_screen_position_left" msgid="7537793098851830883">"Rozdělit vlevo"</string>
<string name="split_screen_position_right" msgid="1569377524925193369">"Rozdělit vpravo"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informace o aplikaci %1$s"</string>
- <string name="long_press_widget_to_add" msgid="3587712543577675817">"Klepnutím a podržením přesunete widget."</string>
+ <string name="long_press_widget_to_add" msgid="3587712543577675817">"Widget přesunete klepnutím a podržením."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvojitým klepnutím a podržením přesunete widget, případně použijte vlastní akce."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"šířka %1$d, výška %2$d"</string>
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Instalace aplikace <xliff:g id="NAME">%1$s</xliff:g>, dokončeno <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Stahování aplikace <xliff:g id="NAME">%1$s</xliff:g> (dokončeno <xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"Instalace aplikace <xliff:g id="NAME">%1$s</xliff:g> čeká na zahájení"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Seznam widgetů"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Seznam widgetů zavřen"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Přidat na plochu"</string>
@@ -156,7 +164,7 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Osobní"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Pracovní"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Pracovní profil"</string>
- <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Pracovní aplikace jsou označené a viditelné vašemu administrátorovi IT"</string>
+ <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Pracovní aplikace jsou označené a váš administrátor IT je vidí"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"Rozumím"</string>
<string name="work_apps_paused_title" msgid="3040901117349444598">"Pracovní aplikace jsou pozastaveny"</string>
<string name="work_apps_paused_body" msgid="261634750995824906">"Pracovní aplikace vám nemohou zasílat oznámení, používat vaši baterii ani získat přístup k vaší poloze"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 094d84e..284f2d9 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installeres. <xliff:g id="PROGRESS">%2$s</xliff:g> fuldført"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloades. <xliff:g id="PROGRESS">%2$s</xliff:g> er gennemført"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> venter på at installere"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Liste med widgets"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Listen med widgets blev lukket"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Føj til startskærm"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 4b92155..0dc06cd 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> wird installiert, <xliff:g id="PROGRESS">%2$s</xliff:g> abgeschlossen"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> wird heruntergeladen, <xliff:g id="PROGRESS">%2$s</xliff:g> abgeschlossen"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"Warten auf Installation von <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Widgetliste"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Widgetliste geschlossen"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Zum Startbildschirm hinzufügen"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 667d511..2b67848 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Έχει ολοκληρωθεί το <xliff:g id="PROGRESS">%2$s</xliff:g> της εγκατάστασης της εφαρμογής <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Λήψη <xliff:g id="NAME">%1$s</xliff:g>, ολοκληρώθηκε <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> σε αναμονή για εγκατάσταση"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Λίστα γραφικών στοιχείων"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Η λίστα γραφικών στοιχείων έκλεισε"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Προσθήκη στην αρχική οθόνη"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 455aea6..4853509 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installing, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloading, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> waiting to install"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Widgets list"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Widgets list closed"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Add to home screen"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 455aea6..4853509 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installing, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloading, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> waiting to install"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Widgets list"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Widgets list closed"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Add to home screen"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 455aea6..4853509 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installing, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloading, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> waiting to install"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Widgets list"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Widgets list closed"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Add to home screen"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 455aea6..4853509 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installing, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloading, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> waiting to install"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Widgets list"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Widgets list closed"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Add to home screen"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 4a4dc49..90cd6cd 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -124,6 +124,10 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installing, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloading, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> waiting to install"</string>
+ <string name="dialog_update_title" msgid="114234265740994042">"App update required"</string>
+ <string name="dialog_update_message" msgid="4176784553982226114">"The app for this icon isn\'t updated. You can update manually to re-enable this shortcut, or remove the icon."</string>
+ <string name="dialog_update" msgid="2178028071796141234">"Update"</string>
+ <string name="dialog_remove" msgid="6510806469849709407">"Remove"</string>
<string name="widgets_list" msgid="796804551140113767">"Widgets list"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Widgets list closed"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Add to home screen"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index fad6690..b67397b 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Se está instalando <xliff:g id="NAME">%1$s</xliff:g>; <xliff:g id="PROGRESS">%2$s</xliff:g> completado"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Se completó el <xliff:g id="PROGRESS">%2$s</xliff:g> de la descarga de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"Instalación de <xliff:g id="NAME">%1$s</xliff:g> en espera"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Lista de widgets"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Se cerró la lista de widgets"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Agregar a pantalla principal"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index ef7271e..a6f07da 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -23,8 +23,8 @@
<string name="work_folder_name" msgid="3753320833950115786">"Trabajo"</string>
<string name="activity_not_found" msgid="8071924732094499514">"La aplicación no está instalada."</string>
<string name="activity_not_available" msgid="7456344436509528827">"La aplicación no está disponible"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"Aplicación descargada inhabilitada en modo seguro"</string>
- <string name="safemode_widget_error" msgid="4863470563535682004">"Widgets inhabilitados en modo seguro"</string>
+ <string name="safemode_shortcut_error" msgid="9160126848219158407">"Aplicación descargada inhabilitada en modo Seguro"</string>
+ <string name="safemode_widget_error" msgid="4863470563535682004">"Widgets inhabilitados en modo Seguro"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Acceso directo no disponible"</string>
<string name="home_screen" msgid="5629429142036709174">"Inicio"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
@@ -32,7 +32,7 @@
<string name="split_screen_position_left" msgid="7537793098851830883">"Dividir parte izquierda"</string>
<string name="split_screen_position_right" msgid="1569377524925193369">"Dividir parte derecha"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Información de la aplicación %1$s"</string>
- <string name="long_press_widget_to_add" msgid="3587712543577675817">"Mantén pulsado un widget para moverlo."</string>
+ <string name="long_press_widget_to_add" msgid="3587712543577675817">"Mantén pulsado un widget para moverlo"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toca dos veces y mantén pulsado un widget para moverlo o usar acciones personalizadas."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de ancho por %2$d de alto"</string>
@@ -41,7 +41,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Añadir a pantalla de inicio"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> añadido a la pantalla de inicio"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
- <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# combinación de teclas}other{# combinaciones de teclas}}"</string>
+ <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# acceso directo}other{# accesos directos}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
<string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
<string name="widgets_full_sheet_search_bar_hint" msgid="8484659090860596457">"Buscar"</string>
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Instalando <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> completado"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Descargando <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="PROGRESS">%2$s</xliff:g> completado)"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"Esperando para instalar <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Lista de widgets"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Lista de widgets cerrada"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Añadir a pantalla de inicio"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 8f6a8d5..ee31cef 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Üksust <xliff:g id="NAME">%1$s</xliff:g> installitakse, <xliff:g id="PROGRESS">%2$s</xliff:g> on valmis"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Rakenduse <xliff:g id="NAME">%1$s</xliff:g> allalaadimine, <xliff:g id="PROGRESS">%2$s</xliff:g> on valmis"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> on installimise ootel"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Vidinate loend"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Vidinate loend on suletud"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Lisa avakuvale"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 995f8dd..2798733 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> instalatzen, <xliff:g id="PROGRESS">%2$s</xliff:g> osatuta"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> deskargatzen, <xliff:g id="PROGRESS">%2$s</xliff:g> osatuta"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> instalatzeko zain"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Widget-zerrenda"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Itxi da widget-zerrenda"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Gehitu hasierako pantailan"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index ee97518..a569816 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> درحال نصب است، <xliff:g id="PROGRESS">%2$s</xliff:g> تکمیل شده است"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"درحال بارگیری <xliff:g id="NAME">%1$s</xliff:g>، <xliff:g id="PROGRESS">%2$s</xliff:g> کامل شد"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> درانتظار نصب"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"فهرست ابزارکها"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"فهرست ابزارکها بسته شد"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"افزودن به صفحه اصلی"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 21006e6..707dc9a 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> asennetaan, <xliff:g id="PROGRESS">%2$s</xliff:g> valmis"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> latautuu, valmiina <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> odottaa asennusta"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Widget-luettelo"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Widget-luettelo suljettu"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Lisää aloitusnäytölle"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 0c023a3..ff7faad 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Installation de l\'application <xliff:g id="NAME">%1$s</xliff:g> en cours, <xliff:g id="PROGRESS">%2$s</xliff:g> terminée"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Téléchargement de <xliff:g id="NAME">%1$s</xliff:g> : <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> en attente d\'installation"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Liste des widgets"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Liste des widgets fermée"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Ajouter à l\'écran d\'accueil"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 5199c89..ce4add7 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Installation de <xliff:g id="NAME">%1$s</xliff:g>… (<xliff:g id="PROGRESS">%2$s</xliff:g> terminés)"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> en cours de téléchargement, <xliff:g id="PROGRESS">%2$s</xliff:g> effectué(s)"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> en attente d\'installation"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Liste des widgets"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"La liste des widgets est fermée"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Ajouter à l\'écran d\'accueil"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index eee0032..6e42995 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Instalando <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> completado"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Descargando <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="PROGRESS">%2$s</xliff:g> completado)"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"Esperando para instalar <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Lista de widgets"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Pechouse a lista de widgets"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Engadir á pantalla de inicio"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 39f61ba..b2d2654 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ઇન્સ્ટૉલ કરી રહ્યાં છીએ, <xliff:g id="PROGRESS">%2$s</xliff:g> પૂર્ણ થયું"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ડાઉનલોડ કરી રહ્યાં છે, <xliff:g id="PROGRESS">%2$s</xliff:g> પૂર્ણ"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>, ઇન્સ્ટૉલ થવાની રાહ જોઈ રહ્યું છે"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"વિજેટની સૂચિ"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"વિજેટની સૂચિ બંધ કરવામાં આવી છે"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"હોમ સ્ક્રીનમાં ઉમેરો"</string>
@@ -156,12 +164,12 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"મનગમતી ઍપ"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"ઑફિસની ઍપ"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"ઑફિસની પ્રોફાઇલ"</string>
- <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"ઑફિસની ઍપને બૅજ આપેલા હોય છે અને તમારા IT વ્યવસ્થાપક તેમને જોઈ શકે છે"</string>
+ <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"ઑફિસની ઍપને બૅજ આપેલા હોય છે અને તમારા IT ઍડમિન તેમને જોઈ શકે છે"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"સમજાઈ ગયું"</string>
- <string name="work_apps_paused_title" msgid="3040901117349444598">"ઑફિસ માટેની ઍપ થોભાવવામાં આવેલ છે"</string>
+ <string name="work_apps_paused_title" msgid="3040901117349444598">"ઑફિસ માટેની ઍપ થોભાવવામાં આવી છે"</string>
<string name="work_apps_paused_body" msgid="261634750995824906">"ઑફિસ માટેની તમારી ઍપ તમને નોટિફિકેશન મોકલી શકતી નથી, તમારી બૅટરી વાપરી શકતી નથી કે તમારું સ્થાન ઍક્સેસ કરી શકતી નથી"</string>
<string name="work_apps_paused_content_description" msgid="5149623040804051095">"ઑફિસ માટેની ઍપ બંધ છે. ઑફિસ માટેની તમારી ઍપ તમને નોટિફિકેશન મોકલી શકતી નથી, તમારી બૅટરી વાપરી શકતી નથી કે તમારું સ્થાન ઍક્સેસ કરી શકતી નથી"</string>
- <string name="work_apps_paused_edu_banner" msgid="8872412121608402058">"ઑફિસની ઍપને બૅજ આપેલા હોય છે અને તમારા IT વ્યવસ્થાપક તેમને જોઈ શકે છે"</string>
+ <string name="work_apps_paused_edu_banner" msgid="8872412121608402058">"ઑફિસની ઍપને બૅજ આપેલા હોય છે અને તમારા IT ઍડમિન તેમને જોઈ શકે છે"</string>
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"સમજાઈ ગયું"</string>
<string name="work_apps_pause_btn_text" msgid="1921059713673767460">"ઑફિસ માટેની ઍપ બંધ કરો"</string>
<string name="work_apps_enable_btn_text" msgid="1156432622148413741">"ઑફિસ માટેની ઍપ ચાલુ કરો"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 6125205..bdb16cc 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> इंस्टॉल किया जा रहा है, <xliff:g id="PROGRESS">%2$s</xliff:g> पूरा हो गया"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> डाउनलोड हो रहा है, <xliff:g id="PROGRESS">%2$s</xliff:g> पूरी हुई"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> के इंस्टॉल होने की प्रतीक्षा की जा रही है"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"विजेट की सूची"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"विजेट की सूची बंद हो गई है"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"होम स्क्रीन पर जोड़ें"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index f12af71..cc7f067 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Instaliranje aplikacije <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> dovršeno"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Preuzimanje aplikacije <xliff:g id="NAME">%1$s</xliff:g>, dovršeno <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"Čekanje na instaliranje aplikacije <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Popis widgeta"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Popis widgeta zatvoren"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Dodajte na početni zaslon"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index d48792a..9cd705c 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Folyamatban van a(z) <xliff:g id="NAME">%1$s</xliff:g> telepítése, <xliff:g id="PROGRESS">%2$s</xliff:g> kész"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"A(z) <xliff:g id="NAME">%1$s</xliff:g> letöltése, <xliff:g id="PROGRESS">%2$s</xliff:g> kész"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"A(z) <xliff:g id="NAME">%1$s</xliff:g> telepítésre vár"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Widgetlista"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Widgetlista bezárva"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Hozzáadás a kezdőképernyőhöz"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 1c90768..e8124a6 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> հավելվածը տեղադրվում է, կատարված է <xliff:g id="PROGRESS">%2$s</xliff:g>-ը"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>–ի ներբեռնում (<xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>-ի տեղադրման սպասում"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Վիջեթների ցանկ"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Վիջեթների ցանկը փակվեց"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Ավելացնել հիմնական էկրանին"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index ee64f2c..07ebae9 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> sedang diinstal, <xliff:g id="PROGRESS">%2$s</xliff:g> selesai"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> sedang didownload, <xliff:g id="PROGRESS">%2$s</xliff:g> selesai"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> menunggu dipasang"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Daftar widget"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Daftar widget ditutup"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Tambahkan ke layar utama"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 7f7b560..3645bb9 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Setur upp <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> lokið"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> í niðurhali, <xliff:g id="PROGRESS">%2$s</xliff:g> lokið"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> bíður uppsetningar"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Græjulisti"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Græjulista lokað"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Bæta á heimaskjá"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 55bc9ac..c56ce0b 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Installazione di <xliff:g id="NAME">%1$s</xliff:g>, completamento: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Download di <xliff:g id="NAME">%1$s</xliff:g> in corso, <xliff:g id="PROGRESS">%2$s</xliff:g> completato"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> in attesa di installazione"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Elenco di widget"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Elenco di widget chiuso"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Aggiungi alla schermata Home"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index e374ced..0aa3f11 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -32,7 +32,7 @@
<string name="split_screen_position_left" msgid="7537793098851830883">"פיצול שמאלה"</string>
<string name="split_screen_position_right" msgid="1569377524925193369">"פיצול ימינה"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"פרטים על האפליקציה %1$s"</string>
- <string name="long_press_widget_to_add" msgid="3587712543577675817">"כדי להעביר ווידג\'ט למקום אחר יש לגעת ולא להרפות."</string>
+ <string name="long_press_widget_to_add" msgid="3587712543577675817">"להעברת ווידג\'ט למקום אחר לוחצים עליו לחיצה ארוכה."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"כדי להעביר ווידג\'ט למקום אחר או להשתמש בפעולות מותאמות אישית, יש ללחוץ פעמיים ולא להרפות."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"רוחב %1$d על גובה %2$d"</string>
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> בתהליך התקנה, <xliff:g id="PROGRESS">%2$s</xliff:g> הושלמו"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"הורדת <xliff:g id="NAME">%1$s</xliff:g> מתבצעת, <xliff:g id="PROGRESS">%2$s</xliff:g> הושלמו"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"מחכה להתקנה של <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"רשימת ווידג\'טים"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"רשימת הווידג\'טים נסגרה"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"הוספה למסך הבית"</string>
@@ -153,7 +161,7 @@
<string name="action_dismiss_notification" msgid="5909461085055959187">"סגירה"</string>
<string name="accessibility_close" msgid="2277148124685870734">"סגירה"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"ההתראה נסגרה"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"אישיות"</string>
+ <string name="all_apps_personal_tab" msgid="4190252696685155002">"אישי"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"עבודה"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"פרופיל עבודה"</string>
<string name="work_profile_edu_work_apps" msgid="7895468576497746520">"האפליקציות לעבודה מתויגות ומוצגות למנהל ה-IT"</string>
@@ -163,7 +171,7 @@
<string name="work_apps_paused_content_description" msgid="5149623040804051095">"האפליקציות לעבודה מושבתות. האפליקציות לא יכולות לשלוח לך התראות, להשתמש בסוללה או לגשת למיקום שלך"</string>
<string name="work_apps_paused_edu_banner" msgid="8872412121608402058">"האפליקציות לעבודה מתויגות ומוצגות למנהל ה-IT"</string>
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"הבנתי"</string>
- <string name="work_apps_pause_btn_text" msgid="1921059713673767460">"כיבוי של אפליקציות לעבודה"</string>
+ <string name="work_apps_pause_btn_text" msgid="1921059713673767460">"השבתה של אפליקציות לעבודה"</string>
<string name="work_apps_enable_btn_text" msgid="1156432622148413741">"הפעלה של אפליקציות לעבודה"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"סינון"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"הפעולה נכשלה: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 83c7f39..9ac4b94 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> をインストールしています: <xliff:g id="PROGRESS">%2$s</xliff:g> 完了"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>をダウンロード中、<xliff:g id="PROGRESS">%2$s</xliff:g>完了"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>のインストール待ち"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"ウィジェット リスト"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"ウィジェット リストを閉じました"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"ホーム画面に追加"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 9208448..6f66155 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"ინსტალირდება <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> დასრულებულია"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"მიმდინარეობს <xliff:g id="NAME">%1$s</xliff:g>-ის ჩამოტვირთვა, <xliff:g id="PROGRESS">%2$s</xliff:g> დასრულდა"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ელოდება ინსტალაციას"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"ვიჯეტების სია"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"ვიჯეტების სია დაიხურა"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"მთავარ ეკრანზე დამატება"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 1383216..8b738e4 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -51,7 +51,7 @@
<string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Жеке виджеттер"</string>
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Жұмыс виджеттері"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Әңгімелер"</string>
- <string name="widget_education_header" msgid="4874760613775913787">"Саусақпен түртсеңіз болғаны – пайдалы ақпарат көз алдыңызда"</string>
+ <string name="widget_education_header" msgid="4874760613775913787">"Саусақпен түртсеңіз болғаны – пайдалы ақпарат көз алдыңызда"</string>
<string name="widget_education_content" msgid="1731667670753497052">"Қолданбаларды ашпай-ақ ақпарат алу үшін негізгі экранға тиісті виджеттерді қосыңыз."</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Виджет параметрлерін өзгерту үшін түртіңіз."</string>
<string name="widget_education_close_button" msgid="8676165703104836580">"Түсінікті"</string>
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> орнатылуда, <xliff:g id="PROGRESS">%2$s</xliff:g> аяқталды"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> жүктелуде, <xliff:g id="PROGRESS">%2$s</xliff:g> аяқталды"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> орнату күтілуде"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Виджеттер тізімі"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Видджеттер тізімі жабылды"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Негізгі экранға қосу"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 2404995..b0a3234 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"កំពុងដំឡើង <xliff:g id="NAME">%1$s</xliff:g>, បានបញ្ចប់ <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"កំពុងដោនឡូត <xliff:g id="NAME">%1$s</xliff:g> បានបញ្ចប់ <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> កំពុងរង់ចាំការដំឡើង"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"បញ្ជីធាតុក្រាហ្វិក"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"បានបិទបញ្ជីធាតុក្រាហ្វិក"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"បញ្ចូលទៅក្នុងអេក្រង់ដើម"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 1087e8a..7d9f8d9 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -50,7 +50,7 @@
<string name="no_search_results" msgid="3787956167293097509">"ಯಾವುದೇ ವಿಜೆಟ್ಗಳು ಅಥವಾ ಶಾರ್ಟ್ಕಟ್ಗಳು ಕಂಡುಬಂದಿಲ್ಲ"</string>
<string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"ವೈಯಕ್ತಿಕ"</string>
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ಕೆಲಸ"</string>
- <string name="widget_category_conversations" msgid="8894438636213590446">"ಸಂವಾದಗಳು"</string>
+ <string name="widget_category_conversations" msgid="8894438636213590446">"ಸಂಭಾಷಣೆಗಳು"</string>
<string name="widget_education_header" msgid="4874760613775913787">"ನಿಮ್ಮ ಬೆರಳ ತುದಿಯಲ್ಲಿ ಉಪಯುಕ್ತ ಮಾಹಿತಿ"</string>
<string name="widget_education_content" msgid="1731667670753497052">"ಆ್ಯಪ್ಗಳನ್ನು ತೆರೆಯದೆಯೇ ಮಾಹಿತಿಯನ್ನು ಪಡೆಯಲು, ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್ನಲ್ಲಿ ನೀವು ವಿಜೆಟ್ಗಳನ್ನು ಸೇರಿಸಬಹುದು"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ವಿಜೆಟ್ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗುತ್ತಿದೆ, <xliff:g id="PROGRESS">%2$s</xliff:g> ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ಡೌನ್ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ, <xliff:g id="PROGRESS">%2$s</xliff:g> ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ಸ್ಥಾಪಿಸಲು ಕಾಯಲಾಗುತ್ತಿದೆ"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"ವಿಜೆಟ್ ಪಟ್ಟಿ"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"ವಿಜೆಟ್ ಪಟ್ಟಿಯನ್ನು ಮುಚ್ಚಲಾಗಿದೆ"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"ಹೋಮ್ ಸ್ಕ್ರೀನ್ಗೆ ಸೇರಿಸಿ"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 65a58f4..22a9b3c 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> 설치 중, <xliff:g id="PROGRESS">%2$s</xliff:g> 완료"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> 다운로드 중, <xliff:g id="PROGRESS">%2$s</xliff:g> 완료"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> 설치 대기 중"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"위젯 목록"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"위젯 목록 닫힘"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"홈 화면에 추가"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 0286ec3..c235b3d 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> орнотулууда, <xliff:g id="PROGRESS">%2$s</xliff:g> аткарылды"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> жүктөлүп алынууда, <xliff:g id="PROGRESS">%2$s</xliff:g> аяктады"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> орнотулушу күтүлүүдө"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Виджеттердин тизмеси"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Виджеттердин тизмеси жабык"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Башкы экранга кошуу"</string>
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 652a61c..422240c 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -37,4 +37,7 @@
<dimen name="drop_target_button_drawable_vertical_padding">2dp</dimen>
<dimen name="drop_target_top_margin">6dp</dimen>
<dimen name="drop_target_bottom_margin">6dp</dimen>
+
+ <!-- Workspace grid visualization parameters -->
+ <dimen name="grid_visualization_horizontal_cell_spacing">24dp</dimen>
</resources>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 1245f5c..66ff43d 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"ກຳລັງຕິດຕັ້ງ <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> ສຳເລັດແລ້ວ"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ກຳລັງດາວໂຫຼດ, <xliff:g id="PROGRESS">%2$s</xliff:g> ສຳເລັດ"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ກຳລັງລໍຖ້າຕິດຕັ້ງ"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"ລາຍຊື່ວິດເຈັດ"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"ປິດລາຍຊື່ວິດເຈັດແລ້ວ"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"ເພີ່ມໃສ່ໂຮມສະກຣີນ"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 4e46c7b..66933ac 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Įdiegiama: „<xliff:g id="NAME">%1$s</xliff:g>“; baigta: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Atsisiunčiama programa „<xliff:g id="NAME">%1$s</xliff:g>“, <xliff:g id="PROGRESS">%2$s</xliff:g> baigta"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"Laukiama, kol bus įdiegta programa „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Valdiklių sąrašas"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Valdiklių sąrašas uždarytas"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Pridėti prie pagrind. ekrano"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 0675912..3eed085 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Notiek lietotnes “<xliff:g id="NAME">%1$s</xliff:g>” instalēšana. Norise: <xliff:g id="PROGRESS">%2$s</xliff:g>."</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Lietotnes <xliff:g id="NAME">%1$s</xliff:g> lejupielāde (<xliff:g id="PROGRESS">%2$s</xliff:g> pabeigti)"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"Notiek <xliff:g id="NAME">%1$s</xliff:g> instalēšana"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Logrīku saraksts"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Logrīku saraksts aizvērts"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Pievienot sākuma ekrānam"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 72a4642..a45391f 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> се инсталира, <xliff:g id="PROGRESS">%2$s</xliff:g> завршено"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Се презема <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> завршено"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> чека да се инсталира"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Список со виџети"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Списокот со виџети е затворен"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Додај на почетниот екран"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 0c6f24b..5a1ee03 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ഇൻസ്റ്റാൾ ചെയ്യുന്നു, <xliff:g id="PROGRESS">%2$s</xliff:g> പൂർത്തിയായി"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ഡൗൺലോഡ് ചെയ്യുന്നു, <xliff:g id="PROGRESS">%2$s</xliff:g> പൂർത്തിയായി"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"ഇൻസ്റ്റാൾ ചെയ്യാൻ <xliff:g id="NAME">%1$s</xliff:g> കാക്കുന്നു"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"വിജറ്റുകളുടെ ലിസ്റ്റ്"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"വിജറ്റുകളുടെ ലിസ്റ്റ് അവസാനിപ്പിച്ചു"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"ഹോം സ്ക്രീനിലേക്ക് ചേർക്കുക"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 303e3cc..b222ba9 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g>-г суулгаж байна. <xliff:g id="PROGRESS">%2$s</xliff:g> дууссан"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>-г татаж байна, <xliff:g id="PROGRESS">%2$s</xliff:g> татсан"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> нь суулгахыг хүлээж байна"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Жижиг хэрэгслийн жагсаалт"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Жижиг хэрэгслийн жагсаалтыг хаасан"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Үндсэн нүүрэнд нэмэх"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 4498fec..0f03074 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> इंस्टॉल करत आहे, <xliff:g id="PROGRESS">%2$s</xliff:g> पूर्ण झाले"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> डाउनलोड होत आहे , <xliff:g id="PROGRESS">%2$s</xliff:g> पूर्ण झाले"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> इंस्टॉल करण्याची प्रतिक्षा करत आहे"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"विजेट सूची"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"विजेट सूची बंद केली"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"होम स्क्रीनवर जोडा"</string>
@@ -156,7 +164,7 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"वैयक्तिक"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"कार्य"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"कार्य प्रोफाइल"</string>
- <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"कामाशी संबंधित ॲप्स ही बॅज केलेली असून तुमच्या IT ॲडमिनला दृश्यमान आहेत"</string>
+ <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"कामाशी संबंधित ॲप्स ही बॅज केलेली असून तुमच्या आयटी ॲडमिनला दृश्यमान आहेत"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"समजले"</string>
<string name="work_apps_paused_title" msgid="3040901117349444598">"कार्य ॲप्स थांबवली आहेत"</string>
<string name="work_apps_paused_body" msgid="261634750995824906">"तुमची कार्य ॲप्स तुम्हाला सूचना पाठवू शकत नाहीत, तुमची बॅटरी वापरू शकत नाहीत किंवा तुमचे स्थान अॅक्सेस करू शकत नाहीत"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 3c75a66..f24038c 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> dipasang, <xliff:g id="PROGRESS">%2$s</xliff:g> selesai"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> memuat turun, <xliff:g id="PROGRESS">%2$s</xliff:g> selesai"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> menunggu untuk dipasang"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Senarai widget"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Senarai widget ditutup"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Tambahkan pada skrin utama"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 48edebc..c53b912 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ကို ထည့်သွင်းနေသည်၊ <xliff:g id="PROGRESS">%2$s</xliff:g> ပြီးပါပြီ"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ဒေါင်းလုဒ်လုပ်နေသည်၊ <xliff:g id="PROGRESS">%2$s</xliff:g> ပြီးပါပြီ"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ကိုထည့်သွင်းရန်စောင့်နေသည်"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"ဝိဂျက်စာရင်း"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"ဝိဂျက်စာရင်းကို ပိတ်ထားသည်"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"ပင်မစာမျက်နှာတွင် ထည့်ရန်"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index ad6a3cc..416f204 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installerer, <xliff:g id="PROGRESS">%2$s</xliff:g> er fullført"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Laster ned <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> er fullført"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"Venter på å installere <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Modulliste"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Modullisten er lukket"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Legg til på startskjermen"</string>
@@ -156,7 +164,7 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Personlig"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Jobb"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Jobbprofil"</string>
- <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Jobbapper er merket og synlige for IT-administratoren din"</string>
+ <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Jobbapper er merket og synlige for IT-administratoren"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"Greit"</string>
<string name="work_apps_paused_title" msgid="3040901117349444598">"Jobbapper er satt på pause"</string>
<string name="work_apps_paused_body" msgid="261634750995824906">"Jobbapper kan ikke sende deg varsler, bruke batteriet eller få tilgang til posisjonen din"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 05a284f..1e212be 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> इन्स्टल गरिँदै छ, <xliff:g id="PROGRESS">%2$s</xliff:g> पूरा भयो"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> डाउनलोड गर्दै, <xliff:g id="PROGRESS">%2$s</xliff:g> सम्पन्न"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> स्थापना गर्न प्रतीक्षा गर्दै"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"विजेटहरूको सूची"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"विजेटहरूको सूची बन्द गरियो"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"होम स्क्रिनमा राख्नुहोस्"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index baf40ae..d534bc4 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installeren, <xliff:g id="PROGRESS">%2$s</xliff:g> voltooid"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> wordt gedownload, <xliff:g id="PROGRESS">%2$s</xliff:g> voltooid"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> wacht op installatie"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Lijst met widgets"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Lijst met widgets gesloten"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Toevoegen aan startscherm"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 6a6b76b..2bfb8a1 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ଇନଷ୍ଟଲ୍ କରାଯାଉଛି, <xliff:g id="PROGRESS">%2$s</xliff:g> ସମ୍ପୂର୍ଣ୍ଣ ହୋଇଛି"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ଡାଉନଲୋଡ୍ ହେଉଛି, <xliff:g id="PROGRESS">%2$s</xliff:g> ସମ୍ପୂର୍ଣ୍ଣ"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ଇନଷ୍ଟଲ୍ ହେବାକୁ ଅପେକ୍ଷା କରିଛି"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"ୱିଜେଟ୍ ତାଲିକା"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"ୱିଜେଟ୍ ତାଲିକା ବନ୍ଦ ହୋଇଛି"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"ମୂଳସ୍କ୍ରିନରେ ଯୋଗ କରନ୍ତୁ"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 797b71f..222247b 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ਨੂੰ ਸਥਾਪਤ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ, <xliff:g id="PROGRESS">%2$s</xliff:g> ਪੂਰਾ ਹੋਇਆ"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ਡਾਉਨਲੋਡ ਹੋਰ ਰਿਹਾ ਹੈ, <xliff:g id="PROGRESS">%2$s</xliff:g> ਸੰਪੂਰਣ"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ਸਥਾਪਤ ਕਰਨ ਦੀ ਉਡੀਕ ਕਰ ਰਿਹਾ ਹੈ"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"ਵਿਜੇਟਾਂ ਦੀ ਸੂਚੀ"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"ਵਿਜੇਟਾਂ ਦੀ ਸੂਚੀ ਬੰਦ ਕੀਤੀ ਗਈ"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਸ਼ਾਮਲ ਕਰੋ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 1f226b3..a7c1c18 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Instaluję aplikację <xliff:g id="NAME">%1$s</xliff:g>, postęp: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Pobieranie elementu <xliff:g id="NAME">%1$s</xliff:g>, ukończono: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> oczekuje na instalację"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Lista widgetów"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Lista widgetów zamknięta"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Dodaj do ekranu głównego"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index ddc1031..6cb77d7 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"A instalar <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> concluído"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"A transferir o <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> concluído"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"A aguardar a instalação do <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Lista de widgets"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Lista de widgets fechada."</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Adicionar ao ecrã principal"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index a008761..40edba2 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Instalando <xliff:g id="NAME">%1$s</xliff:g>. <xliff:g id="PROGRESS">%2$s</xliff:g> concluído"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Fazendo download de <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> concluído"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"Aguardando instalação de <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Lista de widgets"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Lista de widgets fechada"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Adicionar à tela inicial"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index e2c9a62..85703dd 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> se instalează, <xliff:g id="PROGRESS">%2$s</xliff:g> finalizat"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> se descarcă (finalizat <xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> așteaptă instalarea"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Listă de widgeturi"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Lista de widgeturi este închisă"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Adăugați pe ecranul de pornire"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 373e8ed..90add40 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Установка приложения \"<xliff:g id="NAME">%1$s</xliff:g>\" (выполнено <xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Скачивается \"<xliff:g id="NAME">%1$s</xliff:g>\" (<xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"Ожидание установки \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Список виджетов"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Список виджетов закрыт"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Добавить на главный экран"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 868451d..61b91c6 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ස්ථාපනය කරමින්, <xliff:g id="PROGRESS">%2$s</xliff:g> සම්පූර්ණයි"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> බාගත කරමින්, <xliff:g id="PROGRESS">%2$s</xliff:g> සම්පූර්ණයි"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ස්ථාපනය කිරීමට බලා සිටිමින්"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"විජට් ලැයිස්තුව"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"විජට් ලැයිස්තුව වසා ඇත"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"මුල් තිරය වෙත එක් කරන්න"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 7ae936c..f85c1f5 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Inštaluje sa <xliff:g id="NAME">%1$s</xliff:g>. Dokončené: <xliff:g id="PROGRESS">%2$s</xliff:g>."</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Sťahuje sa aplikácia <xliff:g id="NAME">%1$s</xliff:g>. Stiahnuté: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"Aplikácia <xliff:g id="NAME">%1$s</xliff:g> čaká na inštaláciu"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Zoznam miniaplikácií"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Zoznam miniaplikácií je zavretý"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Pridať na plochu"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index cb59a99..f374fca 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> se namešča, dokončano: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Prenašanje aplikacije <xliff:g id="NAME">%1$s</xliff:g>; preneseno <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"Aplikacija <xliff:g id="NAME">%1$s</xliff:g> čaka na namestitev"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Seznam pripomočkov"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Seznam pripomočkov se je zaprl"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Dodajanje na začetni zaslon"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index d385ade..31af388 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> po instalohet, <xliff:g id="PROGRESS">%2$s</xliff:g> i përfunduar"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> po shkarkohet, <xliff:g id="PROGRESS">%2$s</xliff:g> të përfunduara"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> po pret të instalohet"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Lista e miniaplikacioneve"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Lista e miniaplikacioneve u mbyll"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Shto në ekranin bazë"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 0c14b56..6b5fe2b 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -47,7 +47,7 @@
<string name="widgets_full_sheet_search_bar_hint" msgid="8484659090860596457">"Претражите"</string>
<string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"Обришите текст из оквира за претрагу"</string>
<string name="no_widgets_available" msgid="4337693382501046170">"Виџети и пречице нису доступни"</string>
- <string name="no_search_results" msgid="3787956167293097509">"Није пронађен ниједан виџет или пречица"</string>
+ <string name="no_search_results" msgid="3787956167293097509">"Није пронађен ниједан виџет ни пречица"</string>
<string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Лично"</string>
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Посао"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Конверзације"</string>
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> се инсталира, <xliff:g id="PROGRESS">%2$s</xliff:g> готово"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> се преузима, завршено је <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> чека на инсталирање"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Листа виџета"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Листа виџета је затворена"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Додајте на почетни екран"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 4448c30..a8c4d1b 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installeras. <xliff:g id="PROGRESS">%2$s</xliff:g> har slutförts"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> laddas ned, <xliff:g id="PROGRESS">%2$s</xliff:g> klart"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> väntar på installation"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Widgetlista"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Widgetslistan har stängts"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Lägg till på startskärmen"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index b81fbeb..1a7f2a4 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -102,7 +102,7 @@
<string name="folder_name_format_exact" msgid="8626242716117004803">"Folda: <xliff:g id="NAME">%1$s</xliff:g>, vipengee <xliff:g id="SIZE">%2$d</xliff:g>"</string>
<string name="folder_name_format_overflow" msgid="4270108890534995199">"Folda: <xliff:g id="NAME">%1$s</xliff:g>, vipengee <xliff:g id="SIZE">%2$d</xliff:g> au zaidi"</string>
<string name="wallpaper_button_text" msgid="8404103075899945851">"Mandhari"</string>
- <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Mandhari na muundo"</string>
+ <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Mandhari na mtindo"</string>
<string name="settings_button_text" msgid="8873672322605444408">"Mipangilio ya mwanzo"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Imezimwa na msimamizi wako"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"Ruhusu kipengele cha kuzungusha skrini ya kwanza"</string>
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Inasakinisha <xliff:g id="NAME">%1$s</xliff:g>, imekamilika <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> inapakuliwa, <xliff:g id="PROGRESS">%2$s</xliff:g> imekamilika"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> inasubiri kusakinisha"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Orodha ya wijeti"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Orodha ya wijeti imefungwa"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Weka kwenye skrini ya kwanza"</string>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 27b13d7..eb347f2 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -38,12 +38,15 @@
<!-- Hotseat -->
<dimen name="dynamic_grid_hotseat_side_padding">0dp</dimen>
- <dimen name="spring_loaded_hotseat_top_margin">97dp</dimen>
+ <dimen name="spring_loaded_hotseat_top_margin">65dp</dimen>
<!-- Dragging -->
- <dimen name="drop_target_top_margin">34dp</dimen>
+ <dimen name="drop_target_top_margin">64dp</dimen>
<dimen name="drop_target_bottom_margin">16dp</dimen>
<dimen name="drop_target_button_drawable_horizontal_padding">16dp</dimen>
<dimen name="drop_target_button_drawable_vertical_padding">16dp</dimen>
<dimen name="dynamic_grid_drop_target_size">56dp</dimen>
+
+<!-- Workspace grid visualization parameters -->
+ <dimen name="grid_visualization_horizontal_cell_spacing">6dp</dimen>
</resources>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index 3ec211a..fad8c95 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -28,11 +28,11 @@
<dimen name="drop_target_button_drawable_horizontal_padding">24dp</dimen>
<dimen name="drop_target_button_drawable_vertical_padding">20dp</dimen>
<dimen name="drop_target_button_gap">32dp</dimen>
- <dimen name="drop_target_top_margin">32dp</dimen>
- <dimen name="drop_target_bottom_margin">32dp</dimen>
+ <dimen name="drop_target_top_margin">110dp</dimen>
+ <dimen name="drop_target_bottom_margin">48dp</dimen>
<!-- Hotseat -->
- <dimen name="spring_loaded_hotseat_top_margin">164dp</dimen>
+ <dimen name="spring_loaded_hotseat_top_margin">108dp</dimen>
<!-- Widget picker-->
<dimen name="widget_list_horizontal_margin">30dp</dimen>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 9c012f5..b9c7cb5 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> நிறுவப்படுகிறது, <xliff:g id="PROGRESS">%2$s</xliff:g> முடிந்தது"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>ஐப் பதிவிறக்குகிறது, <xliff:g id="PROGRESS">%2$s</xliff:g> முடிந்தது"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>ஐ நிறுவுவதற்காகக் காத்திருக்கிறது"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"விட்ஜெட்கள் பட்டியல்"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"விட்ஜெட்கள் பட்டியல் மூடப்பட்டது"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"முகப்புத் திரையில் சேர்"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 4856915..0976af7 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g>ను ఇన్స్టాల్ చేయడం, <xliff:g id="PROGRESS">%2$s</xliff:g> పూర్తయింది"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> డౌన్లోడ్ అవుతోంది, <xliff:g id="PROGRESS">%2$s</xliff:g> పూర్తయింది"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ఇన్స్టాల్ కావడానికి వేచి ఉంది"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"విడ్జెట్ల లిస్ట్"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"విడ్జెట్ల లిస్ట్ మూసివేయబడింది"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"మొదటి స్క్రీన్కు జోడించండి"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 2d2c0b2..6423bb4 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"กำลังติดตั้ง <xliff:g id="NAME">%1$s</xliff:g> เสร็จแล้ว <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"กำลังดาวน์โหลด <xliff:g id="NAME">%1$s</xliff:g> เสร็จแล้ว <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> กำลังรอติดตั้ง"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"รายการวิดเจ็ต"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"ปิดรายการวิดเจ็ตแล้ว"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"เพิ่มลงในหน้าจอหลัก"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index c87c37a..a737102 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Ini-install ang <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> kumpleto"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Dina-download na ang <xliff:g id="NAME">%1$s</xliff:g>, tapos na ang <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"Hinihintay nang mag-install ang <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Listahan ng mga widget"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Nakasara ang listahan ng mga widget"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Idagdag sa home screen"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index ae4c310..b74e52b 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -52,7 +52,7 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"İş"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Görüşmeler"</string>
<string name="widget_education_header" msgid="4874760613775913787">"Faydalı bilgiler parmaklarınızın ucunda"</string>
- <string name="widget_education_content" msgid="1731667670753497052">"Uygulamaları açmadan bilgi almak için ana ekranınıza widget\'lar ekleyebilirsiniz"</string>
+ <string name="widget_education_content" msgid="1731667670753497052">"Uygulama açmadan bilgi almak için ana ekranınıza widget ekleyebilirsiniz"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Widget ayarlarını değiştirmek için dokunun"</string>
<string name="widget_education_close_button" msgid="8676165703104836580">"Anladım"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Widget ayarlarını değiştir"</string>
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> yükleniyor, <xliff:g id="PROGRESS">%2$s</xliff:g> tamamlandı"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> indiriliyor, <xliff:g id="PROGRESS">%2$s</xliff:g> tamamlandı"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> uygulaması yüklenmek için bekliyor"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Widget listesi"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Widget listesi kapalı"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Ana ekrana ekle"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index e6f6682..619b993 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> встановлюється, виконано <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> завантажується, <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> очікує на завантаження"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Список віджетів"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Список віджектів закрито"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Додати на головний екран"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 32a4108..3fdad53 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> انسٹال کی جا رہی ہے، <xliff:g id="PROGRESS">%2$s</xliff:g> مکمل ہو گئی"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ڈاؤن لوڈ ہو رہا ہے، <xliff:g id="PROGRESS">%2$s</xliff:g> مکمل ہو گیا"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> انسٹال ہونے کا انتظار کر رہی ہے"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"ویجیٹس کی فہرست"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"ویجیٹس کی فہرست بند کر دی گئی"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"ہوم اسکرین میں شامل کریں"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 96e2189..58f1f4e 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> oʻrnatlmoqda, <xliff:g id="PROGRESS">%2$s</xliff:g> yakunlandi"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> yuklab olinmoqda, <xliff:g id="PROGRESS">%2$s</xliff:g> bajarildi"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ilovasi o‘rnatilishi kutilmoqda"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Vidjetlar ro‘yxati"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Vidjetlar ro‘yxati yopildi"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Bosh ekranga chiqarish"</string>
diff --git a/res/values-v33/style.xml b/res/values-v33/style.xml
new file mode 100644
index 0000000..bd48468
--- /dev/null
+++ b/res/values-v33/style.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2022 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.
+*/
+-->
+
+<resources>
+ <style name="HomeSettings.Theme" parent="@android:style/Theme.DeviceDefault.Settings">
+ <item name="android:listPreferredItemPaddingEnd">16dp</item>
+ <item name="android:listPreferredItemPaddingStart">24dp</item>
+ <item name="android:navigationBarColor">@android:color/transparent</item>
+ <item name="android:statusBarColor">@android:color/transparent</item>
+ <item name="android:switchStyle">@style/HomeSettings.SwitchStyle</item>
+ <item name="android:textAppearanceListItem">@style/HomeSettings.PreferenceTitle</item>
+ <item name="android:windowActionBar">false</item>
+ <item name="android:windowNoTitle">true</item>
+ <item name="preferenceTheme">@style/HomeSettings.PreferenceTheme</item>
+ <item name="android:windowAnimationStyle">@style/Animation.SharedBackground</item>
+ </style>
+
+ <style name="Animation.SharedBackground" parent="@android:style/Animation.Activity">
+ <item name="android:activityOpenEnterAnimation">@anim/shared_x_axis_activity_open_enter</item>
+ <item name="android:activityOpenExitAnimation">@anim/shared_x_axis_activity_open_exit</item>
+ <item name="android:activityCloseEnterAnimation">@anim/shared_x_axis_activity_close_enter</item>
+ <item name="android:activityCloseExitAnimation">@anim/shared_x_axis_activity_close_exit</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index b15515f..6a9a9b3 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"Đang cài đặt <xliff:g id="NAME">%1$s</xliff:g>, hoàn tất <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Đang tải xuống <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> hoàn tất"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"Đang chờ cài đặt <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Danh sách tiện ích"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Đã đóng danh sách tiện ích"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Thêm vào màn hình chính"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 775c495..ea7d37e 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"正在安装<xliff:g id="NAME">%1$s</xliff:g>,已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"正在下载<xliff:g id="NAME">%1$s</xliff:g>,已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>正在等待安装"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"微件列表"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"微件列表已关闭"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"添加到主屏幕"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index e0724de..4e2c060 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"正在安裝「<xliff:g id="NAME">%1$s</xliff:g>」(已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"正在下載 <xliff:g id="NAME">%1$s</xliff:g>,已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"正在等待安裝 <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"小工具清單"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"已經關閉嘅小工具清單"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"加去主畫面"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index a2914d6..8394459 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"正在安裝「<xliff:g id="NAME">%1$s</xliff:g>」(已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"正在下載「<xliff:g id="NAME">%1$s</xliff:g>」,已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"正在等待安裝「<xliff:g id="NAME">%1$s</xliff:g>」"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"小工具清單"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"已關閉小工具清單"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"新增至主畫面"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 79b9acd..dc378f7 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -124,6 +124,14 @@
<string name="app_installing_title" msgid="5864044122733792085">"I-<xliff:g id="NAME">%1$s</xliff:g> iyafakwa, seyiqede <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"I-<xliff:g id="NAME">%1$s</xliff:g> iyalandwa, <xliff:g id="PROGRESS">%2$s</xliff:g> kuqediwe"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ilinde ukufakwa"</string>
+ <!-- no translation found for dialog_update_title (114234265740994042) -->
+ <skip />
+ <!-- no translation found for dialog_update_message (4176784553982226114) -->
+ <skip />
+ <!-- no translation found for dialog_update (2178028071796141234) -->
+ <skip />
+ <!-- no translation found for dialog_remove (6510806469849709407) -->
+ <skip />
<string name="widgets_list" msgid="796804551140113767">"Uhlu lwamawijethi"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Uhlu lwamawijethi luvaliwe"</string>
<string name="action_add_to_workspace" msgid="215894119683164916">"Faka kusikrini sasekhaya"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index 0ed2d85..5ecd929 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -166,6 +166,6 @@
<!-- Swipe back to home related -->
<dimen name="swipe_back_window_scale_x_margin">10dp</dimen>
- <dimen name="swipe_back_window_scale_y_margin">80dp</dimen>
+ <dimen name="swipe_back_window_max_delta_y">160dp</dimen>
<dimen name="swipe_back_window_corner_radius">40dp</dimen>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 9a41070..52ff3f0 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -291,15 +291,15 @@
<!-- popup_padding_start + deep_shortcut_icon_size / 2 -->
<dimen name="popup_arrow_horizontal_center_offset">26dp</dimen>
<dimen name="popup_arrow_corner_radius">2dp</dimen>
- <!-- popup_padding_start + icon_size + 10dp -->
+ <!-- popup_padding_start + deep_shortcut_icon_size + 10dp -->
<dimen name="deep_shortcuts_text_padding_start">52dp</dimen>
- <dimen name="system_shortcut_icon_size">24dp</dimen>
+ <dimen name="system_shortcut_icon_size">20dp</dimen>
<!-- popup_arrow_horizontal_center_offset - system_shortcut_icon_size / 2 -->
<dimen name="system_shortcut_margin_start">16dp</dimen>
<dimen name="system_shortcut_header_height">56dp</dimen>
<dimen name="system_shortcut_header_icon_touch_size">48dp</dimen>
- <!-- (touch_size - icon_size) / 2 -->
- <dimen name="system_shortcut_header_icon_padding">12dp</dimen>
+ <!-- (system_shortcut_header_icon_touch_size - system_shortcut_icon_size) / 2 -->
+ <dimen name="system_shortcut_header_icon_padding">14dp</dimen>
<!-- Notifications -->
<dimen name="bg_round_rect_radius">8dp</dimen>
@@ -377,12 +377,13 @@
<dimen name="split_placeholder_size">72dp</dimen>
<dimen name="split_placeholder_inset">16dp</dimen>
<dimen name="split_placeholder_icon_size">44dp</dimen>
- <dimen name="task_menu_width_grid">200dp</dimen>
+ <dimen name="task_menu_width_grid">216dp</dimen>
<!-- Workspace grid visualization parameters -->
- <dimen name="grid_visualization_rounding_radius">22dp</dimen>
- <dimen name="grid_visualization_cell_spacing">6dp</dimen>
+ <dimen name="grid_visualization_rounding_radius">28dp</dimen>
+ <dimen name="grid_visualization_horizontal_cell_spacing">6dp</dimen>
+ <dimen name="grid_visualization_vertical_cell_spacing">6dp</dimen>
<!-- Search results related parameters -->
<dimen name="search_row_icon_size">48dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f699fca..ffa1e3f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -303,6 +303,17 @@
<!-- Title for an app whose download has been started. -->
<string name="app_waiting_download_title"><xliff:g id="name" example="Messenger">%1$s</xliff:g> waiting to install</string>
+
+ <!-- Title shown on the alert dialog prompting the user to update the application in market
+ in order to re-enable the disabled shortcuts -->
+ <string name="dialog_update_title">App update required</string>
+ <!-- Message shown on the alert dialog prompting the user to update the application -->
+ <string name="dialog_update_message">The app for this icon isn\'t updated. You can update manually to re-enable this shortcut, or remove the icon.</string>
+ <!-- Message for the update button in the alert dialog, will bring the user to market -->
+ <string name="dialog_update">Update</string>
+ <!-- Message for the remove button in the alert dialog -->
+ <string name="dialog_remove">Remove</string>
+
<!-- Strings for widgets & more in the popup container/bottom sheet -->
<!-- Accessibility title for the popup containing a list of widgets. [CHAR_LIMIT=50] -->
diff --git a/res/xml/device_profiles.xml b/res/xml/device_profiles.xml
index dd201e5..07ce598 100644
--- a/res/xml/device_profiles.xml
+++ b/res/xml/device_profiles.xml
@@ -145,6 +145,8 @@
launcher:numFolderColumns="3"
launcher:numHotseatIcons="6"
launcher:numAllAppsColumns="6"
+ launcher:isScalable="true"
+ launcher:devicePaddingId="@xml/paddings_6x5"
launcher:dbFile="launcher_6_by_5.db"
launcher:defaultLayoutId="@xml/default_workspace_6x5"
launcher:deviceCategory="tablet" >
@@ -153,14 +155,29 @@
launcher:name="Tablet"
launcher:minWidthDps="900"
launcher:minHeightDps="820"
- launcher:minCellHeight="104"
- launcher:minCellWidth="80"
+ launcher:minCellHeight="120"
+ launcher:minCellWidth="102"
+ launcher:minCellHeightLandscape="104"
+ launcher:minCellWidthLandscape="120"
launcher:iconImageSize="60"
launcher:iconTextSize="14"
- launcher:borderSpace="16"
+ launcher:borderSpaceHorizontal="16"
+ launcher:borderSpaceVertical="64"
+ launcher:borderSpaceLandscapeHorizontal="64"
+ launcher:borderSpaceLandscapeVertical="16"
+ launcher:horizontalMargin="54"
+ launcher:horizontalMarginLandscape="120"
+ launcher:allAppsCellWidth="96"
+ launcher:allAppsCellHeight="142"
+ launcher:allAppsCellWidthLandscape="126"
+ launcher:allAppsCellHeightLandscape="126"
launcher:allAppsIconSize="60"
launcher:allAppsIconTextSize="14"
- launcher:allAppsBorderSpace="16"
+ launcher:allAppsBorderSpaceHorizontal="8"
+ launcher:allAppsBorderSpaceVertical="16"
+ launcher:allAppsBorderSpaceLandscape="16"
+ launcher:hotseatBorderSpace="58"
+ launcher:hotseatBorderSpaceLandscape="50.4"
launcher:canBeDefault="true" />
</grid-option>
diff --git a/res/xml/paddings_6x5.xml b/res/xml/paddings_6x5.xml
new file mode 100644
index 0000000..a958ec7
--- /dev/null
+++ b/res/xml/paddings_6x5.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<device-paddings xmlns:launcher="http://schemas.android.com/apk/res-auto" >
+
+ <!-- Some non default screen sizes -->
+ <device-padding
+ launcher:maxEmptySpace="30dp">
+ <workspaceTopPadding
+ launcher:a="0.34"
+ launcher:b="0"/>
+ <workspaceBottomPadding
+ launcher:a="0.26"
+ launcher:b="0"/>
+ <hotseatBottomPadding
+ launcher:a="0.4"
+ launcher:b="0"/>
+ </device-padding>
+
+ <device-padding
+ launcher:maxEmptySpace="80dp">
+ <workspaceTopPadding
+ launcher:a="0"
+ launcher:b="20dp"/>
+ <workspaceBottomPadding
+ launcher:a="0.4"
+ launcher:b="0"
+ launcher:c="20dp"/>
+ <hotseatBottomPadding
+ launcher:a="0.6"
+ launcher:b="0"
+ launcher:c="20dp"/>
+ </device-padding>
+
+ <device-padding
+ launcher:maxEmptySpace="280dp">
+ <workspaceTopPadding
+ launcher:a="0"
+ launcher:b="112dp"/>
+ <workspaceBottomPadding
+ launcher:a="0.4"
+ launcher:b="0"
+ launcher:c="112dp"/>
+ <hotseatBottomPadding
+ launcher:a="0.6"
+ launcher:b="0"
+ launcher:c="112dp"/>
+ </device-padding>
+
+ <device-padding
+ launcher:maxEmptySpace="9999dp">
+ <workspaceTopPadding
+ launcher:a="0.40"
+ launcher:c="36dp"/>
+ <workspaceBottomPadding
+ launcher:a="0.60"
+ launcher:c="36dp"/>
+ <hotseatBottomPadding
+ launcher:a="0"
+ launcher:b="36dp"/>
+ </device-padding>
+</device-paddings>
\ No newline at end of file
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 4386f41..90869c2 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -208,6 +208,13 @@
}
/**
+ * Returns whether there is at least one view of the given type where {@link #isOpen()} == true.
+ */
+ public static boolean hasOpenView(ActivityContext activity, @FloatingViewType int type) {
+ return getOpenView(activity, type) != null;
+ }
+
+ /**
* Returns a view matching FloatingViewType, and {@link #isOpen()} may be false (if animating
* closed).
*/
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 300f22b..4b4a017 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -383,7 +383,7 @@
// Handle invalid resize across CellLayouts in the two panel UI.
if (mCellLayout.getParent() instanceof Workspace) {
- Workspace workspace = (Workspace) mCellLayout.getParent();
+ Workspace<?> workspace = (Workspace<?>) mCellLayout.getParent();
CellLayout pairedCellLayout = workspace.getScreenPair(mCellLayout);
if (pairedCellLayout != null) {
Rect focusedCellLayoutBound = sTmpRect;
@@ -570,7 +570,7 @@
final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
final CellLayout pairedCellLayout;
if (mCellLayout.getParent() instanceof Workspace) {
- Workspace workspace = (Workspace) mCellLayout.getParent();
+ Workspace<?> workspace = (Workspace<?>) mCellLayout.getParent();
pairedCellLayout = workspace.getScreenPair(mCellLayout);
} else {
pairedCellLayout = null;
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index d235180..87bbac6 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -148,7 +148,8 @@
private boolean mVisualizeDropLocation = true;
private RectF mVisualizeGridRect = new RectF();
private Paint mVisualizeGridPaint = new Paint();
- private int mGridVisualizationPadding;
+ private int mGridVisualizationPaddingX;
+ private int mGridVisualizationPaddingY;
private int mGridVisualizationRoundingRadius;
private float mGridAlpha = 0f;
private int mGridColor = 0;
@@ -260,8 +261,10 @@
mBackground.setAlpha(0);
mGridColor = Themes.getAttrColor(getContext(), R.attr.workspaceAccentColor);
- mGridVisualizationPadding =
- res.getDimensionPixelSize(R.dimen.grid_visualization_cell_spacing);
+ mGridVisualizationPaddingX = res.getDimensionPixelSize(
+ R.dimen.grid_visualization_horizontal_cell_spacing);
+ mGridVisualizationPaddingY = res.getDimensionPixelSize(
+ R.dimen.grid_visualization_vertical_cell_spacing);
mGridVisualizationRoundingRadius =
res.getDimensionPixelSize(R.dimen.grid_visualization_rounding_radius);
mReorderPreviewAnimationMagnitude = (REORDER_PREVIEW_MAGNITUDE * deviceProfile.iconSizePx);
@@ -591,8 +594,8 @@
protected void visualizeGrid(Canvas canvas) {
DeviceProfile dp = mActivity.getDeviceProfile();
- int paddingX = (int) Math.min((mCellWidth - dp.iconSizePx) / 2, mGridVisualizationPadding);
- int paddingY = (int) Math.min((mCellHeight - dp.iconSizePx) / 2, mGridVisualizationPadding);
+ int paddingX = Math.min((mCellWidth - dp.iconSizePx) / 2, mGridVisualizationPaddingX);
+ int paddingY = Math.min((mCellHeight - dp.iconSizePx) / 2, mGridVisualizationPaddingY);
mVisualizeGridRect.set(paddingX, paddingY,
mCellWidth - paddingX,
mCellHeight - paddingY);
@@ -1200,7 +1203,7 @@
return getContext().getString(R.string.move_to_hotseat_position,
Math.max(cellX, cellY) + 1);
} else {
- Workspace workspace = getWorkspace();
+ Workspace<?> workspace = getWorkspace();
int row = cellY + 1;
int col = workspace.mIsRtl ? mCountX - cellX : cellX + 1;
int panelCount = workspace.getPanelCount();
@@ -1214,7 +1217,7 @@
}
}
- private Workspace getWorkspace() {
+ private Workspace<?> getWorkspace() {
return Launcher.cast(mActivity).getWorkspace();
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 72d0f59..33bb0a5 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -928,6 +928,13 @@
return workspaceSpringLoadShrunkBottom;
}
+ /**
+ * Gets the minimum visible amount of the next workspace page when in the spring-loaded state.
+ */
+ public float getWorkspaceSpringLoadedMinimumNextPageVisible() {
+ return getCellSize().x / 2f;
+ }
+
public int getWorkspaceWidth() {
return getWorkspaceWidth(getTotalWorkspacePadding());
}
@@ -1015,29 +1022,32 @@
mInsets.right + hotseatBarSidePaddingStartPx, paddingBottom);
}
} else if (isTaskbarPresent) {
+ boolean isRtl = Utilities.isRtl(context.getResources());
int hotseatHeight = workspacePadding.bottom;
int taskbarOffset = getTaskbarOffsetY();
- int additionalLeftSpace = 0;
+ // Push icons to the side
+ int additionalQsbSpace = isQsbInline ? qsbWidth + hotseatBorderSpace : 0;
- // Center the QSB with hotseat and push icons to the right
- if (isQsbInline) {
- additionalLeftSpace = qsbWidth + hotseatBorderSpace;
- }
-
+ // Center the QSB vertically with hotseat
int hotseatTopPadding = hotseatHeight - taskbarOffset - hotseatCellHeightPx;
int endOffset = ApiWrapper.getHotseatEndOffset(context);
int requiredWidth = iconSizePx * numShownHotseatIcons
+ hotseatBorderSpace * (numShownHotseatIcons - 1)
- + additionalLeftSpace;
+ + additionalQsbSpace;
- int hotseatSize = Math.min(requiredWidth, availableWidthPx - endOffset);
- int sideSpacing = (availableWidthPx - hotseatSize) / 2;
- mHotseatPadding.set(sideSpacing + additionalLeftSpace, hotseatTopPadding, sideSpacing,
- taskbarOffset);
+ int hotseatWidth = Math.min(requiredWidth, availableWidthPx - endOffset);
+ int sideSpacing = (availableWidthPx - hotseatWidth) / 2;
+ mHotseatPadding.set(sideSpacing, hotseatTopPadding, sideSpacing, taskbarOffset);
+
+ if (isRtl) {
+ mHotseatPadding.right += additionalQsbSpace;
+ } else {
+ mHotseatPadding.left += additionalQsbSpace;
+ }
if (endOffset > sideSpacing) {
- int diff = Utilities.isRtl(context.getResources())
+ int diff = isRtl
? sideSpacing - endOffset
: endOffset - sideSpacing;
mHotseatPadding.left -= diff;
@@ -1087,7 +1097,7 @@
*/
public int getTaskbarOffsetY() {
if (isQsbInline) {
- return getQsbOffsetY() + (Math.abs(hotseatQsbHeight - iconSizePx) / 2);
+ return getQsbOffsetY() - (Math.abs(hotseatQsbHeight - hotseatCellHeightPx) / 2);
} else {
return (getQsbOffsetY() - taskbarSize) / 2;
}
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index b94cdbf..ec3629d 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -179,7 +179,7 @@
}
Launcher launcher = Launcher.getLauncher(getContext());
- Workspace workspace = launcher.getWorkspace();
+ Workspace<?> workspace = launcher.getWorkspace();
DeviceProfile dp = launcher.getDeviceProfile();
int buttonHorizontalPadding = dp.dropTargetHorizontalPaddingPx;
int buttonVerticalPadding = dp.dropTargetVerticalPaddingPx;
@@ -252,8 +252,7 @@
int overlap = start + leftButton.getMeasuredWidth() + rightButton.getMeasuredWidth()
- end;
if (overlap > 0) {
- start -= overlap / 2;
- end += overlap / 2;
+ end += overlap;
}
leftButton.layout(start, 0, start + leftButton.getMeasuredWidth(),
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java
similarity index 95%
rename from src/com/android/launcher3/BaseRecyclerView.java
rename to src/com/android/launcher3/FastScrollRecyclerView.java
index 9369bdc..a60d143 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/FastScrollRecyclerView.java
@@ -37,19 +37,19 @@
* <li> Enable fast scroller.
* </ul>
*/
-public abstract class BaseRecyclerView extends RecyclerView {
+public abstract class FastScrollRecyclerView extends RecyclerView {
protected RecyclerViewFastScroller mScrollbar;
- public BaseRecyclerView(Context context) {
+ public FastScrollRecyclerView(Context context) {
this(context, null);
}
- public BaseRecyclerView(Context context, AttributeSet attrs) {
+ public FastScrollRecyclerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
- public BaseRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
+ public FastScrollRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@@ -206,4 +206,4 @@
}
scrollToPosition(0);
}
-}
\ No newline at end of file
+}
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 9c749aa7..a9db5ce 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -41,7 +41,7 @@
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mHasVerticalHotseat;
- private Workspace mWorkspace;
+ private Workspace<?> mWorkspace;
private boolean mSendTouchToWorkspace;
@Nullable
private Consumer<Boolean> mOnVisibilityAggregatedCallback;
@@ -122,7 +122,7 @@
InsettableFrameLayout.dispatchInsets(this, insets);
}
- public void setWorkspace(Workspace w) {
+ public void setWorkspace(Workspace<?> w) {
mWorkspace = w;
}
@@ -195,7 +195,8 @@
int left;
if (mActivity.getDeviceProfile().isQsbInline) {
int qsbSpace = mActivity.getDeviceProfile().hotseatBorderSpace;
- left = l + getPaddingLeft() - qsbWidth - qsbSpace;
+ left = Utilities.isRtl(getResources()) ? r - getPaddingRight() + qsbSpace
+ : l + getPaddingLeft() - qsbWidth - qsbSpace;
} else {
left = (r - l - qsbWidth) / 2;
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 3cc8a81..463280b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -16,6 +16,8 @@
package com.android.launcher3;
+import static android.app.PendingIntent.FLAG_IMMUTABLE;
+import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
@@ -40,7 +42,6 @@
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
-import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD;
import static com.android.launcher3.logging.StatsLogManager.EventEnum;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
@@ -63,7 +64,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.Notification;
@@ -107,7 +107,7 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnPreDrawListener;
import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
@@ -128,7 +128,6 @@
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.BaseAllAppsContainerView;
import com.android.launcher3.allapps.DiscoveryBounce;
-import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
@@ -184,8 +183,6 @@
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.MultiValueAlpha;
-import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
@@ -339,6 +336,7 @@
private Runnable mOnDeferredActivityLaunchCallback;
private ViewOnDrawExecutor mPendingExecutor;
+ private OnPreDrawListener mOnInitialBindListener;
private LauncherModel mModel;
private ModelWriter mModelWriter;
@@ -434,8 +432,7 @@
shareIntent.putExtra(Intent.EXTRA_TEXT, stackTrace);
shareIntent = Intent.createChooser(shareIntent, null);
PendingIntent sharePendingIntent = PendingIntent.getActivity(
- this, 0, shareIntent, PendingIntent.FLAG_UPDATE_CURRENT
- );
+ this, 0, shareIntent, FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE);
Notification notification = new Notification.Builder(this, notificationChannelId)
.setSmallIcon(android.R.drawable.ic_menu_close_clear_cancel)
@@ -502,11 +499,10 @@
if (!mModel.addCallbacksAndLoad(this)) {
if (!internalStateHandled) {
- Log.d(BAD_STATE, "Launcher onCreate not binding sync, setting DragLayer alpha "
- + "ALPHA_INDEX_LAUNCHER_LOAD to 0");
- // If we are not binding synchronously, show a fade in animation when
- // the first page bind completes.
- mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD).setValue(0);
+ Log.d(BAD_STATE, "Launcher onCreate not binding sync, prevent drawing");
+ // If we are not binding synchronously, pause drawing until initial bind complete,
+ // so that the system could continue to show the device loading prompt
+ mOnInitialBindListener = Boolean.FALSE::booleanValue;
}
}
@@ -514,25 +510,9 @@
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
setContentView(getRootView());
- getRootView().getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- // Checks the status of fade in animation.
- final AlphaProperty property =
- mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD);
- if (property.getValue() == 0) {
- Log.d(BAD_STATE, "Launcher onPreDraw ALPHA_INDEX_LAUNCHER_LOAD not"
- + " started yet, cancelling draw.");
- // Animation haven't started yet; suspend.
- return false;
- } else {
- // The animation is started; start drawing.
- getRootView().getViewTreeObserver().removeOnPreDrawListener(this);
- return true;
- }
- }
- });
+ if (mOnInitialBindListener != null) {
+ getRootView().getViewTreeObserver().addOnPreDrawListener(mOnInitialBindListener);
+ }
getRootView().dispatchInsets();
// Listen for broadcasts
@@ -2360,7 +2340,7 @@
// Get the list of added items and intersect them with the set of items here
final Collection<Animator> bounceAnims = new ArrayList<>();
boolean canAnimatePageChange = canAnimatePageChange();
- Workspace workspace = mWorkspace;
+ Workspace<?> workspace = mWorkspace;
int newItemsScreenId = -1;
int end = items.size();
View newView = null;
@@ -2691,36 +2671,12 @@
AllAppsStore.DEFER_UPDATES_NEXT_DRAW));
}
- AlphaProperty property = mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD);
- if (property.getValue() < 1) {
- ObjectAnimator anim = ObjectAnimator.ofFloat(property, MultiValueAlpha.VALUE, 1);
-
- Log.d(BAD_STATE, "Launcher onInitialBindComplete toAlpha=" + 1);
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- Log.d(BAD_STATE, "Launcher onInitialBindComplete onStart");
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- float alpha = mDragLayer == null
- ? -1
- : mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD).getValue();
- Log.d(BAD_STATE, "Launcher onInitialBindComplete onCancel, alpha=" + alpha);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- Log.d(BAD_STATE, "Launcher onInitialBindComplete onEnd");
- }
- });
-
- anim.addListener(AnimatorListeners.forEndCallback(executor::onLoadAnimationCompleted));
- anim.start();
- } else {
- executor.onLoadAnimationCompleted();
+ if (mOnInitialBindListener != null) {
+ getRootView().getViewTreeObserver().removeOnPreDrawListener(mOnInitialBindListener);
+ mOnInitialBindListener = null;
}
+
+ executor.onLoadAnimationCompleted();
executor.attachTo(this);
if (Utilities.ATLEAST_S) {
Trace.endAsyncSection(DISPLAY_WORKSPACE_TRACE_METHOD_NAME,
@@ -2794,7 +2750,7 @@
packageName);
if (supportsAllAppsState && isInState(LauncherState.ALL_APPS)) {
- return getFirstMatch(Collections.singletonList(mAppsView.getActiveRecyclerView()),
+ return getFirstMatch(Collections.singletonList(mAppsView.getActiveAppsRecyclerView()),
preferredItem, packageAndUserAndApp);
} else {
List<ViewGroup> containers = new ArrayList<>(mWorkspace.getPanelCount() + 1);
@@ -3234,12 +3190,12 @@
/** Pauses view updates that should not be run during the app launch animation. */
public void pauseExpensiveViewUpdates() {
// Pause page indicator animations as they lead to layer trashing.
- mWorkspace.getPageIndicator().pauseAnimations();
+ getWorkspace().getPageIndicator().pauseAnimations();
}
/** Resumes view updates at the end of the app launch animation. */
public void resumeExpensiveViewUpdates() {
- mWorkspace.getPageIndicator().skipAnimationsToEnd();
+ getWorkspace().getPageIndicator().skipAnimationsToEnd();
}
}
diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java
index 4f3ae59..808bf96 100644
--- a/src/com/android/launcher3/LauncherAnimUtils.java
+++ b/src/com/android/launcher3/LauncherAnimUtils.java
@@ -72,8 +72,8 @@
* of all the ones set, to have a smooth experience even in the case of overlapping scaling
* animation.
*/
- public static final MultiScalePropertyFactory<Workspace> WORKSPACE_SCALE_PROPERTY_FACTORY =
- new MultiScalePropertyFactory<Workspace>("workspace_scale_property");
+ public static final MultiScalePropertyFactory<Workspace<?>> WORKSPACE_SCALE_PROPERTY_FACTORY =
+ new MultiScalePropertyFactory<Workspace<?>>("workspace_scale_property");
/** Property to set the scale of hotseat. */
public static final MultiScalePropertyFactory<Hotseat> HOTSEAT_SCALE_PROPERTY_FACTORY =
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 1eb493b..0a1d25c 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1195,8 +1195,8 @@
mAllowOverScroll = enable;
}
- protected float getSignificantMoveThreshold() {
- return SIGNIFICANT_MOVE_THRESHOLD;
+ protected boolean isSignificantMove(float absoluteDelta, int pageOrientedSize) {
+ return absoluteDelta > pageOrientedSize * SIGNIFICANT_MOVE_THRESHOLD;
}
@Override
@@ -1322,13 +1322,12 @@
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int velocity = (int) mOrientationHandler.getPrimaryVelocity(velocityTracker,
- mActivePointerId);
+ mActivePointerId);
float delta = primaryDirection - mDownMotionPrimary;
- delta /= mOrientationHandler.getPrimaryScale(this);
- int pageOrientedSize = mOrientationHandler.getMeasuredSize(getPageAt(mCurrentPage));
-
- boolean isSignificantMove = Math.abs(delta)
- > pageOrientedSize * getSignificantMoveThreshold();
+ int pageOrientedSize = (int) (mOrientationHandler.getMeasuredSize(
+ getPageAt(mCurrentPage))
+ * mOrientationHandler.getPrimaryScale(this));
+ boolean isSignificantMove = isSignificantMove(Math.abs(delta), pageOrientedSize);
mTotalMotion += Math.abs(mLastMotion + mLastMotionRemainder - primaryDirection);
boolean passedSlop = mAllowEasyFling || mTotalMotion > mPageSlop;
@@ -1441,7 +1440,7 @@
return Math.abs(velocity) > threshold;
}
- private void resetTouchState() {
+ protected void resetTouchState() {
releaseVelocityTracker();
mIsBeingDragged = false;
mActivePointerId = INVALID_POINTER;
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 9241c45..8358f2a 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -53,6 +53,7 @@
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
+import android.os.Build.VERSION_CODES;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.Message;
@@ -72,9 +73,9 @@
import android.view.animation.Interpolator;
import android.widget.LinearLayout;
+import androidx.annotation.ChecksSdkIntAtLeast;
import androidx.annotation.NonNull;
import androidx.core.graphics.ColorUtils;
-import androidx.core.os.BuildCompat;
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
import com.android.launcher3.graphics.GridCustomizationsProvider;
@@ -122,15 +123,20 @@
public static final String[] EMPTY_STRING_ARRAY = new String[0];
public static final Person[] EMPTY_PERSON_ARRAY = new Person[0];
+ @ChecksSdkIntAtLeast(api = VERSION_CODES.P)
public static final boolean ATLEAST_P = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
+ @ChecksSdkIntAtLeast(api = VERSION_CODES.Q)
public static final boolean ATLEAST_Q = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
+ @ChecksSdkIntAtLeast(api = VERSION_CODES.R)
public static final boolean ATLEAST_R = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R;
+ @ChecksSdkIntAtLeast(api = VERSION_CODES.S)
public static final boolean ATLEAST_S = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
- public static final boolean ATLEAST_T = BuildCompat.isAtLeastT();
+ @ChecksSdkIntAtLeast(api = VERSION_CODES.TIRAMISU, codename = "T")
+ public static final boolean ATLEAST_T = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU;
/**
* Set on a motion event dispatched from the nav bar. See {@link MotionEvent#setEdgeFlags(int)}.
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 61090e7..ed01660 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -50,7 +50,6 @@
import android.os.Handler;
import android.os.Message;
import android.os.Parcelable;
-import android.os.UserHandle;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
@@ -123,7 +122,6 @@
import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
@@ -149,6 +147,8 @@
* {@link #isFinishedSwitchingState()} ()} to return true. */
private static final float FINISHED_SWITCHING_STATE_TRANSITION_PROGRESS = 0.5f;
+ private static final float SIGNIFICANT_MOVE_SCREEN_WIDTH_PERCENTAGE = 0.15f;
+
private static final boolean ENFORCE_DRAG_EVENT_ORDER = false;
private static final int ADJACENT_SCREEN_DROP_DURATION = 300;
@@ -3295,9 +3295,12 @@
}
}
- public void removeAbandonedPromise(String packageName, UserHandle user) {
- ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(
- Collections.singleton(packageName), user);
+ /**
+ * Remove workspace icons & widget information related to items in matcher.
+ *
+ * @param matcher the matcher generated by the caller.
+ */
+ public void persistRemoveItemsByMatcher(ItemInfoMatcher matcher) {
mLauncher.getModelWriter().deleteItemsFromDatabase(matcher);
removeItemsByMatcher(matcher);
}
@@ -3410,6 +3413,17 @@
return getContext().getString(R.string.workspace_scroll_format, currentPage, totalPages);
}
+ @Override
+ protected boolean isSignificantMove(float absoluteDelta, int pageOrientedSize) {
+ DeviceProfile deviceProfile = mLauncher.getDeviceProfile();
+ if (!deviceProfile.isTablet) {
+ return super.isSignificantMove(absoluteDelta, pageOrientedSize);
+ }
+
+ return absoluteDelta
+ > deviceProfile.availableWidthPx * SIGNIFICANT_MOVE_SCREEN_WIDTH_PERCENTAGE;
+ }
+
/**
* Used as a workaround to ensure that the AppWidgetService receives the
* PACKAGE_ADDED broadcast before updating widgets.
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 1e09b2d..84b95ec 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -67,18 +67,18 @@
*/
public class WorkspaceStateTransitionAnimation {
- private static final FloatProperty<Workspace> WORKSPACE_SCALE_PROPERTY =
+ private static final FloatProperty<Workspace<?>> WORKSPACE_SCALE_PROPERTY =
WORKSPACE_SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_WORKSPACE_STATE);
private static final FloatProperty<Hotseat> HOTSEAT_SCALE_PROPERTY =
HOTSEAT_SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_WORKSPACE_STATE);
private final Launcher mLauncher;
- private final Workspace mWorkspace;
+ private final Workspace<?> mWorkspace;
private float mNewScale;
- public WorkspaceStateTransitionAnimation(Launcher launcher, Workspace workspace) {
+ public WorkspaceStateTransitionAnimation(Launcher launcher, Workspace<?> workspace) {
mLauncher = launcher;
mWorkspace = workspace;
}
@@ -224,7 +224,7 @@
* Returns a spring based animator for the scale property of {@param workspace}.
*/
public static ValueAnimator getWorkspaceSpringScaleAnimator(Launcher launcher,
- Workspace workspace, float scale) {
+ Workspace<?> workspace, float scale) {
return getSpringScaleAnimator(launcher, workspace, scale, WORKSPACE_SCALE_PROPERTY);
}
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 18c05eb..12eb837 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -19,7 +19,7 @@
import com.android.launcher3.ButtonDropTarget;
import com.android.launcher3.CellLayout;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.LauncherSettings;
import com.android.launcher3.PendingAddItemInfo;
import com.android.launcher3.R;
import com.android.launcher3.Workspace;
@@ -153,61 +153,9 @@
} else if (action == MOVE) {
return beginAccessibleDrag(host, item, fromKeyboard);
} else if (action == ADD_TO_WORKSPACE) {
- final int[] coordinates = new int[2];
- final int screenId = findSpaceOnWorkspace(item, coordinates);
- if (screenId == -1) {
- return false;
- }
- mContext.getStateManager().goToState(NORMAL, true, forSuccessCallback(() -> {
- if (item instanceof AppInfo) {
- WorkspaceItemInfo info = ((AppInfo) item).makeWorkspaceItem();
- mContext.getModelWriter().addItemToDatabase(info,
- Favorites.CONTAINER_DESKTOP,
- screenId, coordinates[0], coordinates[1]);
-
- mContext.bindItems(
- Collections.singletonList(info),
- /* forceAnimateIcons= */ true,
- /* focusFirstItemForAccessibility= */ true);
- announceConfirmation(R.string.item_added_to_workspace);
- } else if (item instanceof PendingAddItemInfo) {
- PendingAddItemInfo info = (PendingAddItemInfo) item;
- Workspace workspace = mContext.getWorkspace();
- workspace.snapToPage(workspace.getPageIndexForScreenId(screenId));
- mContext.addPendingItem(info, Favorites.CONTAINER_DESKTOP,
- screenId, coordinates, info.spanX, info.spanY);
- }
- else if (item instanceof WorkspaceItemInfo) {
- WorkspaceItemInfo info = ((WorkspaceItemInfo) item).clone();
- mContext.getModelWriter().addItemToDatabase(info,
- Favorites.CONTAINER_DESKTOP,
- screenId, coordinates[0], coordinates[1]);
- mContext.bindItems(Collections.singletonList(info), true, true);
- }
- }));
- return true;
+ return addToWorkspace(item, true);
} else if (action == MOVE_TO_WORKSPACE) {
- Folder folder = Folder.getOpen(mContext);
- folder.close(true);
- WorkspaceItemInfo info = (WorkspaceItemInfo) item;
- folder.getInfo().remove(info, false);
-
- final int[] coordinates = new int[2];
- final int screenId = findSpaceOnWorkspace(item, coordinates);
- if (screenId == -1) {
- return false;
- }
- mContext.getModelWriter().moveItemInDatabase(info,
- Favorites.CONTAINER_DESKTOP,
- screenId, coordinates[0], coordinates[1]);
-
- // Bind the item in next frame so that if a new workspace page was created,
- // it will get laid out.
- new Handler().post(() -> {
- mContext.bindItems(Collections.singletonList(item), true);
- announceConfirmation(R.string.item_moved);
- });
- return true;
+ return moveToWorkspace(item);
} else if (action == RESIZE) {
final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) item;
List<OptionItem> actions = getSupportedResizeActions(host, info);
@@ -365,7 +313,7 @@
* Find empty space on the workspace and returns the screenId.
*/
protected int findSpaceOnWorkspace(ItemInfo info, int[] outCoordinates) {
- Workspace workspace = mContext.getWorkspace();
+ Workspace<?> workspace = mContext.getWorkspace();
IntArray workspaceScreens = workspace.getScreenOrder();
int screenId;
@@ -403,4 +351,76 @@
}
return screenId;
}
+
+ /**
+ * Functionality to add the item {@link ItemInfo} to the workspace
+ * @param item item to be added
+ * @param accessibility true if the first item to be added to the workspace
+ * should be focused for accessibility.
+ *
+ * @return true if the item could be successfully added
+ */
+ public boolean addToWorkspace(ItemInfo item, boolean accessibility) {
+ final int[] coordinates = new int[2];
+ final int screenId = findSpaceOnWorkspace(item, coordinates);
+ if (screenId == -1) {
+ return false;
+ }
+ mContext.getStateManager().goToState(NORMAL, true, forSuccessCallback(() -> {
+ if (item instanceof AppInfo) {
+ WorkspaceItemInfo info = ((AppInfo) item).makeWorkspaceItem();
+ mContext.getModelWriter().addItemToDatabase(info,
+ LauncherSettings.Favorites.CONTAINER_DESKTOP,
+ screenId, coordinates[0], coordinates[1]);
+
+ mContext.bindItems(
+ Collections.singletonList(info),
+ /* forceAnimateIcons= */ true,
+ /* focusFirstItemForAccessibility= */ accessibility);
+ announceConfirmation(R.string.item_added_to_workspace);
+ } else if (item instanceof PendingAddItemInfo) {
+ PendingAddItemInfo info = (PendingAddItemInfo) item;
+ Workspace<?> workspace = mContext.getWorkspace();
+ workspace.snapToPage(workspace.getPageIndexForScreenId(screenId));
+ mContext.addPendingItem(info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
+ screenId, coordinates, info.spanX, info.spanY);
+ } else if (item instanceof WorkspaceItemInfo) {
+ WorkspaceItemInfo info = ((WorkspaceItemInfo) item).clone();
+ mContext.getModelWriter().addItemToDatabase(info,
+ LauncherSettings.Favorites.CONTAINER_DESKTOP,
+ screenId, coordinates[0], coordinates[1]);
+ mContext.bindItems(Collections.singletonList(info), true, accessibility);
+ }
+ }));
+ return true;
+ }
+ /**
+ * Functionality to move the item {@link ItemInfo} to the workspace
+ * @param item item to be moved
+ *
+ * @return true if the item could be successfully added
+ */
+ public boolean moveToWorkspace(ItemInfo item) {
+ Folder folder = Folder.getOpen(mContext);
+ folder.close(true);
+ WorkspaceItemInfo info = (WorkspaceItemInfo) item;
+ folder.getInfo().remove(info, false);
+
+ final int[] coordinates = new int[2];
+ final int screenId = findSpaceOnWorkspace(item, coordinates);
+ if (screenId == -1) {
+ return false;
+ }
+ mContext.getModelWriter().moveItemInDatabase(info,
+ LauncherSettings.Favorites.CONTAINER_DESKTOP,
+ screenId, coordinates[0], coordinates[1]);
+
+ // Bind the item in next frame so that if a new workspace page was created,
+ // it will get laid out.
+ new Handler().post(() -> {
+ mContext.bindItems(Collections.singletonList(item), true);
+ announceConfirmation(R.string.item_moved);
+ });
+ return true;
+ }
}
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index e279f59..16a2823 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -80,7 +80,7 @@
OnClickListener marketSearchClickListener = (v) -> mActivityContext.startActivitySafely(v,
marketSearchIntent, null);
for (int i = 0; i < mAH.size(); i++) {
- mAH.get(i).adapter.setLastSearchQuery(query, marketSearchClickListener);
+ mAH.get(i).mAdapter.setLastSearchQuery(query, marketSearchClickListener);
}
mIsSearching = true;
rebindAdapters();
@@ -142,7 +142,7 @@
@Override
public String getDescription() {
- if (!mUsingTabs && mIsSearching) {
+ if (!mUsingTabs && isSearching()) {
return getContext().getString(R.string.all_apps_search_results);
} else {
return super.getDescription();
@@ -150,8 +150,13 @@
}
@Override
- protected boolean showTabs() {
- return super.showTabs() && !mIsSearching;
+ protected boolean shouldShowTabs() {
+ return super.shouldShowTabs() && !isSearching();
+ }
+
+ @Override
+ public boolean isSearching() {
+ return mIsSearching;
}
@Override
@@ -173,15 +178,19 @@
}
@Override
- protected View replaceRVContainer(boolean showTabs) {
- View rvContainer = super.replaceRVContainer(showTabs);
+ protected View replaceAppsRVContainer(boolean showTabs) {
+ View rvContainer = super.replaceAppsRVContainer(showTabs);
removeCustomRules(rvContainer);
+ removeCustomRules(getSearchRecyclerView());
if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
alignParentTop(rvContainer, showTabs);
+ alignParentTop(getSearchRecyclerView(), showTabs);
layoutAboveSearchContainer(rvContainer);
+ layoutAboveSearchContainer(getSearchRecyclerView());
} else {
layoutBelowSearchContainer(rvContainer, showTabs);
+ layoutBelowSearchContainer(getSearchRecyclerView(), showTabs);
}
return rvContainer;
@@ -208,7 +217,7 @@
float prog = Utilities.boundToRange((float) scrolledOffset / mHeaderThreshold, 0f, 1f);
boolean bgVisible = mSearchUiManager.getBackgroundVisibility();
- if (scrolledOffset == 0 && !mIsSearching) {
+ if (scrolledOffset == 0 && !isSearching()) {
bgVisible = true;
} else if (scrolledOffset > mHeaderThreshold) {
bgVisible = false;
@@ -242,7 +251,7 @@
int topMargin = getContext().getResources().getDimensionPixelSize(
R.dimen.all_apps_header_top_margin);
if (includeTabsMargin) {
- topMargin = topMargin + getContext().getResources().getDimensionPixelSize(
+ topMargin += getContext().getResources().getDimensionPixelSize(
R.dimen.all_apps_header_pill_height);
}
layoutParams.topMargin = topMargin;
@@ -283,9 +292,9 @@
}
@Override
- protected BaseAllAppsAdapter getAdapter(AlphabeticalAppsList<T> mAppsList,
+ protected BaseAllAppsAdapter<T> createAdapter(AlphabeticalAppsList<T> appsList,
BaseAdapterProvider[] adapterProviders) {
- return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), mAppsList,
+ return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), appsList,
adapterProviders);
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 7dbe711..18c6788 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -37,8 +37,8 @@
import androidx.recyclerview.widget.RecyclerView;
-import com.android.launcher3.BaseRecyclerView;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.FastScrollRecyclerView;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -53,13 +53,13 @@
/**
* A RecyclerView with custom fast scroll support for the all apps view.
*/
-public class AllAppsRecyclerView extends BaseRecyclerView {
- private static final String TAG = "AllAppsContainerView";
+public class AllAppsRecyclerView extends FastScrollRecyclerView {
+ protected static final String TAG = "AllAppsRecyclerView";
private static final boolean DEBUG = false;
private static final boolean DEBUG_LATENCY = Utilities.isPropertyEnabled(SEARCH_LOGGING);
- private AlphabeticalAppsList<?> mApps;
- private final int mNumAppsPerRow;
+ protected AlphabeticalAppsList<?> mApps;
+ protected final int mNumAppsPerRow;
// The specific view heights that we use to calculate scroll
private final SparseIntArray mViewHeights = new SparseIntArray();
@@ -74,8 +74,8 @@
};
// The empty-search result background
- private AllAppsBackgroundDrawable mEmptySearchBackground;
- private int mEmptySearchBackgroundTopOffset;
+ protected AllAppsBackgroundDrawable mEmptySearchBackground;
+ protected int mEmptySearchBackgroundTopOffset;
private ArrayList<View> mAutoSizedOverlays = new ArrayList<>();
@@ -112,7 +112,7 @@
return mApps;
}
- private void updatePoolSize() {
+ protected void updatePoolSize() {
DeviceProfile grid = ActivityContext.lookupContext(getContext()).getDeviceProfile();
RecyclerView.RecycledViewPool pool = getRecycledViewPool();
int approxRows = (int) Math.ceil(grid.availableHeightPx / grid.allAppsIconSizePx);
@@ -137,8 +137,8 @@
Log.d(TAG, "onDraw at = " + System.currentTimeMillis());
}
if (DEBUG_LATENCY) {
- Log.d(SEARCH_LOGGING,
- "-- Recycle view onDraw, time stamp = " + System.currentTimeMillis());
+ Log.d(SEARCH_LOGGING, getClass().getSimpleName() + " onDraw; time stamp = "
+ + System.currentTimeMillis());
}
super.onDraw(c);
}
@@ -223,8 +223,7 @@
&& mEmptySearchBackground != null && mEmptySearchBackground.getAlpha() > 0) {
mEmptySearchBackground.setHotspot(e.getX(), e.getY());
}
- hideKeyboardAsync(ActivityContext.lookupContext(getContext()),
- getApplicationWindowToken());
+ hideKeyboardAsync(ActivityContext.lookupContext(getContext()), getApplicationWindowToken());
return result;
}
@@ -360,13 +359,6 @@
}
@Override
- public boolean supportsFastScrolling() {
- // Only allow fast scrolling when the user is not searching, since the results are not
- // grouped in a meaningful order
- return !mApps.hasFilter();
- }
-
- @Override
public int getCurrentScrollY() {
// Return early if there are no items or we haven't been measured
List<AllAppsGridAdapter.AdapterItem> items = mApps.getAdapterItems();
@@ -376,7 +368,7 @@
// Calculate the y and offset for the item
View child = getChildAt(0);
- int position = getChildPosition(child);
+ int position = getChildAdapterPosition(child);
if (position == NO_POSITION) {
return -1;
}
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index cdc313f..723bc65 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -44,6 +44,9 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.util.MultiAdditivePropertyFactory;
+import com.android.launcher3.util.MultiValueAlpha;
+import com.android.launcher3.util.UiThreadHelper;
import com.android.launcher3.views.ScrimView;
/**
@@ -75,6 +78,58 @@
}
};
+ public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PULL_BACK_TRANSLATION =
+ new FloatProperty<AllAppsTransitionController>("allAppsPullBackTranslation") {
+
+ @Override
+ public Float get(AllAppsTransitionController controller) {
+ if (controller.mIsTablet) {
+ return controller.mAppsView.getAppsRecyclerViewContainer()
+ .getTranslationY();
+ } else {
+ return controller.getAppsViewPullbackTranslationY().get(
+ controller.mAppsView);
+ }
+ }
+
+ @Override
+ public void setValue(AllAppsTransitionController controller, float translation) {
+ if (controller.mIsTablet) {
+ controller.mAppsView.getAppsRecyclerViewContainer().setTranslationY(
+ translation);
+ } else {
+ controller.getAppsViewPullbackTranslationY().set(controller.mAppsView,
+ translation);
+ }
+ }
+ };
+
+ public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PULL_BACK_ALPHA =
+ new FloatProperty<AllAppsTransitionController>("allAppsPullBackAlpha") {
+
+ @Override
+ public Float get(AllAppsTransitionController controller) {
+ if (controller.mIsTablet) {
+ return controller.mAppsView.getAppsRecyclerViewContainer().getAlpha();
+ } else {
+ return controller.getAppsViewPullbackAlpha().getValue();
+ }
+ }
+
+ @Override
+ public void setValue(AllAppsTransitionController controller, float alpha) {
+ if (controller.mIsTablet) {
+ controller.mAppsView.getAppsRecyclerViewContainer().setAlpha(alpha);
+ } else {
+ controller.getAppsViewPullbackAlpha().setValue(alpha);
+ }
+ }
+ };
+
+ private static final int INDEX_APPS_VIEW_PROGRESS = 0;
+ private static final int INDEX_APPS_VIEW_PULLBACK = 1;
+ private static final int APPS_VIEW_INDEX_COUNT = 2;
+
private ActivityAllAppsContainerView<Launcher> mAppsView;
private final Launcher mLauncher;
@@ -91,13 +146,20 @@
private ScrimView mScrimView;
+ private final MultiAdditivePropertyFactory<View>
+ mAppsViewTranslationYPropertyFactory = new MultiAdditivePropertyFactory<>(
+ "appsViewTranslationY", View.TRANSLATION_Y);
+ private MultiValueAlpha mAppsViewAlpha;
+
+ private boolean mIsTablet;
+
public AllAppsTransitionController(Launcher l) {
mLauncher = l;
DeviceProfile dp = mLauncher.getDeviceProfile();
setShiftRange(dp.allAppsShiftRange);
mProgress = 1f;
-
mIsVerticalLayout = dp.isVerticalBarLayout();
+ mIsTablet = dp.isTablet;
mLauncher.addOnDeviceProfileChangeListener(this);
}
@@ -114,6 +176,8 @@
mLauncher.getHotseat().setTranslationY(0);
mLauncher.getWorkspace().getPageIndicator().setTranslationY(0);
}
+
+ mIsTablet = dp.isTablet;
}
/**
@@ -126,13 +190,29 @@
*/
public void setProgress(float progress) {
mProgress = progress;
- mAppsView.setTranslationY(mProgress * mShiftRange);
+ getAppsViewProgressTranslationY().set(mAppsView, mProgress * mShiftRange);
}
public float getProgress() {
return mProgress;
}
+ private FloatProperty<View> getAppsViewProgressTranslationY() {
+ return mAppsViewTranslationYPropertyFactory.get(INDEX_APPS_VIEW_PROGRESS);
+ }
+
+ private FloatProperty<View> getAppsViewPullbackTranslationY() {
+ return mAppsViewTranslationYPropertyFactory.get(INDEX_APPS_VIEW_PULLBACK);
+ }
+
+ private MultiValueAlpha.AlphaProperty getAppsViewProgressAlpha() {
+ return mAppsViewAlpha.getProperty(INDEX_APPS_VIEW_PROGRESS);
+ }
+
+ private MultiValueAlpha.AlphaProperty getAppsViewPullbackAlpha() {
+ return mAppsViewAlpha.getProperty(INDEX_APPS_VIEW_PULLBACK);
+ }
+
/**
* Sets the vertical transition progress to {@param state} and updates all the dependent UI
* accordingly.
@@ -151,6 +231,15 @@
@Override
public void setStateWithAnimation(LauncherState toState,
StateAnimationConfig config, PendingAnimation builder) {
+ if (NORMAL.equals(toState) && mLauncher.isInState(ALL_APPS)) {
+ UiThreadHelper.hideKeyboardAsync(mLauncher, mLauncher.getAppsView().getWindowToken());
+ builder.addEndListener(success -> {
+ // Reset pull back progress and alpha after switching states.
+ ALL_APPS_PULL_BACK_TRANSLATION.set(this, 0f);
+ ALL_APPS_PULL_BACK_ALPHA.set(this, 1f);
+ });
+ }
+
float targetProgress = toState.getVerticalProgress(mLauncher);
if (Float.compare(mProgress, targetProgress) == 0) {
setAlphas(toState, config, builder);
@@ -189,7 +278,8 @@
boolean hasAllAppsContent = (visibleElements & ALL_APPS_CONTENT) != 0;
Interpolator allAppsFade = config.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR);
- setter.setViewAlpha(mAppsView, hasAllAppsContent ? 1 : 0, allAppsFade);
+ setter.setFloat(getAppsViewProgressAlpha(), MultiValueAlpha.VALUE,
+ hasAllAppsContent ? 1 : 0, allAppsFade);
boolean shouldProtectHeader =
ALL_APPS == state || mLauncher.getStateManager().getState() == ALL_APPS;
@@ -212,6 +302,8 @@
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
}
mAppsView.setScrimView(scrimView);
+ mAppsViewAlpha = new MultiValueAlpha(mAppsView, APPS_VIEW_INDEX_COUNT);
+ mAppsViewAlpha.setUpdateVisibility(true);
}
/**
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 7687fea..42374b8 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -18,6 +18,8 @@
import android.content.Context;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.AppInfo;
@@ -71,6 +73,7 @@
// The set of apps from the system
private final List<AppInfo> mApps = new ArrayList<>();
+ @Nullable
private final AllAppsStore mAllAppsStore;
// The number of results in current adapter
@@ -88,14 +91,16 @@
private int mNumAppRowsInAdapter;
private ItemInfoMatcher mItemFilter;
- public AlphabeticalAppsList(Context context, AllAppsStore appsStore,
+ public AlphabeticalAppsList(Context context, @Nullable AllAppsStore appsStore,
WorkAdapterProvider adapterProvider) {
mAllAppsStore = appsStore;
mActivityContext = ActivityContext.lookupContext(context);
mAppNameComparator = new AppInfoComparator(context);
mWorkAdapterProvider = adapterProvider;
mNumAppsPerRowAllApps = mActivityContext.getDeviceProfile().inv.numAllAppsColumns;
- mAllAppsStore.addUpdateListener(this);
+ if (mAllAppsStore != null) {
+ mAllAppsStore.addUpdateListener(this);
+ }
}
public void updateItemFilter(ItemInfoMatcher itemFilter) {
@@ -168,9 +173,9 @@
}
/**
- * Returns whether there are is a filter set.
+ * Returns whether there are search results which will hide the A-Z list.
*/
- public boolean hasFilter() {
+ public boolean hasSearchResults() {
return !mSearchResults.isEmpty();
}
@@ -178,7 +183,7 @@
* Returns whether there are no filtered results.
*/
public boolean hasNoFilteredResults() {
- return hasFilter() && mAccessibilityResultsCount == 0;
+ return hasSearchResults() && mAccessibilityResultsCount == 0;
}
/**
@@ -196,13 +201,13 @@
return true;
}
- public boolean appendSearchResults(ArrayList<AdapterItem> results) {
- if (hasFilter() && results != null && results.size() > 0) {
+ /** Appends results to search. */
+ public void appendSearchResults(ArrayList<AdapterItem> results) {
+ if (hasSearchResults() && results != null && results.size() > 0) {
updateSearchAdapterItems(results, mSearchResults.size());
+ mSearchResults.addAll(results);
refreshRecyclerView();
- return true;
}
- return false;
}
void updateSearchAdapterItems(ArrayList<AdapterItem> list, int offset) {
@@ -222,11 +227,14 @@
*/
@Override
public void onAppsUpdated() {
+ if (mAllAppsStore == null) {
+ return;
+ }
// Sort the list of apps
mApps.clear();
for (AppInfo app : mAllAppsStore.getApps()) {
- if (mItemFilter == null || mItemFilter.matches(app, null) || hasFilter()) {
+ if (mItemFilter == null || mItemFilter.matches(app, null) || hasSearchResults()) {
mApps.add(app);
}
}
@@ -296,7 +304,18 @@
// Recreate the filtered and sectioned apps (for convenience for the grid layout) from the
// ordered set of sections
- if (!hasFilter()) {
+ if (hasSearchResults()) {
+ if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
+ // Append the search market item
+ if (hasNoFilteredResults()) {
+ mSearchResults.add(AdapterItem.asEmptySearch(position++));
+ } else {
+ mSearchResults.add(AdapterItem.asAllAppsDivider(position++));
+ }
+ mSearchResults.add(AdapterItem.asMarketSearch(position++));
+ }
+ updateSearchAdapterItems(mSearchResults, 0);
+ } else {
mAccessibilityResultsCount = mApps.size();
if (mWorkAdapterProvider != null) {
position += mWorkAdapterProvider.addWorkItems(mAdapterItems);
@@ -323,18 +342,6 @@
mAdapterItems.add(appItem);
}
- } else {
- updateSearchAdapterItems(mSearchResults, 0);
- if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
- // Append the search market item
- if (hasNoFilteredResults()) {
- mAdapterItems.add(AdapterItem.asEmptySearch(position++));
- } else {
- mAdapterItems.add(AdapterItem.asAllAppsDivider(position++));
- }
- mAdapterItems.add(AdapterItem.asMarketSearch(position++));
-
- }
}
if (mNumAppsPerRowAllApps != 0) {
// Update the number of rows in the adapter after we do all the merging (otherwise, we
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index f913aa9..6a44989 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -80,7 +80,7 @@
OnDeviceProfileChangeListener, OnActivePageChangedListener,
ScrimView.ScrimDrawingController {
- private static final String BUNDLE_KEY_CURRENT_PAGE = "launcher.allapps.current_page";
+ protected static final String BUNDLE_KEY_CURRENT_PAGE = "launcher.allapps.current_page";
public static final float PULL_MULTIPLIER = .02f;
public static final float FLING_VELOCITY_MULTIPLIER = 1200f;
@@ -109,6 +109,7 @@
private int mNavBarScrimHeight = 0;
private AllAppsPagedView mViewPager;
+ private SearchRecyclerView mSearchRecyclerView;
protected FloatingHeaderView mHeader;
private View mBottomSheetBackground;
@@ -141,9 +142,10 @@
mActivityContext.getSystemService(UserManager.class),
this,
Utilities.getPrefs(mActivityContext));
- mAH = Arrays.asList(null, null);
- mAH.set(AdapterHolder.MAIN, new AdapterHolder(false /* isWork */));
- mAH.set(AdapterHolder.WORK, new AdapterHolder(true /* isWork */));
+ mAH = Arrays.asList(null, null, null);
+ mAH.set(AdapterHolder.MAIN, new AdapterHolder(AdapterHolder.MAIN));
+ mAH.set(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK));
+ mAH.set(AdapterHolder.SEARCH, new AdapterHolder(AdapterHolder.SEARCH));
mNavBarScrimPaint = new Paint();
mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
@@ -175,7 +177,7 @@
Bundle state = (Bundle) sparseArray.get(R.id.work_tab_state_id, null);
if (state != null) {
int currentPage = state.getInt(BUNDLE_KEY_CURRENT_PAGE, 0);
- if (currentPage != 0 && mViewPager != null) {
+ if (currentPage == AdapterHolder.WORK && mViewPager != null) {
mViewPager.setCurrentPage(currentPage);
rebindAdapters();
} else {
@@ -198,7 +200,7 @@
*/
public void setOnIconLongClickListener(OnLongClickListener listener) {
for (AdapterHolder holder : mAH) {
- holder.adapter.setOnIconLongClickListener(listener);
+ holder.mAdapter.setOnIconLongClickListener(listener);
}
}
@@ -213,7 +215,7 @@
@Override
public void onDeviceProfileChanged(DeviceProfile dp) {
for (AdapterHolder holder : mAH) {
- holder.adapter.setAppsPerRow(dp.numShownAllAppsColumns);
+ holder.mAdapter.setAppsPerRow(dp.numShownAllAppsColumns);
if (holder.mRecyclerView != null) {
// Remove all views and clear the pool, while keeping the data same. After this
// call, all the viewHolders will be recreated.
@@ -237,7 +239,7 @@
}
}
mHasWorkApps = hasWorkApps;
- if (!mAH.get(AdapterHolder.MAIN).mAppsList.hasFilter()) {
+ if (!mAH.get(AdapterHolder.MAIN).mAppsList.hasSearchResults()) {
rebindAdapters();
if (hasWorkApps) {
mWorkManager.reset();
@@ -256,7 +258,11 @@
if (mActivityContext.getDragLayer().isEventOverView(mBottomSheetHandleArea, ev)) {
return true;
}
- AllAppsRecyclerView rv = getActiveRecyclerView();
+ if (isSearching()) {
+ return mAH.get(AdapterHolder.SEARCH).mRecyclerView
+ .shouldContainerScroll(ev, mActivityContext.getDragLayer());
+ }
+ AllAppsRecyclerView rv = getActiveAppsRecyclerView();
if (rv == null) {
return true;
}
@@ -270,7 +276,7 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- AllAppsRecyclerView rv = getActiveRecyclerView();
+ AllAppsRecyclerView rv = getActiveAppsRecyclerView();
if (rv != null && rv.getScrollbar().isHitInParent(ev.getX(), ev.getY(),
mFastScrollerOffset)) {
mTouchHandler = rv.getScrollbar();
@@ -287,7 +293,7 @@
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- AllAppsRecyclerView rv = getActiveRecyclerView();
+ AllAppsRecyclerView rv = getActiveAppsRecyclerView();
if (rv != null && rv.getScrollbar().isHitInParent(ev.getX(), ev.getY(),
mFastScrollerOffset)) {
mTouchHandler = rv.getScrollbar();
@@ -320,8 +326,8 @@
return getContext().getString(R.string.all_apps_button_label);
}
- /** The current recycler view visible in the container. */
- public AllAppsRecyclerView getActiveRecyclerView() {
+ /** The current apps recycler view in the container (may be hidden for search results). */
+ public AllAppsRecyclerView getActiveAppsRecyclerView() {
if (!mUsingTabs || isPersonalTab()) {
return mAH.get(AdapterHolder.MAIN).mRecyclerView;
} else {
@@ -370,12 +376,15 @@
// This is a focus listener that proxies focus from a view into the list view. This is to
// work around the search box from getting first focus and showing the cursor.
setOnFocusChangeListener((v, hasFocus) -> {
- if (hasFocus && getActiveRecyclerView() != null) {
- getActiveRecyclerView().requestFocus();
+ if (hasFocus && getActiveAppsRecyclerView() != null) {
+ getActiveAppsRecyclerView().requestFocus();
}
});
mHeader = findViewById(R.id.all_apps_header);
+ mSearchRecyclerView = findViewById(R.id.search_results_list_view);
+ mAH.get(AdapterHolder.SEARCH).setup(mSearchRecyclerView,
+ /* Filter out A-Z apps */ (itemInfo, componentName) -> false);
rebindAdapters(true /* force */);
mBottomSheetBackground = findViewById(R.id.bottom_sheet_background);
@@ -438,13 +447,19 @@
}
protected void rebindAdapters(boolean force) {
- boolean showTabs = showTabs();
+ updateSearchResultsVisibility();
+
+ boolean showTabs = shouldShowTabs();
if (showTabs == mUsingTabs && !force) {
return;
}
mUsingTabs = showTabs;
- replaceRVContainer(mUsingTabs);
+ if (isSearching()) {
+ return;
+ }
+
+ replaceAppsRVContainer(mUsingTabs);
mAllAppsStore.unregisterIconContainer(mAH.get(AdapterHolder.MAIN).mRecyclerView);
mAllAppsStore.unregisterIconContainer(mAH.get(AdapterHolder.WORK).mRecyclerView);
@@ -479,6 +494,17 @@
mAllAppsStore.registerIconContainer(mAH.get(AdapterHolder.WORK).mRecyclerView);
}
+ private void updateSearchResultsVisibility() {
+ if (isSearching()) {
+ getSearchRecyclerView().setVisibility(VISIBLE);
+ getAppsRecyclerViewContainer().setVisibility(GONE);
+ } else {
+ getSearchRecyclerView().setVisibility(GONE);
+ getAppsRecyclerViewContainer().setVisibility(VISIBLE);
+ }
+ mHeader.setActiveRV(getCurrentPage());
+ }
+
private void setDeviceManagementResources() {
if (mActivityContext.getStringCache() != null) {
Button personalTab = findViewById(R.id.tab_personal);
@@ -489,18 +515,23 @@
}
}
- protected boolean showTabs() {
+ protected boolean shouldShowTabs() {
return mHasWorkApps;
}
- protected View replaceRVContainer(boolean showTabs) {
- for (AdapterHolder adapterHolder : mAH) {
+ protected boolean isSearching() {
+ return false;
+ }
+
+ protected View replaceAppsRVContainer(boolean showTabs) {
+ for (int i = AdapterHolder.MAIN; i <= AdapterHolder.WORK; i++) {
+ AdapterHolder adapterHolder = mAH.get(i);
if (adapterHolder.mRecyclerView != null) {
adapterHolder.mRecyclerView.setLayoutManager(null);
adapterHolder.mRecyclerView.setAdapter(null);
}
}
- View oldView = getRecyclerViewContainer();
+ View oldView = getAppsRecyclerViewContainer();
int index = indexOfChild(oldView);
removeView(oldView);
int layout = showTabs ? R.layout.all_apps_tabs : R.layout.all_apps_rv_layout;
@@ -521,13 +552,17 @@
return newView;
}
- public View getRecyclerViewContainer() {
+ public View getAppsRecyclerViewContainer() {
return mViewPager != null ? mViewPager : findViewById(R.id.apps_list_view);
}
+ public SearchRecyclerView getSearchRecyclerView() {
+ return mSearchRecyclerView;
+ }
+
@Override
public void onActivePageChanged(int currentActivePage) {
- mHeader.setMainActive(currentActivePage == AdapterHolder.MAIN);
+ mHeader.setActiveRV(currentActivePage);
if (mAH.get(currentActivePage).mRecyclerView != null) {
mAH.get(currentActivePage).mRecyclerView.bindFastScrollbar();
}
@@ -556,8 +591,8 @@
return isDescendantViewVisible(R.id.tab_work);
}
- public AlphabeticalAppsList<T> getApps() {
- return mAH.get(AdapterHolder.MAIN).mAppsList;
+ public AlphabeticalAppsList<T> getSearchResultList() {
+ return mAH.get(AdapterHolder.SEARCH).mAppsList;
}
public FloatingHeaderView getFloatingHeaderView() {
@@ -566,17 +601,19 @@
@VisibleForTesting
public View getContentView() {
- return mViewPager == null ? getActiveRecyclerView() : mViewPager;
+ return mViewPager == null ? getActiveAppsRecyclerView() : mViewPager;
}
/** The current page visible in all apps. */
public int getCurrentPage() {
- return mViewPager != null ? mViewPager.getCurrentPage() : AdapterHolder.MAIN;
+ return isSearching()
+ ? AdapterHolder.SEARCH
+ : mViewPager == null ? AdapterHolder.MAIN : mViewPager.getCurrentPage();
}
/** The scroll bar for the active recycler view. */
public RecyclerViewFastScroller getScrollBar() {
- AllAppsRecyclerView rv = getActiveRecyclerView();
+ AllAppsRecyclerView rv = getActiveAppsRecyclerView();
return rv == null ? null : rv.getScrollbar();
}
@@ -585,7 +622,9 @@
mHeader.setup(
mAH.get(AdapterHolder.MAIN).mRecyclerView,
mAH.get(AdapterHolder.WORK).mRecyclerView,
- mAH.get(AdapterHolder.WORK).mRecyclerView == null);
+ (SearchRecyclerView) mAH.get(AdapterHolder.SEARCH).mRecyclerView,
+ getCurrentPage(),
+ /* tabsHidden= */ mAH.get(AdapterHolder.WORK).mRecyclerView == null);
int padding = mHeader.getMaxTranslation();
for (int i = 0; i < mAH.size(); i++) {
@@ -696,39 +735,48 @@
return ColorUtils.blendARGB(mScrimColor, mHeaderProtectionColor, blendRatio);
}
- protected abstract BaseAllAppsAdapter getAdapter(AlphabeticalAppsList<T> mAppsList,
+ protected abstract BaseAllAppsAdapter<T> createAdapter(AlphabeticalAppsList<T> mAppsList,
BaseAdapterProvider[] adapterProviders);
protected int getHeaderBottom() {
return (int) getTranslationY();
}
+ /**
+ * Returns a view that denotes the visible part of all apps container view.
+ */
+ public View getVisibleContainerView() {
+ return mActivityContext.getDeviceProfile().isTablet ? mBottomSheetBackground : this;
+ }
+
/** Holds a {@link BaseAllAppsAdapter} and related fields. */
public class AdapterHolder {
public static final int MAIN = 0;
public static final int WORK = 1;
+ public static final int SEARCH = 2;
- private final boolean mIsWork;
- public final BaseAllAppsAdapter<T> adapter;
+ private final int mType;
+ public final BaseAllAppsAdapter<T> mAdapter;
final RecyclerView.LayoutManager mLayoutManager;
final AlphabeticalAppsList<T> mAppsList;
final Rect mPadding = new Rect();
AllAppsRecyclerView mRecyclerView;
boolean mVerticalFadingEdge;
- AdapterHolder(boolean isWork) {
- mIsWork = isWork;
- mAppsList = new AlphabeticalAppsList<>(mActivityContext, mAllAppsStore,
- isWork ? mWorkManager.getAdapterProvider() : null);
+ AdapterHolder(int type) {
+ mType = type;
+ mAppsList = new AlphabeticalAppsList<>(mActivityContext,
+ isSearch() ? null : mAllAppsStore,
+ isWork() ? mWorkManager.getAdapterProvider() : null);
BaseAdapterProvider[] adapterProviders =
- isWork ? new BaseAdapterProvider[]{mMainAdapterProvider,
+ isWork() ? new BaseAdapterProvider[]{mMainAdapterProvider,
mWorkManager.getAdapterProvider()}
: new BaseAdapterProvider[]{mMainAdapterProvider};
- adapter = getAdapter(mAppsList, adapterProviders);
- mAppsList.setAdapter(adapter);
- mLayoutManager = adapter.getLayoutManager();
+ mAdapter = createAdapter(mAppsList, adapterProviders);
+ mAppsList.setAdapter(mAdapter);
+ mLayoutManager = mAdapter.getLayoutManager();
}
void setup(@NonNull View rv, @Nullable ItemInfoMatcher matcher) {
@@ -737,14 +785,14 @@
mRecyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
mRecyclerView.setApps(mAppsList);
mRecyclerView.setLayoutManager(mLayoutManager);
- mRecyclerView.setAdapter(adapter);
+ mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setHasFixedSize(true);
// No animations will occur when changes occur to the items in this RecyclerView.
mRecyclerView.setItemAnimator(null);
mRecyclerView.addOnScrollListener(mScrollListener);
FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(mRecyclerView);
mRecyclerView.addItemDecoration(focusedItemDecorator);
- adapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
+ mAdapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
applyVerticalFadingEdgeEnabled(mVerticalFadingEdge);
applyPadding();
}
@@ -752,7 +800,7 @@
void applyPadding() {
if (mRecyclerView != null) {
int bottomOffset = 0;
- if (mIsWork && mWorkManager.getWorkModeSwitch() != null) {
+ if (isWork() && mWorkManager.getWorkModeSwitch() != null) {
bottomOffset = mInsets.bottom + mWorkManager.getWorkModeSwitch().getHeight();
}
mRecyclerView.setPadding(mPadding.left, mPadding.top, mPadding.right,
@@ -762,15 +810,15 @@
private void applyVerticalFadingEdgeEnabled(boolean enabled) {
mVerticalFadingEdge = enabled;
- mAH.get(AdapterHolder.MAIN).mRecyclerView.setVerticalFadingEdgeEnabled(!mUsingTabs
- && mVerticalFadingEdge);
+ mRecyclerView.setVerticalFadingEdgeEnabled(!mUsingTabs && mVerticalFadingEdge);
}
- }
- /**
- * Returns a view that denotes the visible part of all apps container view.
- */
- public View getVisibleContainerView() {
- return mActivityContext.getDeviceProfile().isTablet ? mBottomSheetBackground : this;
+ private boolean isWork() {
+ return mType == WORK;
+ }
+
+ private boolean isSearch() {
+ return mType == SEARCH;
+ }
}
}
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 72f14a8..3e717bd 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -33,6 +33,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
+import com.android.launcher3.allapps.BaseAllAppsContainerView.AdapterHolder;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.views.ActivityContext;
@@ -90,8 +91,8 @@
protected ViewGroup mTabLayout;
private AllAppsRecyclerView mMainRV;
private AllAppsRecyclerView mWorkRV;
+ private SearchRecyclerView mSearchRV;
private AllAppsRecyclerView mCurrentRV;
- private ViewGroup mParent;
public boolean mHeaderCollapsed;
protected int mSnappedScrolledY;
private int mTranslationY;
@@ -100,7 +101,6 @@
protected boolean mTabsHidden;
protected int mMaxTranslation;
- private boolean mMainRVActive = true;
private boolean mCollapsed = false;
@@ -232,7 +232,8 @@
return super.getFocusedChild();
}
- void setup(AllAppsRecyclerView mainRV, AllAppsRecyclerView workRV, boolean tabsHidden) {
+ void setup(AllAppsRecyclerView mainRV, AllAppsRecyclerView workRV, SearchRecyclerView searchRV,
+ int activeRV, boolean tabsHidden) {
for (FloatingHeaderRow row : mAllRows) {
row.setup(this, mAllRows, tabsHidden);
}
@@ -242,8 +243,8 @@
mTabLayout.setVisibility(tabsHidden ? View.GONE : View.VISIBLE);
mMainRV = setupRV(mMainRV, mainRV);
mWorkRV = setupRV(mWorkRV, workRV);
- mParent = (ViewGroup) mMainRV.getParent();
- setMainActive(mMainRVActive || mWorkRV == null);
+ mSearchRV = (SearchRecyclerView) setupRV(mSearchRV, searchRV);
+ setActiveRV(activeRV);
reset(false);
}
@@ -267,9 +268,10 @@
}
}
- public void setMainActive(boolean active) {
- mCurrentRV = active ? mMainRV : mWorkRV;
- mMainRVActive = active;
+ public void setActiveRV(int rvType) {
+ mCurrentRV =
+ rvType == AdapterHolder.MAIN ? mMainRV
+ : rvType == AdapterHolder.WORK ? mWorkRV : mSearchRV;
}
public int getMaxTranslation() {
@@ -332,10 +334,15 @@
mHeaderClip.top = clipTop;
// clipping on a draw might cause additional redraw
setClipBounds(mHeaderClip);
- mMainRV.setClipBounds(mRVClip);
+ if (mMainRV != null) {
+ mMainRV.setClipBounds(mRVClip);
+ }
if (mWorkRV != null) {
mWorkRV.setClipBounds(mRVClip);
}
+ if (mSearchRV != null) {
+ mSearchRV.setClipBounds(mRVClip);
+ }
}
/**
@@ -402,8 +409,8 @@
}
private void calcOffset(Point p) {
- p.x = getLeft() - mCurrentRV.getLeft() - mParent.getLeft();
- p.y = getTop() - mCurrentRV.getTop() - mParent.getTop();
+ p.x = getLeft() - mCurrentRV.getLeft() - ((ViewGroup) mCurrentRV.getParent()).getLeft();
+ p.y = getTop() - mCurrentRV.getTop() - ((ViewGroup) mCurrentRV.getParent()).getTop();
}
public boolean hasVisibleContent() {
diff --git a/src/com/android/launcher3/allapps/SearchRecyclerView.java b/src/com/android/launcher3/allapps/SearchRecyclerView.java
new file mode 100644
index 0000000..435668a
--- /dev/null
+++ b/src/com/android/launcher3/allapps/SearchRecyclerView.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.allapps;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+/** A RecyclerView for AllApps Search results. */
+public class SearchRecyclerView extends AllAppsRecyclerView {
+ private static final String TAG = "SearchRecyclerView";
+
+ public SearchRecyclerView(Context context) {
+ this(context, null);
+ }
+
+ public SearchRecyclerView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public SearchRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public SearchRecyclerView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void updatePoolSize() {
+ RecycledViewPool pool = getRecycledViewPool();
+ pool.setMaxRecycledViews(AllAppsGridAdapter.VIEW_TYPE_ICON, mNumAppsPerRow);
+ // TODO(b/206905515): Add maxes for other View types.
+ }
+
+ @Override
+ public boolean supportsFastScrolling() {
+ return false;
+ }
+}
diff --git a/src/com/android/launcher3/allapps/WorkEduCard.java b/src/com/android/launcher3/allapps/WorkEduCard.java
index c336496..fa9a8f6 100644
--- a/src/com/android/launcher3/allapps/WorkEduCard.java
+++ b/src/com/android/launcher3/allapps/WorkEduCard.java
@@ -71,7 +71,7 @@
super.onFinishInflate();
findViewById(R.id.action_btn).setOnClickListener(this);
MarginLayoutParams lp = ((MarginLayoutParams) findViewById(R.id.wrapper).getLayoutParams());
- lp.width = mActivityContext.getAppsView().getActiveRecyclerView().getTabWidth();
+ lp.width = mActivityContext.getAppsView().getActiveAppsRecyclerView().getTabWidth();
}
@Override
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index bcb0d14..6203cea 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -27,6 +27,7 @@
import android.os.UserManager;
import android.util.Log;
import android.view.ViewGroup;
+import android.view.WindowInsets;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
@@ -147,6 +148,9 @@
workFabMarginBottom +=
mWorkModeSwitch.getResources().getDimensionPixelSize(R.dimen.qsb_widget_height);
}
+ if (!mAllApps.mActivityContext.getDeviceProfile().isGestureMode){
+ workFabMarginBottom += mAllApps.mActivityContext.getDeviceProfile().getInsets().bottom;
+ }
((ViewGroup.MarginLayoutParams) mWorkModeSwitch.getLayoutParams()).bottomMargin =
workFabMarginBottom;
if (mWorkModeSwitch.getParent() != mAllApps) {
@@ -158,7 +162,6 @@
mWorkModeSwitch.updateCurrentState(mCurrentState == STATE_ENABLED);
return true;
}
-
/**
* Removes work profile toggle button from {@link BaseAllAppsContainerView}
*/
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index 893e547..4bd106f 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -57,7 +57,7 @@
private final AllAppsSearchBarController mSearchBarController;
private final SpannableStringBuilder mSearchQueryBuilder;
- private AlphabeticalAppsList<?> mApps;
+ private AlphabeticalAppsList<?> mSearchResultsList;
private ActivityAllAppsContainerView<?> mAppsView;
// The amount of pixels to shift down and overlap with the rest of the content.
@@ -102,8 +102,8 @@
// Update the width to match the grid padding
DeviceProfile dp = mLauncher.getDeviceProfile();
int myRequestedWidth = getSize(widthMeasureSpec);
- int rowWidth = myRequestedWidth - mAppsView.getActiveRecyclerView().getPaddingLeft()
- - mAppsView.getActiveRecyclerView().getPaddingRight();
+ int rowWidth = myRequestedWidth - mAppsView.getActiveAppsRecyclerView().getPaddingLeft()
+ - mAppsView.getActiveAppsRecyclerView().getPaddingRight();
int cellWidth = DeviceProfile.calculateCellWidth(rowWidth,
dp.cellLayoutBorderSpacePx.x, dp.numShownHotseatIcons);
@@ -131,7 +131,7 @@
@Override
public void initializeSearch(ActivityAllAppsContainerView<?> appsView) {
- mApps = appsView.getApps();
+ mSearchResultsList = appsView.getSearchResultList();
mAppsView = appsView;
mSearchBarController.initialize(
new DefaultAppSearchAlgorithm(getContext()),
@@ -170,7 +170,7 @@
@Override
public void onSearchResult(String query, ArrayList<AdapterItem> items) {
if (items != null) {
- mApps.setSearchResults(items);
+ mSearchResultsList.setSearchResults(items);
notifyResultChanged();
mAppsView.setLastSearchQuery(query);
}
@@ -179,14 +179,14 @@
@Override
public void onAppendSearchResult(String query, ArrayList<AdapterItem> items) {
if (items != null) {
- mApps.appendSearchResults(items);
+ mSearchResultsList.appendSearchResults(items);
notifyResultChanged();
}
}
@Override
public void clearSearchResult() {
- if (mApps.setSearchResults(null)) {
+ if (mSearchResultsList.setSearchResults(null)) {
notifyResultChanged();
}
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 5ee4203..8eeca7d 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -65,9 +65,7 @@
public class DragLayer extends BaseDragLayer<Launcher> {
public static final int ALPHA_INDEX_OVERLAY = 0;
- public static final int ALPHA_INDEX_LAUNCHER_LOAD = 1;
- public static final int ALPHA_INDEX_TRANSITIONS = 2;
- private static final int ALPHA_CHANNEL_COUNT = 3;
+ private static final int ALPHA_CHANNEL_COUNT = 1;
public static final int ANIMATION_END_DISAPPEAR = 0;
public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
@@ -104,7 +102,10 @@
mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
}
- public void setup(DragController dragController, Workspace workspace) {
+ /**
+ * Set up the drag layer with the parameters.
+ */
+ public void setup(DragController dragController, Workspace<?> workspace) {
mDragController = dragController;
recreateControllers();
mWorkspaceDragScrim = new Scrim(this);
diff --git a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
index 74d9a22..6f295e6 100644
--- a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
+++ b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
@@ -20,9 +20,13 @@
import android.annotation.TargetApi;
import android.graphics.Bitmap;
-import android.graphics.Matrix;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
+import android.graphics.Path.Direction;
+import android.graphics.Picture;
+import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.AdaptiveIconDrawable;
@@ -31,10 +35,11 @@
import android.util.Log;
import androidx.annotation.Nullable;
+import androidx.annotation.UiThread;
+import com.android.launcher3.Utilities;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.folder.PreviewBackground;
-import com.android.launcher3.graphics.ShiftedBitmapDrawable;
import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.views.ActivityContext;
@@ -69,79 +74,104 @@
return mBadge;
}
+ @TargetApi(Build.VERSION_CODES.P)
public static @Nullable FolderAdaptiveIcon createFolderAdaptiveIcon(
- ActivityContext activity, int folderId, Point dragViewSize) {
+ ActivityContext activity, int folderId, Point size) {
Preconditions.assertNonUiThread();
+ if (!Utilities.ATLEAST_P) {
+ return null;
+ }
- // Create the actual drawable on the UI thread to avoid race conditions with
+ // assume square
+ if (size.x != size.y) {
+ return null;
+ }
+ int requestedSize = size.x;
+
+ // Only use the size actually needed for drawing the folder icon
+ int drawingSize = activity.getDeviceProfile().folderIconSizePx;
+ int foregroundSize = Math.max(requestedSize, drawingSize);
+ float shift = foregroundSize - requestedSize;
+
+ Picture background = new Picture();
+ Picture foreground = new Picture();
+ Picture badge = new Picture();
+
+ Canvas bgCanvas = background.beginRecording(requestedSize, requestedSize);
+ Canvas badgeCanvas = badge.beginRecording(requestedSize, requestedSize);
+
+ Canvas fgCanvas = foreground.beginRecording(foregroundSize, foregroundSize);
+ fgCanvas.translate(shift, shift);
+
+ // Do not clip the folder drawing since the icon previews extend outside the background.
+ Path mask = new Path();
+ mask.addRect(-shift, -shift, requestedSize + shift, requestedSize + shift,
+ Direction.CCW);
+
+ // Initialize the actual draw commands on the UI thread to avoid race conditions with
// FolderIcon draw pass
try {
- return MAIN_EXECUTOR.submit(() -> {
+ MAIN_EXECUTOR.submit(() -> {
FolderIcon icon = activity.findFolderIcon(folderId);
- return icon == null ? null : createDrawableOnUiThread(icon, dragViewSize);
-
+ if (icon == null) {
+ throw new IllegalArgumentException("Folder not found with id: " + folderId);
+ }
+ initLayersOnUiThread(icon, requestedSize, bgCanvas, fgCanvas, badgeCanvas);
}).get();
} catch (Exception e) {
Log.e(TAG, "Unable to create folder icon", e);
return null;
+ } finally {
+ background.endRecording();
+ foreground.endRecording();
+ badge.endRecording();
}
+
+ // Only convert foreground to a bitmap as it can contain multiple draw commands. Other
+ // layers either draw a nothing or a single draw call.
+ Bitmap fgBitmap = Bitmap.createBitmap(foreground);
+ Paint foregroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ // Do not use PictureDrawable as it moves the picture to the canvas bounds, whereas we want
+ // to draw it at (0,0)
+ return new FolderAdaptiveIcon(
+ new BitmapRendererDrawable(c -> c.drawPicture(background)),
+ new BitmapRendererDrawable(
+ c -> c.drawBitmap(fgBitmap, -shift, -shift, foregroundPaint)),
+ new BitmapRendererDrawable(c -> c.drawPicture(badge)),
+ mask);
}
- private static FolderAdaptiveIcon createDrawableOnUiThread(FolderIcon icon,
- Point dragViewSize) {
- Preconditions.assertUIThread();
-
+ @UiThread
+ private static void initLayersOnUiThread(FolderIcon icon, int size,
+ Canvas backgroundCanvas, Canvas foregroundCanvas, Canvas badgeCanvas) {
icon.getPreviewBounds(sTmpRect);
-
- PreviewBackground bg = icon.getFolderBackground();
-
- // assume square
- assert (dragViewSize.x == dragViewSize.y);
final int previewSize = sTmpRect.width();
- final int margin = (dragViewSize.x - previewSize) / 2;
+ PreviewBackground bg = icon.getFolderBackground();
+ final int margin = (size - previewSize) / 2;
final float previewShiftX = -sTmpRect.left + margin;
final float previewShiftY = -sTmpRect.top + margin;
// Initialize badge, which consists of the outline stroke, shadow and dot; these
// must be rendered above the foreground
- Bitmap badgeBmp = BitmapRenderer.createHardwareBitmap(dragViewSize.x, dragViewSize.y,
- (canvas) -> {
- canvas.save();
- canvas.translate(previewShiftX, previewShiftY);
- bg.drawShadow(canvas);
- bg.drawBackgroundStroke(canvas);
- icon.drawDot(canvas);
- canvas.restore();
- });
+ badgeCanvas.save();
+ badgeCanvas.translate(previewShiftX, previewShiftY);
+ icon.drawDot(badgeCanvas);
+ badgeCanvas.restore();
- // Initialize mask
- Path mask = new Path();
- Matrix m = new Matrix();
- m.setTranslate(previewShiftX, previewShiftY);
- bg.getClipPath().transform(m, mask);
+ // Draw foreground
+ foregroundCanvas.save();
+ foregroundCanvas.translate(previewShiftX, previewShiftY);
+ icon.getPreviewItemManager().draw(foregroundCanvas);
+ foregroundCanvas.restore();
- Bitmap previewBitmap = BitmapRenderer.createHardwareBitmap(dragViewSize.x, dragViewSize.y,
- (canvas) -> {
- canvas.save();
- canvas.translate(previewShiftX, previewShiftY);
- icon.getPreviewItemManager().draw(canvas);
- canvas.restore();
- });
-
- Bitmap bgBitmap = BitmapRenderer.createHardwareBitmap(dragViewSize.x, dragViewSize.y,
- (canvas) -> {
- Paint p = new Paint();
- p.setColor(bg.getBgColor());
-
- canvas.drawCircle(dragViewSize.x / 2f, dragViewSize.y / 2f, bg.getRadius(), p);
- });
-
- ShiftedBitmapDrawable badge = new ShiftedBitmapDrawable(badgeBmp, 0, 0);
- ShiftedBitmapDrawable foreground = new ShiftedBitmapDrawable(previewBitmap, 0, 0);
- ShiftedBitmapDrawable background = new ShiftedBitmapDrawable(bgBitmap, 0, 0);
-
- return new FolderAdaptiveIcon(background, foreground, badge, mask);
+ // Draw background
+ Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ backgroundPaint.setColor(bg.getBgColor());
+ bg.drawShadow(backgroundCanvas);
+ backgroundCanvas.drawCircle(size / 2f, size / 2f, bg.getRadius(), backgroundPaint);
+ bg.drawBackgroundStroke(backgroundCanvas);
}
@Override
@@ -174,4 +204,52 @@
& mBadge.getChangingConfigurations();
}
}
+
+ private static class BitmapRendererDrawable extends Drawable {
+
+ private final BitmapRenderer mRenderer;
+
+ BitmapRendererDrawable(BitmapRenderer renderer) {
+ mRenderer = renderer;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ mRenderer.draw(canvas);
+ }
+
+ @Override
+ public void setAlpha(int i) { }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) { }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ return new MyConstantState(mRenderer);
+ }
+
+ private static class MyConstantState extends ConstantState {
+ private final BitmapRenderer mRenderer;
+
+ MyConstantState(BitmapRenderer renderer) {
+ mRenderer = renderer;
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new BitmapRendererDrawable(mRenderer);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return 0;
+ }
+ }
+ }
}
diff --git a/src/com/android/launcher3/dragndrop/SpringLoadedDragController.java b/src/com/android/launcher3/dragndrop/SpringLoadedDragController.java
index 6325877..fb8a1bc 100644
--- a/src/com/android/launcher3/dragndrop/SpringLoadedDragController.java
+++ b/src/com/android/launcher3/dragndrop/SpringLoadedDragController.java
@@ -55,7 +55,7 @@
public void onAlarm(Alarm alarm) {
if (mScreen != null) {
// Snap to the screen that we are hovering over now
- Workspace w = mLauncher.getWorkspace();
+ Workspace<?> w = mLauncher.getWorkspace();
if (!w.isVisible(mScreen)) {
w.snapToPage(w.indexOfChild(mScreen));
}
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 7c665c6..5fe2435 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -342,7 +342,7 @@
Rect to = finalRect;
if (to == null) {
to = new Rect();
- Workspace workspace = launcher.getWorkspace();
+ Workspace<?> workspace = launcher.getWorkspace();
// Set cellLayout and this to it's final state to compute final animation locations
workspace.setFinalTransitionTransform();
float scaleX = getScaleX();
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 3dfece7..a11bd4f 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -23,7 +23,6 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
import static com.android.launcher3.model.ModelUtils.getMissingHotseatRanks;
-import static com.android.launcher3.model.ModelUtils.sortWorkspaceItemsSpatially;
import android.annotation.TargetApi;
import android.app.Fragment;
@@ -420,8 +419,6 @@
currentWorkspaceItems, otherWorkspaceItems);
filterCurrentWorkspaceItems(currentScreenIds, dataModel.appWidgets, currentAppWidgets,
otherAppWidgets);
-
- sortWorkspaceItemsSpatially(mIdp, currentWorkspaceItems);
for (ItemInfo itemInfo : currentWorkspaceItems) {
switch (itemInfo.itemType) {
case Favorites.ITEM_TYPE_APPLICATION:
diff --git a/src/com/android/launcher3/graphics/ShiftedBitmapDrawable.java b/src/com/android/launcher3/graphics/ShiftedBitmapDrawable.java
deleted file mode 100644
index f8583b8..0000000
--- a/src/com/android/launcher3/graphics/ShiftedBitmapDrawable.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2019 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.graphics;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.drawable.Drawable;
-
-/**
- * A simple drawable which draws a bitmap at a fixed position irrespective of the bounds
- */
-public class ShiftedBitmapDrawable extends Drawable {
-
- private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
- private final Bitmap mBitmap;
- private float mShiftX;
- private float mShiftY;
-
- private final ConstantState mConstantState;
-
- public ShiftedBitmapDrawable(Bitmap bitmap, float shiftX, float shiftY) {
- mBitmap = bitmap;
- mShiftX = shiftX;
- mShiftY = shiftY;
-
- mConstantState = new MyConstantState(mBitmap, mShiftX, mShiftY);
- }
-
- public float getShiftX() {
- return mShiftX;
- }
-
- public float getShiftY() {
- return mShiftY;
- }
-
- public void setShiftX(float shiftX) {
- mShiftX = shiftX;
- }
-
- public void setShiftY(float shiftY) {
- mShiftY = shiftY;
- }
-
- @Override
- public void draw(Canvas canvas) {
- canvas.drawBitmap(mBitmap, mShiftX, mShiftY, mPaint);
- }
-
- @Override
- public void setAlpha(int i) { }
-
- @Override
- public void setColorFilter(ColorFilter colorFilter) {
- mPaint.setColorFilter(colorFilter);
- }
-
- @Override
- public int getOpacity() {
- return PixelFormat.TRANSLUCENT;
- }
-
- @Override
- public ConstantState getConstantState() {
- return mConstantState;
- }
-
- private static class MyConstantState extends ConstantState {
- private final Bitmap mBitmap;
- private float mShiftX;
- private float mShiftY;
-
- MyConstantState(Bitmap bitmap, float shiftX, float shiftY) {
- mBitmap = bitmap;
- mShiftX = shiftX;
- mShiftY = shiftY;
- }
-
- @Override
- public Drawable newDrawable() {
- return new ShiftedBitmapDrawable(mBitmap, mShiftX, mShiftY);
- }
-
- @Override
- public int getChangingConfigurations() {
- return 0;
- }
- }
-}
\ No newline at end of file
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 7ba2317..fe9b633 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -42,8 +42,10 @@
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
+import android.util.SparseArray;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.core.util.Pair;
import com.android.launcher3.InvariantDeviceProfile;
@@ -94,6 +96,8 @@
private final InstantAppResolver mInstantAppResolver;
private final IconProvider mIconProvider;
+ private final SparseArray<BitmapInfo> mWidgetCategoryBitmapInfos;
+
private int mPendingIconRequestCount = 0;
public IconCache(Context context, InvariantDeviceProfile idp) {
@@ -111,6 +115,7 @@
mUserManager = UserCache.INSTANCE.get(mContext);
mInstantAppResolver = InstantAppResolver.newInstance(mContext);
mIconProvider = iconProvider;
+ mWidgetCategoryBitmapInfos = new SparseArray<>();
}
@Override
@@ -477,13 +482,39 @@
CacheEntry entry = getEntryForPackageLocked(
infoInOut.packageName, infoInOut.user, useLowResIcon);
applyCacheEntry(entry, infoInOut);
- if (infoInOut.widgetCategory != NO_CATEGORY) {
- WidgetSection widgetSection = WidgetSections.getWidgetSections(mContext)
- .get(infoInOut.widgetCategory);
- infoInOut.title = mContext.getString(widgetSection.mSectionTitle);
- infoInOut.contentDescription = mPackageManager.getUserBadgedLabel(
- infoInOut.title, infoInOut.user);
+ if (infoInOut.widgetCategory == NO_CATEGORY) {
+ return;
}
+
+ WidgetSection widgetSection = WidgetSections.getWidgetSections(mContext)
+ .get(infoInOut.widgetCategory);
+ infoInOut.title = mContext.getString(widgetSection.mSectionTitle);
+ infoInOut.contentDescription = mPackageManager.getUserBadgedLabel(
+ infoInOut.title, infoInOut.user);
+ final BitmapInfo cachedBitmap = mWidgetCategoryBitmapInfos.get(infoInOut.widgetCategory);
+ if (cachedBitmap != null) {
+ infoInOut.bitmap = getBadgedIcon(cachedBitmap, infoInOut.user);
+ return;
+ }
+
+ try (LauncherIcons li = LauncherIcons.obtain(mContext)) {
+ final BitmapInfo tempBitmap = li.createBadgedIconBitmap(
+ mContext.getDrawable(widgetSection.mSectionDrawable),
+ new BaseIconFactory.IconOptions().setShrinkNonAdaptiveIcons(false));
+ mWidgetCategoryBitmapInfos.put(infoInOut.widgetCategory, tempBitmap);
+ infoInOut.bitmap = getBadgedIcon(tempBitmap, infoInOut.user);
+ } catch (Exception e) {
+ Log.e(TAG, "Error initializing bitmap for icons with widget category", e);
+ }
+
+ }
+
+ private synchronized BitmapInfo getBadgedIcon(@Nullable final BitmapInfo bitmap,
+ @NonNull final UserHandle user) {
+ if (bitmap == null) {
+ return getDefaultIcon(user);
+ }
+ return bitmap.withFlags(getUserFlagOpLocked(user));
}
protected void applyCacheEntry(CacheEntry entry, ItemInfoWithIcon info) {
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 9af72c3..2b6e426 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -586,6 +586,9 @@
@UiEvent(doc = "User clicked on IME quicksearch button.")
LAUNCHER_ALLAPPS_QUICK_SEARCH_WITH_IME(1047),
+
+ @UiEvent(doc = "User tapped taskbar All Apps button.")
+ LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP(1057),
;
// ADD MORE
diff --git a/src/com/android/launcher3/model/BaseLoaderResults.java b/src/com/android/launcher3/model/BaseLoaderResults.java
index 5b278ab..6c4cfb9 100644
--- a/src/com/android/launcher3/model/BaseLoaderResults.java
+++ b/src/com/android/launcher3/model/BaseLoaderResults.java
@@ -18,7 +18,6 @@
import static com.android.launcher3.model.ItemInstallQueue.FLAG_LOADER_RUNNING;
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
-import static com.android.launcher3.model.ModelUtils.sortWorkspaceItemsSpatially;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.os.Process;
@@ -27,6 +26,8 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel.CallbackTask;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.data.AppInfo;
@@ -110,6 +111,42 @@
public abstract void bindWidgets();
+ /**
+ * Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to right)
+ */
+ protected void sortWorkspaceItemsSpatially(InvariantDeviceProfile profile,
+ ArrayList<ItemInfo> workspaceItems) {
+ final int screenCols = profile.numColumns;
+ final int screenCellCount = profile.numColumns * profile.numRows;
+ Collections.sort(workspaceItems, (lhs, rhs) -> {
+ if (lhs.container == rhs.container) {
+ // Within containers, order by their spatial position in that container
+ switch (lhs.container) {
+ case LauncherSettings.Favorites.CONTAINER_DESKTOP: {
+ int lr = (lhs.screenId * screenCellCount + lhs.cellY * screenCols
+ + lhs.cellX);
+ int rr = (rhs.screenId * screenCellCount + +rhs.cellY * screenCols
+ + rhs.cellX);
+ return Integer.compare(lr, rr);
+ }
+ case LauncherSettings.Favorites.CONTAINER_HOTSEAT: {
+ // We currently use the screen id as the rank
+ return Integer.compare(lhs.screenId, rhs.screenId);
+ }
+ default:
+ if (FeatureFlags.IS_STUDIO_BUILD) {
+ throw new RuntimeException(
+ "Unexpected container type when sorting workspace items.");
+ }
+ return 0;
+ }
+ } else {
+ // Between containers, order by hotseat, desktop
+ return Integer.compare(lhs.container, rhs.container);
+ }
+ });
+ }
+
protected void executeCallbacksTask(CallbackTask task, Executor executor) {
executor.execute(() -> {
if (mMyBindingId != mBgDataModel.lastBindId) {
@@ -131,7 +168,7 @@
return idleLock;
}
- private static class WorkspaceBinder {
+ private class WorkspaceBinder {
private final Executor mUiExecutor;
private final Callbacks mCallbacks;
diff --git a/src/com/android/launcher3/model/ModelUtils.java b/src/com/android/launcher3/model/ModelUtils.java
index ef5eef1..df6768d 100644
--- a/src/com/android/launcher3/model/ModelUtils.java
+++ b/src/com/android/launcher3/model/ModelUtils.java
@@ -23,10 +23,8 @@
import android.os.Process;
import android.util.Log;
-import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.data.ItemInfo;
@@ -92,42 +90,6 @@
}
/**
- * Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to right)
- */
- public static void sortWorkspaceItemsSpatially(InvariantDeviceProfile profile,
- ArrayList<ItemInfo> workspaceItems) {
- final int screenCols = profile.numColumns;
- final int screenCellCount = profile.numColumns * profile.numRows;
- Collections.sort(workspaceItems, (lhs, rhs) -> {
- if (lhs.container == rhs.container) {
- // Within containers, order by their spatial position in that container
- switch (lhs.container) {
- case LauncherSettings.Favorites.CONTAINER_DESKTOP: {
- int lr = (lhs.screenId * screenCellCount + lhs.cellY * screenCols
- + lhs.cellX);
- int rr = (rhs.screenId * screenCellCount + +rhs.cellY * screenCols
- + rhs.cellX);
- return Integer.compare(lr, rr);
- }
- case LauncherSettings.Favorites.CONTAINER_HOTSEAT: {
- // We currently use the screen id as the rank
- return Integer.compare(lhs.screenId, rhs.screenId);
- }
- default:
- if (FeatureFlags.IS_STUDIO_BUILD) {
- throw new RuntimeException(
- "Unexpected container type when sorting workspace items.");
- }
- return 0;
- }
- } else {
- // Between containers, order by hotseat, desktop
- return Integer.compare(lhs.container, rhs.container);
- }
- });
- }
-
- /**
* Iterates though current workspace items and returns available hotseat ranks for prediction.
*/
public static IntArray getMissingHotseatRanks(List<ItemInfo> items, int len) {
diff --git a/src/com/android/launcher3/model/StringCache.java b/src/com/android/launcher3/model/StringCache.java
index 2fc852d..663a463 100644
--- a/src/com/android/launcher3/model/StringCache.java
+++ b/src/com/android/launcher3/model/StringCache.java
@@ -16,6 +16,7 @@
package com.android.launcher3.model;
+import android.annotation.SuppressLint;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.os.Build;
@@ -215,6 +216,7 @@
context, DISABLED_BY_ADMIN_MESSAGE, R.string.msg_disabled_by_admin);
}
+ @SuppressLint("NewApi")
private String getEnterpriseString(
Context context, String updatableStringId, int defaultStringId) {
return Utilities.ATLEAST_T
diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
index 19345d7..76a0c4d 100644
--- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
@@ -71,10 +71,6 @@
*/
public static final int FLAG_DISABLED_LOCKED_USER = 1 << 5;
- public static final int FLAG_DISABLED_MASK = FLAG_DISABLED_SAFEMODE
- | FLAG_DISABLED_NOT_AVAILABLE | FLAG_DISABLED_SUSPENDED
- | FLAG_DISABLED_QUIET_USER | FLAG_DISABLED_BY_PUBLISHER | FLAG_DISABLED_LOCKED_USER;
-
/**
* The item points to a system app.
*/
@@ -114,6 +110,16 @@
| FLAG_INCREMENTAL_DOWNLOAD_ACTIVE;
/**
+ * Indicates that the icon is a disabled shortcut and application updates are required.
+ */
+ public static final int FLAG_DISABLED_VERSION_LOWER = 1 << 12;
+
+ public static final int FLAG_DISABLED_MASK = FLAG_DISABLED_SAFEMODE
+ | FLAG_DISABLED_NOT_AVAILABLE | FLAG_DISABLED_SUSPENDED
+ | FLAG_DISABLED_QUIET_USER | FLAG_DISABLED_BY_PUBLISHER | FLAG_DISABLED_LOCKED_USER
+ | FLAG_DISABLED_VERSION_LOWER;
+
+ /**
* Status associated with the system state of the underlying item. This is calculated every
* time a new info is created and not persisted on the disk.
*/
diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
index a195979..2b3da33 100644
--- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
+++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
@@ -180,12 +180,25 @@
runtimeStatusFlags |= FLAG_DISABLED_BY_PUBLISHER;
}
disabledMessage = shortcutInfo.getDisabledMessage();
+ if (Utilities.ATLEAST_P
+ && shortcutInfo.getDisabledReason() == ShortcutInfo.DISABLED_REASON_VERSION_LOWER) {
+ runtimeStatusFlags |= FLAG_DISABLED_VERSION_LOWER;
+ } else {
+ runtimeStatusFlags &= ~FLAG_DISABLED_VERSION_LOWER;
+ }
Person[] persons = ApiWrapper.getPersons(shortcutInfo);
personKeys = persons.length == 0 ? Utilities.EMPTY_STRING_ARRAY
: Arrays.stream(persons).map(Person::getKey).sorted().toArray(String[]::new);
}
+ /**
+ * {@code true} if the shortcut is disabled due to its app being a lower version.
+ */
+ public boolean isDisabledVersionLower() {
+ return (runtimeStatusFlags & FLAG_DISABLED_VERSION_LOWER) != 0;
+ }
+
/** Returns the WorkspaceItemInfo id associated with the deep shortcut. */
public String getDeepShortcutId() {
return itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index bbeb886..04eb38a 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -35,6 +35,7 @@
import android.util.Pair;
import androidx.annotation.AnyThread;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
@@ -154,14 +155,9 @@
case MSG_NOTIFICATION_FULL_REFRESH:
List<StatusBarNotification> activeNotifications = null;
if (sIsConnected) {
- try {
- activeNotifications = Arrays.stream(getActiveNotifications())
- .filter(this::notificationIsValidForUI)
- .collect(Collectors.toList());
- } catch (SecurityException ex) {
- Log.e(TAG, "SecurityException: failed to fetch notifications");
- activeNotifications = new ArrayList<>();
- }
+ activeNotifications = Arrays.stream(getActiveNotificationsSafely(null))
+ .filter(this::notificationIsValidForUI)
+ .collect(Collectors.toList());
} else {
activeNotifications = new ArrayList<>();
}
@@ -175,7 +171,7 @@
}
case MSG_RANKING_UPDATE: {
String[] keys = ((RankingMap) message.obj).getOrderedKeys();
- for (StatusBarNotification sbn : getActiveNotifications(keys)) {
+ for (StatusBarNotification sbn : getActiveNotificationsSafely(keys)) {
updateGroupKeyIfNecessary(sbn);
}
return true;
@@ -214,6 +210,16 @@
return true;
}
+ private @NonNull StatusBarNotification[] getActiveNotificationsSafely(@Nullable String[] keys) {
+ StatusBarNotification[] result = null;
+ try {
+ result = getActiveNotifications(keys);
+ } catch (SecurityException e) {
+ Log.e(TAG, "SecurityException: failed to fetch notifications");
+ }
+ return result == null ? new StatusBarNotification[0] : result;
+ }
+
@Override
public void onListenerConnected() {
super.onListenerConnected();
@@ -313,9 +319,8 @@
*/
@WorkerThread
public List<StatusBarNotification> getNotificationsForKeys(List<NotificationKeyData> keys) {
- StatusBarNotification[] notifications = getActiveNotifications(
- keys.stream().map(n -> n.notificationKey).toArray(String[]::new));
- return notifications == null ? Collections.emptyList() : Arrays.asList(notifications);
+ return Arrays.asList(getActiveNotificationsSafely(
+ keys.stream().map(n -> n.notificationKey).toArray(String[]::new)));
}
/**
diff --git a/src/com/android/launcher3/pageindicators/PageIndicator.java b/src/com/android/launcher3/pageindicators/PageIndicator.java
index 5967be7..ec69193 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicator.java
@@ -28,21 +28,22 @@
/**
* Sets the flag if the Page Indicator should autohide.
- * @param shouldAutoHide
*/
default void setShouldAutoHide(boolean shouldAutoHide) {
- //No-op by default
+ // No-op by default
}
+
/**
* Pauses all currently running animations.
*/
default void pauseAnimations() {
- //No-op by default
+ // No-op by default
}
+
/**
* Force-ends all currently running or paused animations.
*/
default void skipAnimationsToEnd() {
- //No-op by default
+ // No-op by default
}
}
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index f06e5ce..196cc56 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -351,7 +351,7 @@
if (mColorExtractors == null) {
return;
}
- Workspace workspace = launcher.getWorkspace();
+ Workspace<?> workspace = launcher.getWorkspace();
if (workspace == null) {
return;
}
@@ -602,6 +602,7 @@
mIsAboveIcon = y > dragLayer.getTop() + insets.top;
if (!mIsAboveIcon) {
y = mTempRect.top + iconHeight + extraVerticalSpace;
+ height -= extraVerticalSpace;
}
// Insets are added later, so subtract them now.
@@ -609,7 +610,7 @@
y -= insets.top;
mGravity = 0;
- if (y + height > dragLayer.getBottom() - insets.bottom) {
+ if ((insets.top + y + height) > (dragLayer.getBottom() - insets.bottom)) {
// The container is opening off the screen, so just center it in the drag layer instead.
mGravity = Gravity.CENTER_VERTICAL;
// Put the container next to the icon, preferring the right side in ltr (left in rtl).
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index 9be3cc5..7e9d56d 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -46,14 +46,22 @@
@Override
public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
DeviceProfile grid = launcher.getDeviceProfile();
- Workspace ws = launcher.getWorkspace();
+ Workspace<?> ws = launcher.getWorkspace();
if (ws.getChildCount() == 0) {
return super.getWorkspaceScaleAndTranslation(launcher);
}
float shrunkTop = grid.getWorkspaceSpringLoadShrunkTop();
float shrunkBottom = grid.getWorkspaceSpringLoadShrunkBottom();
- float scale = (shrunkBottom - shrunkTop) / ws.getNormalChildHeight();
+ float scale = Math.min((shrunkBottom - shrunkTop) / ws.getNormalChildHeight(), 1f);
+
+ // Reduce scale if next pages would not be visible after scaling the workspace
+ float scaledWorkspaceWidth = ws.getWidth() * scale;
+ float maxAvailableWidth =
+ ws.getWidth() - (2 * grid.getWorkspaceSpringLoadedMinimumNextPageVisible());
+ if (scaledWorkspaceWidth > maxAvailableWidth) {
+ scale *= maxAvailableWidth / scaledWorkspaceWidth;
+ }
float halfHeight = ws.getHeight() / 2;
float myCenter = ws.getTop() + halfHeight;
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 2eae99a..ee8f85d 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -108,7 +108,7 @@
case TestProtocol.REQUEST_APPS_LIST_SCROLL_Y: {
return getLauncherUIProperty(Bundle::putInt,
- l -> l.getAppsView().getActiveRecyclerView().getCurrentScrollY());
+ l -> l.getAppsView().getActiveAppsRecyclerView().getCurrentScrollY());
}
case TestProtocol.REQUEST_WIDGETS_SCROLL_Y: {
@@ -178,7 +178,7 @@
case TestProtocol.REQUEST_WORKSPACE_CELL_LAYOUT_SIZE:
return getLauncherUIProperty(Bundle::putIntArray, launcher -> {
- final Workspace workspace = launcher.getWorkspace();
+ final Workspace<?> workspace = launcher.getWorkspace();
final int screenId = workspace.getScreenIdForPageIndex(
workspace.getCurrentPage());
final CellLayout cellLayout = workspace.getScreenWithId(screenId);
@@ -189,7 +189,7 @@
final WorkspaceCellCenterRequest request = extra.getParcelable(
TestProtocol.TEST_INFO_REQUEST_FIELD);
return getLauncherUIProperty(Bundle::putParcelable, launcher -> {
- final Workspace workspace = launcher.getWorkspace();
+ final Workspace<?> workspace = launcher.getWorkspace();
// TODO(b/216387249): allow caller selecting different pages.
CellLayout cellLayout = (CellLayout) workspace.getPageAt(
workspace.getCurrentPage());
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 8d57d69..cd00f15 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -43,6 +43,7 @@
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.folder.Folder;
@@ -58,8 +59,10 @@
import com.android.launcher3.model.data.SearchActionItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.InstallSessionHelper;
+import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
+import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.views.FloatingIconView;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
@@ -67,6 +70,8 @@
import com.android.launcher3.widget.WidgetAddFlowHandler;
import com.android.launcher3.widget.WidgetManagerHelper;
+import java.util.Collections;
+
/**
* Class for handling clicks on workspace and all-apps items
*/
@@ -171,7 +176,8 @@
(d, i) -> startMarketIntentForPackage(v, launcher, packageName))
.setNeutralButton(R.string.abandoned_clean_this,
(d, i) -> launcher.getWorkspace()
- .removeAbandonedPromise(packageName, user))
+ .persistRemoveItemsByMatcher(ItemInfoMatcher.ofPackages(
+ Collections.singleton(packageName), user)))
.create().show();
}
@@ -205,6 +211,12 @@
public static boolean handleDisabledItemClicked(WorkspaceItemInfo shortcut, Context context) {
final int disabledFlags = shortcut.runtimeStatusFlags
& WorkspaceItemInfo.FLAG_DISABLED_MASK;
+ // Handle the case where the disabled reason is DISABLED_REASON_VERSION_LOWER.
+ // Show an AlertDialog for the user to choose either updating the app or cancel the launch.
+ if (maybeCreateAlertDialogForShortcut(shortcut, context)) {
+ return true;
+ }
+
if ((disabledFlags
& ~FLAG_DISABLED_SUSPENDED
& ~FLAG_DISABLED_QUIET_USER) == 0) {
@@ -230,6 +242,37 @@
}
}
+ private static boolean maybeCreateAlertDialogForShortcut(final WorkspaceItemInfo shortcut,
+ Context context) {
+ try {
+ final Launcher launcher = Launcher.getLauncher(context);
+ if (shortcut.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
+ && shortcut.isDisabledVersionLower()) {
+
+ new AlertDialog.Builder(context)
+ .setTitle(R.string.dialog_update_title)
+ .setMessage(R.string.dialog_update_message)
+ .setPositiveButton(R.string.dialog_update, (d, i) -> {
+ // Direct the user to the play store to update the app
+ context.startActivity(shortcut.getMarketIntent(context));
+ })
+ .setNeutralButton(R.string.dialog_remove, (d, i) -> {
+ // Remove the icon if launcher is successfully initialized
+ launcher.getWorkspace().persistRemoveItemsByMatcher(ItemInfoMatcher
+ .ofShortcutKeys(Collections.singleton(ShortcutKey
+ .fromItemInfo(shortcut))));
+ })
+ .create()
+ .show();
+ return true;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error creating alert dialog", e);
+ }
+
+ return false;
+ }
+
/**
* Event handler for an app shortcut click.
*
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index fe0bf6d..17bbdf1 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -64,7 +64,7 @@
private final Rect mTempRect = new Rect();
private final Launcher mLauncher;
- private final Workspace mWorkspace;
+ private final Workspace<?> mWorkspace;
private final PointF mTouchDownPoint = new PointF();
private final float mTouchSlop;
@@ -72,7 +72,7 @@
private final GestureDetector mGestureDetector;
- public WorkspaceTouchListener(Launcher launcher, Workspace workspace) {
+ public WorkspaceTouchListener(Launcher launcher, Workspace<?> workspace) {
mLauncher = launcher;
mWorkspace = workspace;
// Use twice the touch slop as we are looking for long press which is more
diff --git a/src/com/android/launcher3/util/GridOccupancy.java b/src/com/android/launcher3/util/GridOccupancy.java
index 9c752a7..1301460 100644
--- a/src/com/android/launcher3/util/GridOccupancy.java
+++ b/src/com/android/launcher3/util/GridOccupancy.java
@@ -7,7 +7,7 @@
/**
* Utility object to manage the occupancy in a grid.
*/
-public class GridOccupancy {
+public class GridOccupancy extends AbsGridOccupancy {
private final int mCountX;
private final int mCountY;
@@ -30,24 +30,7 @@
* @return true if a vacant cell was found
*/
public boolean findVacantCell(int[] vacantOut, int spanX, int spanY) {
- for (int y = 0; (y + spanY) <= mCountY; y++) {
- for (int x = 0; (x + spanX) <= mCountX; x++) {
- boolean available = !cells[x][y];
- out:
- for (int i = x; i < x + spanX; i++) {
- for (int j = y; j < y + spanY; j++) {
- available = available && !cells[i][j];
- if (!available) break out;
- }
- }
- if (available) {
- vacantOut[0] = x;
- vacantOut[1] = y;
- return true;
- }
- }
- }
- return false;
+ return super.findVacantCell(vacantOut, cells, mCountX, mCountY, spanX, spanY);
}
public void copyTo(GridOccupancy dest) {
diff --git a/src/com/android/launcher3/util/MultiAdditivePropertyFactory.java b/src/com/android/launcher3/util/MultiAdditivePropertyFactory.java
new file mode 100644
index 0000000..50f7027
--- /dev/null
+++ b/src/com/android/launcher3/util/MultiAdditivePropertyFactory.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2022 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.util;
+
+import android.util.ArrayMap;
+import android.util.FloatProperty;
+import android.util.Log;
+import android.util.Property;
+import android.view.View;
+
+/**
+ * Allows to combine multiple values set by several sources.
+ *
+ * The various sources are meant to use [set], providing different `setterIndex` params. When it is
+ * not set, 0 is used. This is meant to cover the case multiple animations are going on at the same
+ * time.
+ *
+ * This class behaves similarly to [MultiValueAlpha], but is meant to be more abstract and reusable.
+ * It sets the addition of all values.
+ *
+ * @param <T> Type where to apply the property.
+ */
+public class MultiAdditivePropertyFactory<T extends View> {
+
+ private static final boolean DEBUG = false;
+ private static final String TAG = "MultiAdditivePropertyFactory";
+ private final String mName;
+ private final ArrayMap<Integer, MultiAdditiveProperty> mProperties =
+ new ArrayMap<>();
+
+ // This is an optimization for cases when set is called repeatedly with the same setterIndex.
+ private float mAggregationOfOthers = 0f;
+ private Integer mLastIndexSet = -1;
+ private final Property<View, Float> mProperty;
+
+ public MultiAdditivePropertyFactory(String name, Property<View, Float> property) {
+ mName = name;
+ mProperty = property;
+ }
+
+ /** Returns the [MultiFloatProperty] associated with [inx], creating it if not present. */
+ public MultiAdditiveProperty get(Integer index) {
+ return mProperties.computeIfAbsent(index,
+ (k) -> new MultiAdditiveProperty(index, mName + "_" + index));
+ }
+
+ /**
+ * Each [setValue] will be aggregated with the other properties values created by the
+ * corresponding factory.
+ */
+ class MultiAdditiveProperty extends FloatProperty<T> {
+ private final int mInx;
+ private float mValue = 0f;
+
+ MultiAdditiveProperty(int inx, String name) {
+ super(name);
+ mInx = inx;
+ }
+
+ @Override
+ public void setValue(T obj, float newValue) {
+ if (mLastIndexSet != mInx) {
+ mAggregationOfOthers = 0f;
+ mProperties.forEach((key, property) -> {
+ if (key != mInx) {
+ mAggregationOfOthers += property.mValue;
+ }
+ });
+ mLastIndexSet = mInx;
+ }
+ float lastAggregatedValue = mAggregationOfOthers + newValue;
+ mValue = newValue;
+ apply(obj, lastAggregatedValue);
+
+ if (DEBUG) {
+ Log.d(TAG, "name=" + mName
+ + " newValue=" + newValue + " mInx=" + mInx
+ + " aggregated=" + lastAggregatedValue + " others= " + mProperties);
+ }
+ }
+
+ @Override
+ public Float get(T view) {
+ // The scale of the view should match mLastAggregatedValue. Still, if it has been
+ // changed without using this property, it can differ. As this get method is usually
+ // used to set the starting point on an animation, this would result in some jumps
+ // when the view scale is different than the last aggregated value. To stay on the
+ // safe side, let's return the real view scale.
+ return mProperty.get(view);
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(mValue);
+ }
+ }
+
+ protected void apply(View view, float value) {
+ mProperty.set(view, value);
+ }
+}
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java
index 39d7cfe..c1e4fa8 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.java
+++ b/src/com/android/launcher3/util/OnboardingPrefs.java
@@ -38,8 +38,9 @@
public static final String HOME_BOUNCE_COUNT = "launcher.home_bounce_count";
public static final String HOTSEAT_DISCOVERY_TIP_COUNT = "launcher.hotseat_discovery_tip_count";
public static final String HOTSEAT_LONGPRESS_TIP_SEEN = "launcher.hotseat_longpress_tip_seen";
- public static final String SEARCH_EDU_SEEN = "launcher.search_edu_seen";
+ public static final String SEARCH_KEYBOARD_EDU_SEEN = "launcher.search_edu_seen";
public static final String SEARCH_SNACKBAR_COUNT = "launcher.keyboard_snackbar_count";
+ public static final String SEARCH_ONBOARDING_COUNT = "launcher.search_onboarding_count";
public static final String TASKBAR_EDU_SEEN = "launcher.taskbar_edu_seen";
public static final String ALL_APPS_VISITED_COUNT = "launcher.all_apps_visited_count";
// When adding a new key, add it here as well, to be able to reset it from Developer Options.
@@ -47,7 +48,8 @@
"All Apps Bounce", new String[] { HOME_BOUNCE_SEEN, HOME_BOUNCE_COUNT },
"Hybrid Hotseat Education", new String[] { HOTSEAT_DISCOVERY_TIP_COUNT,
HOTSEAT_LONGPRESS_TIP_SEEN },
- "Search Education", new String[] { SEARCH_EDU_SEEN, SEARCH_SNACKBAR_COUNT },
+ "Search Education", new String[] { SEARCH_KEYBOARD_EDU_SEEN, SEARCH_SNACKBAR_COUNT,
+ SEARCH_ONBOARDING_COUNT},
"Taskbar Education", new String[] { TASKBAR_EDU_SEEN },
"All Apps Visited Count", new String[] {ALL_APPS_VISITED_COUNT}
);
@@ -58,12 +60,11 @@
@StringDef(value = {
HOME_BOUNCE_SEEN,
HOTSEAT_LONGPRESS_TIP_SEEN,
- SEARCH_EDU_SEEN,
+ SEARCH_KEYBOARD_EDU_SEEN,
TASKBAR_EDU_SEEN
})
@Retention(RetentionPolicy.SOURCE)
- public @interface EventBoolKey {
- }
+ public @interface EventBoolKey {}
/**
* Events that occur multiple times, which we count up to a max defined in {@link #MAX_COUNTS}.
@@ -72,19 +73,21 @@
HOME_BOUNCE_COUNT,
HOTSEAT_DISCOVERY_TIP_COUNT,
SEARCH_SNACKBAR_COUNT,
+ SEARCH_ONBOARDING_COUNT,
ALL_APPS_VISITED_COUNT
})
@Retention(RetentionPolicy.SOURCE)
- public @interface EventCountKey {
- }
+ public @interface EventCountKey {}
private static final Map<String, Integer> MAX_COUNTS;
static {
- Map<String, Integer> maxCounts = new ArrayMap<>(4);
+ Map<String, Integer> maxCounts = new ArrayMap<>(5);
maxCounts.put(HOME_BOUNCE_COUNT, 3);
maxCounts.put(HOTSEAT_DISCOVERY_TIP_COUNT, 5);
maxCounts.put(SEARCH_SNACKBAR_COUNT, 3);
+ // This is the sum of all onboarding cards. Currently there is only 1 card shown 3 times.
+ maxCounts.put(SEARCH_ONBOARDING_COUNT, 3);
maxCounts.put(ALL_APPS_VISITED_COUNT, 20);
MAX_COUNTS = Collections.unmodifiableMap(maxCounts);
}
diff --git a/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java b/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java
index f1276dd..43e9820 100644
--- a/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java
+++ b/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java
@@ -32,7 +32,7 @@
// Don't use all the wallpaper for parallax until you have at least this many pages
private static final int MIN_PARALLAX_PAGE_SPAN = 4;
- private final Workspace mWorkspace;
+ private final Workspace<?> mWorkspace;
private final boolean mIsRtl;
private final Handler mHandler;
@@ -43,7 +43,7 @@
private boolean mLockedToDefaultPage;
private int mNumScreens;
- public WallpaperOffsetInterpolator(Workspace workspace) {
+ public WallpaperOffsetInterpolator(Workspace<?> workspace) {
mWorkspace = workspace;
mIsRtl = Utilities.isRtl(workspace.getResources());
mHandler = new OffsetHandler(workspace.getContext());
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 56a1d37..babe607 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -49,7 +49,6 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.icons.FastBitmapDrawable;
@@ -413,8 +412,7 @@
@WorkerThread
@SuppressWarnings("WrongThread")
private static int getOffsetForIconBounds(Launcher l, Drawable drawable, RectF position) {
- if (!(drawable instanceof AdaptiveIconDrawable)
- || (drawable instanceof FolderAdaptiveIcon)) {
+ if (!(drawable instanceof AdaptiveIconDrawable)) {
return 0;
}
int blurSizeOutline =
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index a982786..5f6e453 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -43,7 +43,7 @@
import androidx.annotation.RequiresApi;
import androidx.recyclerview.widget.RecyclerView;
-import com.android.launcher3.BaseRecyclerView;
+import com.android.launcher3.FastScrollRecyclerView;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.graphics.FastScrollThumbDrawable;
@@ -127,7 +127,7 @@
private String mPopupSectionName;
private Insets mSystemGestureInsets;
- protected BaseRecyclerView mRv;
+ protected FastScrollRecyclerView mRv;
private RecyclerView.OnScrollListener mOnScrollListener;
private int mDownX;
@@ -172,7 +172,7 @@
ta.recycle();
}
- public void setRecyclerView(BaseRecyclerView rv, TextView popupView) {
+ public void setRecyclerView(FastScrollRecyclerView rv, TextView popupView) {
if (mRv != null && mOnScrollListener != null) {
mRv.removeOnScrollListener(mOnScrollListener);
}
diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index 1f6551e..130ee3a 100644
--- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -18,7 +18,6 @@
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
import static com.android.launcher3.icons.FastBitmapDrawable.getDisabledColorFilter;
-import static com.android.launcher3.widget.WidgetSections.getWidgetSections;
import android.content.Context;
import android.graphics.Canvas;
@@ -341,8 +340,6 @@
if (mInfo.pendingItemInfo.widgetCategory == WidgetSections.NO_CATEGORY) {
return null;
}
- Context context = getContext();
- return context.getDrawable(getWidgetSections(context).get(
- mInfo.pendingItemInfo.widgetCategory).mSectionDrawable);
+ return mInfo.pendingItemInfo.newIcon(getContext());
}
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
index 932e06d..b0e2ec1 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.widget.picker;
-import static com.android.launcher3.widget.WidgetSections.NO_CATEGORY;
import android.content.Context;
import android.content.res.Resources;
@@ -43,8 +42,6 @@
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.util.PluralMessageFormat;
import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.widget.WidgetSections;
-import com.android.launcher3.widget.WidgetSections.WidgetSection;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
@@ -177,13 +174,7 @@
private void setIcon(PackageItemInfo info) {
Drawable icon;
- if (info.widgetCategory == NO_CATEGORY) {
- icon = info.newIcon(getContext());
- } else {
- WidgetSection widgetSection = WidgetSections.getWidgetSections(getContext())
- .get(info.widgetCategory);
- icon = getContext().getDrawable(widgetSection.mSectionDrawable);
- }
+ icon = info.newIcon(getContext());
applyDrawables(icon);
mIconDrawable = icon;
if (mIconDrawable != null) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
index f780f03..ea62c17 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
@@ -27,8 +27,8 @@
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
-import com.android.launcher3.BaseRecyclerView;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.FastScrollRecyclerView;
import com.android.launcher3.R;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.widget.model.WidgetListSpaceEntry;
@@ -41,7 +41,7 @@
/**
* The widgets recycler view.
*/
-public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouchListener {
+public class WidgetsRecyclerView extends FastScrollRecyclerView implements OnItemTouchListener {
private WidgetsListAdapter mAdapter;
diff --git a/src_shortcuts_overrides/com/android/launcher3/util/AbsGridOccupancy.java b/src_shortcuts_overrides/com/android/launcher3/util/AbsGridOccupancy.java
new file mode 100644
index 0000000..968b281
--- /dev/null
+++ b/src_shortcuts_overrides/com/android/launcher3/util/AbsGridOccupancy.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 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.util;
+
+/**
+ * Defines method to find the next vacant cell on a grid.
+ * This uses the default top-down, left-right approach and can be over-written through
+ * code swaps in different launchers.
+ */
+public abstract class AbsGridOccupancy {
+ /**
+ * Find the first vacant cell, if there is one.
+ *
+ * @param vacantOut Holds the x and y coordinate of the vacant cell
+ * @param spanX Horizontal cell span.
+ * @param spanY Vertical cell span.
+ *
+ * @return true if a vacant cell was found
+ */
+ protected boolean findVacantCell(int[] vacantOut, boolean[][] cells, int countX, int countY,
+ int spanX, int spanY) {
+ for (int y = 0; (y + spanY) <= countY; y++) {
+ for (int x = 0; (x + spanX) <= countX; x++) {
+ boolean available = !cells[x][y];
+ out:
+ for (int i = x; i < x + spanX; i++) {
+ for (int j = y; j < y + spanY; j++) {
+ available = available && !cells[i][j];
+ if (!available) break out;
+ }
+ }
+ if (available) {
+ vacantOut[0] = x;
+ vacantOut[1] = y;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/tests/Android.bp b/tests/Android.bp
index 7542d04..54cded0 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -37,6 +37,7 @@
"src/com/android/launcher3/util/WidgetUtils.java",
"src/com/android/launcher3/util/rule/FailureWatcher.java",
"src/com/android/launcher3/util/rule/LauncherActivityRule.java",
+ "src/com/android/launcher3/util/rule/SamplerRule.java",
"src/com/android/launcher3/util/rule/ScreenRecordRule.java",
"src/com/android/launcher3/util/rule/ShellCommandRule.java",
"src/com/android/launcher3/util/rule/SimpleActivityRule.java",
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 136f115..9b37741 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -68,6 +68,7 @@
import com.android.launcher3.util.WidgetUtils;
import com.android.launcher3.util.rule.FailureWatcher;
import com.android.launcher3.util.rule.LauncherActivityRule;
+import com.android.launcher3.util.rule.SamplerRule;
import com.android.launcher3.util.rule.ScreenRecordRule;
import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.util.rule.TestStabilityRule;
@@ -227,7 +228,8 @@
@Rule
public TestRule mOrderSensitiveRules = RuleChain
- .outerRule(new TestStabilityRule())
+ .outerRule(new SamplerRule())
+ .around(new TestStabilityRule())
.around(mActivityMonitor)
.around(getRulesInsideActivityMonitor());
@@ -523,7 +525,7 @@
}
protected int getAllAppsScroll(Launcher launcher) {
- return launcher.getAppsView().getActiveRecyclerView().getCurrentScrollY();
+ return launcher.getAppsView().getActiveAppsRecyclerView().getCurrentScrollY();
}
private void checkLauncherIntegrity(
diff --git a/tests/src/com/android/launcher3/ui/WorkProfileTest.java b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
index f31e4f3..13b93d1 100644
--- a/tests/src/com/android/launcher3/ui/WorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
@@ -134,8 +134,8 @@
executeOnLauncher(l -> {
ActivityAllAppsContainerView<?> allApps = l.getAppsView();
assertEquals("Work tab is not focused", allApps.getCurrentPage(), WORK_PAGE);
- View workPausedCard = allApps.getActiveRecyclerView().findViewHolderForAdapterPosition(
- 0).itemView;
+ View workPausedCard = allApps.getActiveAppsRecyclerView()
+ .findViewHolderForAdapterPosition(0).itemView;
workPausedCard.findViewById(R.id.enable_work_apps).performClick();
});
waitForLauncherCondition("Work profile toggle ON failed", launcher -> {
@@ -155,7 +155,7 @@
});
waitForLauncherCondition("Work profile education not shown",
- l -> l.getAppsView().getActiveRecyclerView()
+ l -> l.getAppsView().getActiveAppsRecyclerView()
.findViewHolderForAdapterPosition(0).itemView instanceof WorkEduCard,
LauncherInstrumentation.WAIT_TIME_MS);
}
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index 9fb52fc..0db719e 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -15,6 +15,9 @@
*/
package com.android.launcher3.ui.widget;
+import static android.app.PendingIntent.FLAG_MUTABLE;
+import static android.app.PendingIntent.FLAG_ONE_SHOT;
+
import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
import static org.junit.Assert.assertNotNull;
@@ -144,7 +147,7 @@
// Set callback
PendingIntent callback = PendingIntent.getBroadcast(mTargetContext, 0,
- new Intent(mCallbackAction), PendingIntent.FLAG_ONE_SHOT);
+ new Intent(mCallbackAction), FLAG_ONE_SHOT | FLAG_MUTABLE);
mTargetContext.sendBroadcast(RequestPinItemActivity.getCommandIntent(
RequestPinItemActivity.class, "setCallback").putExtra(
RequestPinItemActivity.EXTRA_PARAM + "0", callback));
diff --git a/tests/src/com/android/launcher3/util/MultiAdditivePropertyTest.kt b/tests/src/com/android/launcher3/util/MultiAdditivePropertyTest.kt
new file mode 100644
index 0000000..309d055
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/MultiAdditivePropertyTest.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 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.util
+
+import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Unit tests for [MultiAdditivePropertyFactory] */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MultiAdditivePropertyTest {
+
+ private val received = mutableListOf<Float>()
+
+ private val factory =
+ object : MultiAdditivePropertyFactory<View?>("Test", View.TRANSLATION_X) {
+ override fun apply(obj: View?, value: Float) {
+ received.add(value)
+ }
+ }
+
+ private val p1 = factory.get(1)
+ private val p2 = factory.get(2)
+ private val p3 = factory.get(3)
+
+ @Test
+ fun set_sameIndexes_allApplied() {
+ val v1 = 50f
+ val v2 = 100f
+ p1.set(null, v1)
+ p1.set(null, v1)
+ p1.set(null, v2)
+
+ assertThat(received).containsExactly(v1, v1, v2)
+ }
+
+ @Test
+ fun set_differentIndexes_aggregationApplied() {
+ val v1 = 50f
+ val v2 = 100f
+ val v3 = 150f
+ p1.set(null, v1)
+ p2.set(null, v2)
+ p3.set(null, v3)
+
+ assertThat(received).containsExactly(v1, v1 + v2, v1 + v2 + v3)
+ }
+}
diff --git a/tests/src/com/android/launcher3/util/MultiScalePropertyTest.kt b/tests/src/com/android/launcher3/util/MultiScalePropertyTest.kt
index 6099987..7d92214 100644
--- a/tests/src/com/android/launcher3/util/MultiScalePropertyTest.kt
+++ b/tests/src/com/android/launcher3/util/MultiScalePropertyTest.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2022 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.util
import android.view.View
diff --git a/tests/src/com/android/launcher3/util/rule/SamplerRule.java b/tests/src/com/android/launcher3/util/rule/SamplerRule.java
new file mode 100644
index 0000000..6125f2a
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/rule/SamplerRule.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2022 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.util.rule;
+
+import android.os.SystemClock;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * A rule that generates a file that helps diagnosing cases when the test process was terminated
+ * because the test execution took too long, and tests that ran for too long even without being
+ * terminated. If the process was terminated or the test was long, the test leaves an artifact with
+ * stack traces of all threads, every SAMPLE_INTERVAL_MS. This will help understanding where we
+ * stuck.
+ */
+public class SamplerRule implements TestRule {
+ private static final int TOO_LONG_TEST_MS = 180000;
+ private static final int SAMPLE_INTERVAL_MS = 3000;
+
+ public static Thread startThread(Description description) {
+ Thread thread =
+ new Thread() {
+ @Override
+ public void run() {
+ // Write all-threads stack stace every SAMPLE_INTERVAL_MS while the test
+ // is running.
+ // After the test finishes, delete that file. If the test process is
+ // terminated due to timeout, the trace file won't be deleted.
+ final File file = getFile();
+
+ final long startTime = SystemClock.elapsedRealtime();
+ try (OutputStreamWriter outputStreamWriter =
+ new OutputStreamWriter(
+ new BufferedOutputStream(
+ new FileOutputStream(file)))) {
+ writeSamples(outputStreamWriter);
+ } catch (IOException | InterruptedException e) {
+ // Simply suppressing the exceptions, nothing to do here.
+ } finally {
+ // If the process is not killed, then there was no test timeout, and
+ // we are not interested in the trace file, unless the test ran too
+ // long.
+ if (SystemClock.elapsedRealtime() - startTime < TOO_LONG_TEST_MS) {
+ file.delete();
+ }
+ }
+ }
+
+ private File getFile() {
+ final String strDate = new SimpleDateFormat("HH:mm:ss").format(new Date());
+
+ final String descStr = description.getTestClass().getSimpleName() + "."
+ + description.getMethodName();
+ return artifactFile(
+ "ThreadStackSamples-" + strDate + "-" + descStr + ".txt");
+ }
+
+ private void writeSamples(OutputStreamWriter writer)
+ throws IOException, InterruptedException {
+ int count = 0;
+ while (true) {
+ writer.write(
+ "#"
+ + (count++)
+ + " =============================================\r\n");
+ for (StackTraceElement[] stack : getAllStackTraces().values()) {
+ writer.write("---------------------\r\n");
+ for (StackTraceElement frame : stack) {
+ writer.write(frame.toString() + "\r\n");
+ }
+ }
+ writer.flush();
+
+ sleep(SAMPLE_INTERVAL_MS);
+ }
+ }
+ };
+
+ thread.start();
+ return thread;
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ final Thread traceThread = startThread(description);
+ try {
+ base.evaluate();
+ } finally {
+ traceThread.interrupt();
+ traceThread.join();
+ }
+ }
+ };
+ }
+
+ private static File artifactFile(String fileName) {
+ return new File(
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getFilesDir(),
+ fileName);
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 950e72c..afb4f8d 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -227,11 +227,6 @@
public LauncherInstrumentation(Instrumentation instrumentation) {
mInstrumentation = instrumentation;
mDevice = UiDevice.getInstance(instrumentation);
- try {
- mDevice.executeShellCommand("am wait-for-broadcast-idle");
- } catch (IOException e) {
- log("Failed to wait for broadcast idle");
- }
// Launcher should run in test harness so that custom accessibility protocol between
// Launcher and TAPL is enabled. In-process tests enable this protocol with a direct call