Merge "Default ENABLE_PREDICTION_DISMISS to true" into ub-launcher3-master
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index d747bb8..6d105ac 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -71,6 +71,7 @@
<application
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
android:fullBackupOnly="true"
+ android:backupInForeground="true"
android:fullBackupContent="@xml/backupscheme"
android:hardwareAccelerated="true"
android:icon="@drawable/ic_launcher_home"
diff --git a/quickstep/AndroidManifest-launcher.xml b/quickstep/AndroidManifest-launcher.xml
index 60afddb..527bfc3 100644
--- a/quickstep/AndroidManifest-launcher.xml
+++ b/quickstep/AndroidManifest-launcher.xml
@@ -52,7 +52,7 @@
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
- android:taskAffinity=""
+ android:taskAffinity="${packageName}.launcher"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index a06a2dd..d360613 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -93,6 +93,7 @@
android:name="com.android.quickstep.interaction.GestureSandboxActivity"
android:autoRemoveFromRecents="true"
android:excludeFromRecents="true"
+ android:taskAffinity="${packageName}.launcher"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="com.android.quickstep.action.GESTURE_SANDBOX" />
diff --git a/quickstep/recents_ui_overrides/res/layout/fallback_recents_activity.xml b/quickstep/recents_ui_overrides/res/layout/fallback_recents_activity.xml
index ef272ed..686189e 100644
--- a/quickstep/recents_ui_overrides/res/layout/fallback_recents_activity.xml
+++ b/quickstep/recents_ui_overrides/res/layout/fallback_recents_activity.xml
@@ -28,4 +28,9 @@
android:clipToPadding="false"
android:outlineProvider="none"
android:theme="@style/HomeScreenElementTheme" />
+
+ <include
+ android:id="@+id/overview_actions_view"
+ layout="@layout/overview_actions_holder" />
+
</com.android.quickstep.fallback.RecentsRootView>
diff --git a/quickstep/recents_ui_overrides/res/layout/overview_panel.xml b/quickstep/recents_ui_overrides/res/layout/overview_panel.xml
index a572cad..eac0bfa 100644
--- a/quickstep/recents_ui_overrides/res/layout/overview_panel.xml
+++ b/quickstep/recents_ui_overrides/res/layout/overview_panel.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,17 +13,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.launcher3.InsettableFrameLayout
+<com.android.quickstep.views.LauncherRecentsView
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- <com.android.quickstep.views.LauncherRecentsView
- android:id="@+id/overview_panel_recents"
- android:theme="@style/HomeScreenElementTheme"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:accessibilityPaneTitle="@string/accessibility_recent_apps"
- android:visibility="invisible" />
-</com.android.launcher3.InsettableFrameLayout>
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:accessibilityPaneTitle="@string/accessibility_recent_apps"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:theme="@style/HomeScreenElementTheme"
+ android:visibility="invisible" />
diff --git a/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml b/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml
index fe99037..c93cad6 100644
--- a/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml
+++ b/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml
@@ -35,25 +35,27 @@
<TextView
style="@style/TextHeadline"
+ android:id="@+id/hotseat_edu_heading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="18dp"
android:paddingLeft="@dimen/bottom_sheet_edu_padding"
android:paddingRight="@dimen/bottom_sheet_edu_padding"
- android:text="@string/hotseat_migrate_title"
+ android:text="@string/hotseat_edu_title_migrate"
android:textAlignment="center"
android:textColor="@android:color/white"
android:textSize="20sp" />
<TextView
android:layout_width="match_parent"
+ android:id="@+id/hotseat_edu_content"
android:layout_height="wrap_content"
android:layout_marginTop="18dp"
android:layout_marginBottom="18dp"
android:fontFamily="roboto-medium"
android:paddingLeft="@dimen/bottom_sheet_edu_padding"
android:paddingRight="@dimen/bottom_sheet_edu_padding"
- android:text="@string/hotseat_migrate_message"
+ android:text="@string/hotseat_edu_message_migrate"
android:textAlignment="center"
android:textColor="@android:color/white"
android:textSize="16sp" />
@@ -83,7 +85,7 @@
android:layout_height="wrap_content"
android:layout_gravity="end"
android:background="?android:attr/selectableItemBackground"
- android:text="@string/hotseat_migrate_accept"
+ android:text="@string/hotseat_edu_accept"
android:textAlignment="textEnd"
android:textColor="@android:color/white" />
@@ -91,7 +93,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/no_thanks"
- android:text="@string/hotseat_migrate_dismiss"
+ android:text="@string/hotseat_edu_dismiss"
android:layout_gravity="start"
android:background="?android:attr/selectableItemBackground"
android:textColor="@android:color/white" />
diff --git a/quickstep/recents_ui_overrides/res/values/dimens.xml b/quickstep/recents_ui_overrides/res/values/dimens.xml
index de97d08..61c576e 100644
--- a/quickstep/recents_ui_overrides/res/values/dimens.xml
+++ b/quickstep/recents_ui_overrides/res/values/dimens.xml
@@ -23,10 +23,4 @@
<!-- Minimum distance to swipe to trigger accessibility gesture -->
<dimen name="accessibility_gesture_min_swipe_distance">80dp</dimen>
-
- <!-- Swipe up to home related -->
- <dimen name="swipe_up_fling_min_visible_change">18dp</dimen>
- <dimen name="swipe_up_y_overshoot">10dp</dimen>
- <dimen name="swipe_up_max_workspace_trans_y">-60dp</dimen>
-
</resources>
\ No newline at end of file
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
index e7290a4..a07cd1d 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
@@ -27,11 +27,15 @@
import androidx.core.app.NotificationCompat;
+import com.android.launcher3.CellLayout;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
+import com.android.launcher3.Workspace;
import com.android.launcher3.WorkspaceItemInfo;
+import com.android.launcher3.WorkspaceLayoutManager;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.Themes;
@@ -61,16 +65,25 @@
mNotification = createNotification();
}
- void migrate() {
+ boolean migrate() {
+ Workspace workspace = mLauncher.getWorkspace();
+ CellLayout firstScreen = workspace.getScreenWithId(WorkspaceLayoutManager.FIRST_SCREEN_ID);
+ int toPage = Workspace.FIRST_SCREEN_ID;
+ int toRow = mLauncher.getDeviceProfile().inv.numRows - 1;
+ if (FeatureFlags.HOTSEAT_MIGRATE_NEW_PAGE.get()) {
+ toPage = workspace.getScreenIdForPageIndex(workspace.getPageCount());
+ toRow = 0;
+ } else if (!firstScreen.makeSpaceForHotseatMigration(true)) {
+ return false;
+ }
ViewGroup hotseatVG = mLauncher.getHotseat().getShortcutsAndWidgets();
- int workspacePageCount = mLauncher.getWorkspace().getPageCount();
for (int i = 0; i < hotseatVG.getChildCount(); i++) {
View child = hotseatVG.getChildAt(i);
ItemInfo tag = (ItemInfo) child.getTag();
mLauncher.getModelWriter().moveItemInDatabase(tag,
- LauncherSettings.Favorites.CONTAINER_DESKTOP, workspacePageCount, tag.screenId,
- 0);
+ LauncherSettings.Favorites.CONTAINER_DESKTOP, toPage, tag.screenId, toRow);
}
+ return true;
}
void removeNotification() {
@@ -93,7 +106,7 @@
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return;
- CharSequence name = mLauncher.getString(R.string.hotseat_migrate_title);
+ CharSequence name = mLauncher.getString(R.string.hotseat_edu_prompt_title);
int importance = NotificationManager.IMPORTANCE_LOW;
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, name,
importance);
@@ -104,8 +117,8 @@
Intent intent = new Intent(mLauncher.getApplicationContext(), mLauncher.getClass());
intent = new NotificationHandler().addToIntent(intent);
- CharSequence name = mLauncher.getString(R.string.hotseat_migrate_prompt_title);
- String description = mLauncher.getString(R.string.hotseat_migrate_prompt_content);
+ CharSequence name = mLauncher.getString(R.string.hotseat_edu_prompt_title);
+ String description = mLauncher.getString(R.string.hotseat_edu_prompt_content);
NotificationCompat.Builder builder = new NotificationCompat.Builder(mLauncher,
NOTIFICATION_CHANNEL_ID)
.setContentTitle(name)
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
index 8926246..538b7f3 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
@@ -26,6 +26,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
+import android.widget.TextView;
import android.widget.Toast;
import com.android.launcher3.CellLayout;
@@ -34,7 +35,9 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.WorkspaceItemInfo;
+import com.android.launcher3.WorkspaceLayoutManager;
import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.uioverrides.PredictedAppIcon;
import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -49,12 +52,24 @@
public class HotseatEduDialog extends AbstractSlideInView implements Insettable {
private static final int DEFAULT_CLOSE_DURATION = 200;
+ protected static final int FINAL_SCRIM_BG_COLOR = 0x88000000;
- public static boolean shown = false;
+ // We don't migrate if user has more than SAME_PAGE_MAX_ROWS rows of item in their screen
+ private static final int SAME_PAGE_MAX_ROWS = 2;
+
+ private static final int MIGRATE_SAME_PAGE = 0;
+ private static final int MIGRATE_NEW_PAGE = 1;
+ private static final int MIGRATE_NO_MIGRATE = 2;
+
private final Rect mInsets = new Rect();
private View mHotseatWrapper;
private CellLayout mSampleHotseat;
+ private TextView mEduHeading;
+ private TextView mEduContent;
+ private Button mDismissBtn;
+
+ private int mMigrationMode = MIGRATE_SAME_PAGE;
public void setHotseatEduController(HotseatEduController hotseatEduController) {
mHotseatEduController = hotseatEduController;
@@ -78,6 +93,8 @@
super.onFinishInflate();
mHotseatWrapper = findViewById(R.id.hotseat_wrapper);
mSampleHotseat = findViewById(R.id.sample_prediction);
+ mEduHeading = findViewById(R.id.hotseat_edu_heading);
+ mEduContent = findViewById(R.id.hotseat_edu_content);
DeviceProfile grid = mLauncher.getDeviceProfile();
Rect padding = grid.getHotseatLayoutPadding();
@@ -87,24 +104,27 @@
mSampleHotseat.setPadding(padding.left, 0, padding.right, 0);
Button turnOnBtn = findViewById(R.id.turn_predictions_on);
- turnOnBtn.setOnClickListener(this::onMigrate);
+ turnOnBtn.setOnClickListener(this::onAccept);
- Button learnMoreBtn = findViewById(R.id.no_thanks);
- learnMoreBtn.setOnClickListener(this::onKeepDefault);
+ mDismissBtn = findViewById(R.id.no_thanks);
+ mDismissBtn.setOnClickListener(this::onDismiss);
}
- private void onMigrate(View v) {
- if (mHotseatEduController == null) return;
+ private void onAccept(View v) {
+ if (mMigrationMode == MIGRATE_NO_MIGRATE || !mHotseatEduController.migrate()) {
+ onDismiss(v);
+ return;
+ }
handleClose(true);
- mHotseatEduController.migrate();
mHotseatEduController.finishOnboarding();
logUserAction(true);
- Toast.makeText(mLauncher, R.string.hotseat_items_migrated, Toast.LENGTH_LONG).show();
+ int toastStringRes = mMigrationMode == MIGRATE_SAME_PAGE
+ ? R.string.hotseat_items_migrated : R.string.hotseat_items_migrated_alt;
+ Toast.makeText(mLauncher, toastStringRes, Toast.LENGTH_LONG).show();
}
- private void onKeepDefault(View v) {
- if (mHotseatEduController == null) return;
+ private void onDismiss(View v) {
Toast.makeText(getContext(), R.string.hotseat_no_migration, Toast.LENGTH_LONG).show();
mHotseatEduController.finishOnboarding();
logUserAction(false);
@@ -148,6 +168,8 @@
target.tipType = LauncherLogProto.TipType.HYBRID_HOTSEAT;
target.controlType = migrated ? LauncherLogProto.ControlType.HYBRID_HOTSEAT_ACCEPTED
: HYBRID_HOTSEAT_CANCELED;
+ // encoding migration type on pageIndex
+ target.pageIndex = mMigrationMode;
LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null);
}
@@ -161,6 +183,7 @@
LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null);
}
+
private void animateOpen() {
if (mIsOpen || mOpenCloseAnimator.isRunning()) {
return;
@@ -183,17 +206,12 @@
handleClose(false);
}
- /**
- * Opens User education dialog with a list of suggested apps
- */
- public void show(List<WorkspaceItemInfo> predictions) {
- if (getParent() != null
- || predictions.size() < mLauncher.getDeviceProfile().inv.numHotseatIcons) {
- return;
- }
- attachToContainer();
- logOnBoardingSeen();
- animateOpen();
+ @Override
+ protected int getScrimColor(Context context) {
+ return FINAL_SCRIM_BG_COLOR;
+ }
+
+ private void populatePreview(List<WorkspaceItemInfo> predictions) {
for (int i = 0; i < mLauncher.getDeviceProfile().inv.numHotseatIcons; i++) {
WorkspaceItemInfo info = predictions.get(i);
PredictedAppIcon icon = PredictedAppIcon.createIcon(mSampleHotseat, info);
@@ -204,6 +222,43 @@
}
}
+ @Override
+ protected void attachToContainer() {
+ super.attachToContainer();
+ if (FeatureFlags.HOTSEAT_MIGRATE_NEW_PAGE.get()) {
+ mEduContent.setText(R.string.hotseat_edu_message_migrate_alt);
+ mMigrationMode = MIGRATE_NEW_PAGE;
+ return;
+ }
+ CellLayout page = mLauncher.getWorkspace().getScreenWithId(
+ WorkspaceLayoutManager.FIRST_SCREEN_ID);
+
+ int maxItemsOnPage = SAME_PAGE_MAX_ROWS * mLauncher.getDeviceProfile().inv.numColumns
+ + (FeatureFlags.QSB_ON_FIRST_SCREEN ? 1 : 0);
+ if (page.getShortcutsAndWidgets().getChildCount() > maxItemsOnPage
+ || !page.makeSpaceForHotseatMigration(false)) {
+ mMigrationMode = MIGRATE_NO_MIGRATE;
+ mEduContent.setText(R.string.hotseat_edu_message_no_migrate);
+ mEduHeading.setText(R.string.hotseat_edu_title_no_migrate);
+ mDismissBtn.setVisibility(GONE);
+ }
+ }
+
+ /**
+ * Opens User education dialog with a list of suggested apps
+ */
+ public void show(List<WorkspaceItemInfo> predictions) {
+ if (getParent() != null
+ || predictions.size() < mLauncher.getDeviceProfile().inv.numHotseatIcons
+ || mHotseatEduController == null) {
+ return;
+ }
+ attachToContainer();
+ logOnBoardingSeen();
+ animateOpen();
+ populatePreview(predictions);
+ }
+
/**
* Factory method for HotseatPredictionUserEdu dialog
*/
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
index f50bb3e..a17476e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -45,6 +45,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.model.PagedViewOrientedState;
import com.android.launcher3.states.RotationHelper;
import com.android.launcher3.touch.PagedOrientationHandler;
@@ -146,8 +147,8 @@
VibratorWrapper.INSTANCE.get(mContext).vibrate(OVERVIEW_HAPTIC);
}
- public Consumer<MotionEvent> getRecentsViewDispatcher() {
- return mRecentsView != null ? mRecentsView.getEventDispatcher() : null;
+ public Consumer<MotionEvent> getRecentsViewDispatcher(RotationMode navBarRotationMode) {
+ return mRecentsView != null ? mRecentsView.getEventDispatcher(navBarRotationMode) : null;
}
@UiThread
@@ -447,7 +448,7 @@
RotationHelper.mapInverseRectFromNormalOrientation(startRect,
mDp.widthPx, mDp.heightPx, mOrientedState.getDisplayRotation());
}
- RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext.getResources());
+ RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext);
if (isFloatingIconView) {
FloatingIconView fiv = (FloatingIconView) floatingView;
anim.addAnimatorListener(fiv);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index bd9f330..893868b 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -176,7 +176,8 @@
// Proxy events to recents view
if (mPassedWindowMoveSlop && mInteractionHandler != null
&& !mRecentsViewDispatcher.hasConsumer()) {
- mRecentsViewDispatcher.setConsumer(mInteractionHandler.getRecentsViewDispatcher());
+ mRecentsViewDispatcher.setConsumer(mInteractionHandler
+ .getRecentsViewDispatcher(mNavBarPosition.getRotationMode()));
}
int edgeFlags = ev.getEdgeFlags();
ev.setEdgeFlags(edgeFlags | EDGE_NAV_BAR);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
index 682c92c..dde7605 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -17,7 +17,6 @@
import android.animation.Animator;
import android.content.Context;
-import android.content.res.Resources;
import android.graphics.PointF;
import android.graphics.RectF;
@@ -106,7 +105,7 @@
private float mMinVisChange;
private float mYOvershoot;
- public RectFSpringAnim(RectF startRect, RectF targetRect, Resources resources) {
+ public RectFSpringAnim(RectF startRect, RectF targetRect, Context context) {
mStartRect = startRect;
mTargetRect = targetRect;
mCurrentCenterX = mStartRect.centerX();
@@ -114,8 +113,9 @@
mTrackingBottomY = startRect.bottom < targetRect.bottom;
mCurrentY = mTrackingBottomY ? mStartRect.bottom : mStartRect.top;
- mMinVisChange = resources.getDimensionPixelSize(R.dimen.swipe_up_fling_min_visible_change);
- mYOvershoot = resources.getDimensionPixelSize(R.dimen.swipe_up_y_overshoot);
+ ResourceProvider rp = DynamicResource.provider(context);
+ mMinVisChange = rp.getDimension(R.dimen.swipe_up_fling_min_visible_change);
+ mYOvershoot = rp.getDimension(R.dimen.swipe_up_y_overshoot);
}
public void onTargetPositionChanged() {
@@ -160,7 +160,7 @@
float endX = mTargetRect.centerX();
float minXValue = Math.min(startX, endX);
float maxXValue = Math.max(startX, endX);
- mRectXAnim = new FlingSpringAnim(this, RECT_CENTER_X, startX, endX,
+ mRectXAnim = new FlingSpringAnim(this, context, RECT_CENTER_X, startX, endX,
velocityPxPerMs.x * 1000, mMinVisChange, minXValue, maxXValue, 1f, onXEndListener);
float startVelocityY = velocityPxPerMs.y * 1000;
@@ -170,13 +170,13 @@
float endY = mTrackingBottomY ? mTargetRect.bottom : mTargetRect.top;
float minYValue = Math.min(startY, endY - mYOvershoot);
float maxYValue = Math.max(startY, endY);
- mRectYAnim = new FlingSpringAnim(this, RECT_Y, startY, endY, startVelocityY,
+ mRectYAnim = new FlingSpringAnim(this, context, RECT_Y, startY, endY, startVelocityY,
mMinVisChange, minYValue, maxYValue, springVelocityFactor, onYEndListener);
float minVisibleChange = Math.abs(1f / mStartRect.height());
ResourceProvider rp = DynamicResource.provider(context);
- float damping = rp.getFloat(R.dimen.swipe_up_rect_damping_ratio);
- float stiffness = rp.getFloat(R.dimen.swipe_up_rect_stiffness);
+ float damping = rp.getFloat(R.dimen.swipe_up_rect_scale_damping_ratio);
+ float stiffness = rp.getFloat(R.dimen.swipe_up_rect_scale_stiffness);
mRectScaleAnim = new SpringAnimation(this, RECT_SCALE_PROGRESS)
.setSpring(new SpringForce(1f)
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index c201455..9bc95d7 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -29,6 +29,7 @@
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS;
import static com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController.SUCCESS_TRANSITION_PROGRESS;
@@ -66,6 +67,7 @@
import android.util.FloatProperty;
import android.util.Property;
import android.util.SparseBooleanArray;
+import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -84,7 +86,9 @@
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
+import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.PagedView;
import com.android.launcher3.R;
@@ -96,6 +100,7 @@
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.states.RotationHelper;
import com.android.launcher3.touch.PagedOrientationHandler.CurveProperties;
import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -111,6 +116,7 @@
import com.android.quickstep.RecentsAnimationTargets;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.RecentsModel.TaskVisualsChangeListener;
+import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.TaskUtils;
@@ -204,7 +210,7 @@
private boolean mDwbToastShown;
protected boolean mDisallowScrollToClearAll;
private boolean mOverlayEnabled;
- private boolean mFreezeViewVisibility;
+ protected boolean mFreezeViewVisibility;
/**
* TODO: Call reloadIdNeeded in onTaskStackChanged.
@@ -274,6 +280,9 @@
}
};
+ private RotationHelper.ForcedRotationChangedListener mForcedRotationChangedListener =
+ isForcedRotation -> RecentsView.this.disableMultipleLayoutRotations(!isForcedRotation);
+
private final PinnedStackAnimationListener mIPinnedStackAnimationListener =
new PinnedStackAnimationListener();
@@ -320,6 +329,8 @@
// Keeps track of the index where the first TaskView should be
private int mTaskViewStartIndex = 0;
+ private View mActionsView;
+ private boolean mGestureRunning = false;
private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener =
(inMultiWindowMode) -> {
@@ -378,6 +389,11 @@
int rotation = RotationHelper.getRotationFromDegrees(i);
if (mPreviousRotation != rotation) {
animateRecentsRotationInPlace(rotation);
+ if (rotation == 0) {
+ showActionsView();
+ } else {
+ hideActionsView();
+ }
mPreviousRotation = rotation;
}
}
@@ -466,6 +482,9 @@
mIPinnedStackAnimationListener.setActivity(mActivity);
SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(
mIPinnedStackAnimationListener);
+ Launcher launcher = Launcher.getLauncher(getContext());
+ launcher.getRotationHelper().addForcedRotationCallback(mForcedRotationChangedListener);
+ addActionsView();
}
@Override
@@ -480,6 +499,8 @@
mIdp.removeOnChangeListener(this);
SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(null);
mIPinnedStackAnimationListener.setActivity(null);
+ Launcher launcher = Launcher.getLauncher(getContext());
+ launcher.getRotationHelper().removeForcedRotationCallback(mForcedRotationChangedListener);
}
@Override
@@ -627,6 +648,7 @@
if (getTaskViewCount() != requiredTaskCount) {
if (indexOfChild(mClearAllButton) != -1) {
removeView(mClearAllButton);
+ hideActionsView();
}
for (int i = getTaskViewCount(); i < requiredTaskCount; i++) {
addView(mTaskViewPool.getView());
@@ -636,6 +658,7 @@
}
if (requiredTaskCount > 0) {
addView(mClearAllButton);
+ showActionsView();
}
}
@@ -675,6 +698,7 @@
if (indexOfChild(mClearAllButton) != -1) {
removeView(mClearAllButton);
}
+ hideActionsView();
}
public int getTaskViewCount() {
@@ -922,6 +946,7 @@
setEnableDrawingLiveTile(false);
setRunningTaskHidden(true);
setRunningTaskIconScaledDown(true);
+ mGestureRunning = true;
}
/**
@@ -991,6 +1016,7 @@
}
setRunningTaskHidden(false);
animateUpRunningTaskIconScale();
+ mGestureRunning = false;
}
/**
@@ -1007,6 +1033,7 @@
addView(taskView, mTaskViewStartIndex);
if (wasEmpty) {
addView(mClearAllButton);
+ showActionsView();
}
// The temporary running task is only used for the duration between the start of the
// gesture and the task list is loaded and applied
@@ -1332,6 +1359,7 @@
if (getTaskViewCount() == 0) {
removeView(mClearAllButton);
+ hideActionsView();
startHome();
} else {
snapToPageImmediately(pageToSnapTo);
@@ -1476,15 +1504,17 @@
}
}
mClearAllButton.setContentAlpha(mContentAlpha);
-
int alphaInt = Math.round(alpha * 255);
mEmptyMessagePaint.setAlpha(alphaInt);
mEmptyIcon.setAlpha(alphaInt);
-
if (alpha > 0) {
setVisibility(VISIBLE);
+ if (!mGestureRunning) {
+ showActionsView();
+ }
} else if (!mFreezeViewVisibility) {
setVisibility(GONE);
+ hideActionsView();
}
}
@@ -1498,6 +1528,11 @@
if (!mFreezeViewVisibility) {
setVisibility(mContentAlpha > 0 ? VISIBLE : GONE);
+ if (mContentAlpha > 0) {
+ showActionsView();
+ } else {
+ hideActionsView();
+ }
}
}
}
@@ -1946,8 +1981,13 @@
return offsetX;
}
- public Consumer<MotionEvent> getEventDispatcher() {
- int degreesRotated = RotationHelper.getDegreesFromRotation(mLayoutRotation);
+ public Consumer<MotionEvent> getEventDispatcher(RotationMode navBarRotationMode) {
+ float degreesRotated;
+ if (navBarRotationMode == RotationMode.NORMAL) {
+ degreesRotated = RotationHelper.getDegreesFromRotation(mLayoutRotation);
+ } else {
+ degreesRotated = -navBarRotationMode.surfaceRotation;
+ }
if (degreesRotated == 0) {
return super::onTouchEvent;
}
@@ -2043,6 +2083,7 @@
void onEmptyMessageUpdated(boolean isEmpty);
}
+
private static class PinnedStackAnimationListener<T extends BaseActivity> extends
IPinnedStackAnimationListener.Stub {
private T mActivity;
@@ -2058,4 +2099,34 @@
mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS);
}
}
+
+ private void showActionsView() {
+ if (mActionsView != null && getTaskViewCount() > 0) {
+ mActionsView.setVisibility(VISIBLE);
+ }
+ }
+
+ private void hideActionsView() {
+ if (mActionsView != null) {
+ mActionsView.setVisibility(GONE);
+ }
+ }
+
+ private void addActionsView() {
+ if (mActionsView == null && ENABLE_OVERVIEW_ACTIONS.get()
+ && SysUINavigationMode.removeShelfFromOverview(mActivity)) {
+ mActionsView = ((ViewGroup) getParent()).findViewById(R.id.overview_actions_view);
+ if (mActionsView != null) {
+ Rect rect = new Rect();
+ getTaskSize(rect);
+ InsettableFrameLayout.LayoutParams layoutParams =
+ new InsettableFrameLayout.LayoutParams(rect.width(),
+ getResources().getDimensionPixelSize(
+ R.dimen.overview_actions_height));
+ layoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
+ mActionsView.setLayoutParams(layoutParams);
+ showActionsView();
+ }
+ }
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index 9150cc7..e09e01f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -16,6 +16,20 @@
package com.android.quickstep.views;
+import static android.view.Gravity.BOTTOM;
+import static android.view.Gravity.CENTER_HORIZONTAL;
+import static android.view.Gravity.CENTER_VERTICAL;
+import static android.view.Gravity.END;
+import static android.view.Gravity.START;
+import static android.view.Gravity.TOP;
+import static android.widget.Toast.LENGTH_SHORT;
+
+import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -39,14 +53,11 @@
import android.widget.FrameLayout;
import android.widget.Toast;
-import androidx.annotation.Nullable;
-
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.states.RotationHelper;
@@ -76,20 +87,6 @@
import java.util.List;
import java.util.function.Consumer;
-import static android.view.Gravity.BOTTOM;
-import static android.view.Gravity.CENTER_HORIZONTAL;
-import static android.view.Gravity.CENTER_VERTICAL;
-import static android.view.Gravity.END;
-import static android.view.Gravity.START;
-import static android.view.Gravity.TOP;
-import static android.widget.Toast.LENGTH_SHORT;
-import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
-import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
-import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
-
/**
* A task in the Recents view.
*/
@@ -173,8 +170,6 @@
private final float mWindowCornerRadius;
private final BaseDraggingActivity mActivity;
- @Nullable private View mActionsView;
-
private ObjectAnimator mIconAndDimAnimator;
private float mIconScaleAnimStartProgress = 0;
private float mFocusTransitionProgress = 1;
@@ -193,8 +188,6 @@
private float mFooterVerticalOffset = 0;
private float mFooterAlpha = 1;
private int mStackHeight;
- private boolean mHideActionsView;
- private PagedOrientationHandler mOrientationHandler;
public TaskView(Context context) {
this(context, null);
@@ -246,18 +239,6 @@
TaskView.LayoutParams thumbnailParams = (LayoutParams) mSnapshotView.getLayoutParams();
thumbnailParams.bottomMargin = LayoutUtils.thumbnailBottomMargin(context);
mSnapshotView.setLayoutParams(thumbnailParams);
-
-
- if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) {
- mActionsView = mSnapshotView.getTaskOverlay().getActionsView();
- if (mActionsView != null) {
- TaskView.LayoutParams params = new TaskView.LayoutParams(LayoutParams.MATCH_PARENT,
- getResources().getDimensionPixelSize(R.dimen.overview_actions_height),
- BOTTOM);
- addView(mActionsView, params);
- mActionsView.setAlpha(0);
- }
- }
}
public boolean isTaskOverlayModal() {
@@ -457,7 +438,6 @@
int thumbnailPadding = (int) getResources().getDimension(R.dimen.task_thumbnail_top_margin);
LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
int rotation = RotationHelper.getDegreesFromRotation(iconRotation);
- mHideActionsView = true;
switch (iconRotation) {
case Surface.ROTATION_90:
iconParams.gravity = (isRtl ? END : START) | CENTER_VERTICAL;
@@ -479,13 +459,11 @@
iconParams.gravity = TOP | CENTER_HORIZONTAL;
iconParams.leftMargin = iconParams.topMargin = iconParams.rightMargin =
iconParams.bottomMargin = 0;
- mHideActionsView = false;
break;
}
mSnapshotView.setLayoutParams(snapshotParams);
mIconView.setLayoutParams(iconParams);
mIconView.setRotation(rotation);
- updateActionsViewVisibility(!mHideActionsView);
}
private void setIconAndDimTransitionProgress(float progress, boolean invert) {
@@ -502,11 +480,6 @@
mIconView.setScaleX(scale);
mIconView.setScaleY(scale);
-
- if (mActionsView != null && isRunningTask()) {
- mActionsView.setAlpha(scale);
- }
-
mFooterVerticalOffset = 1.0f - scale;
for (FooterWrapper footer : mFooters) {
if (footer != null) {
@@ -597,31 +570,8 @@
mMenuView.setScaleX(getScaleX());
mMenuView.setScaleY(getScaleY());
}
-
- // This is not the proper implementation and will be replaced with a proper layout.
- if (mActionsView != null) {
- if (mFocusTransitionProgress == 1f) {
- mActionsView.setAlpha(1 - curveInterpolation / MAX_PAGE_SCRIM_ALPHA);
- }
- maintainActionViewPosition(curveScaleForCurveInterpolation);
- }
-
}
- private void maintainActionViewPosition(float curveScaleForCurveInterpolation) {
- float inverseCurveScaleFactor = curveScaleForCurveInterpolation == 0 ? 0 :
- (1f / curveScaleForCurveInterpolation);
- mActionsView.setScaleX(inverseCurveScaleFactor);
- mActionsView.setScaleY(inverseCurveScaleFactor);
- mActionsView.setTranslationX(inverseCurveScaleFactor * (-getX()
- + getRecentsView().getScrollX() + getRecentsView().scrollOffsetLeft()));
- mActionsView.setTranslationY(
- (1f - curveScaleForCurveInterpolation) * (mSnapshotView.getHeight()
- + mActionsView.getHeight()) / 2f
- + inverseCurveScaleFactor * (-getTranslationY()));
- }
-
-
/**
* Sets the footer at the specific index and returns the previously set footer.
*/
@@ -903,7 +853,6 @@
mFullscreenProgress = progress;
boolean isFullscreen = mFullscreenProgress > 0;
mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
- updateActionsViewVisibility(progress < 1 && !mHideActionsView);
setClipChildren(!isFullscreen);
setClipToPadding(!isFullscreen);
@@ -937,12 +886,6 @@
invalidateOutline();
}
- private void updateActionsViewVisibility(boolean isVisible) {
- if (mActionsView != null) {
- mActionsView.setVisibility(isVisible ? VISIBLE : GONE);
- }
- }
-
public boolean isRunningTask() {
if (getRecentsView() == null) {
return false;
@@ -990,5 +933,4 @@
mScale = scale;
}
}
-
}
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 45a62ab..90d4245 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -66,27 +66,32 @@
<!-- Content description for a close button. [CHAR LIMIT=NONE] -->
<string name="back_gesture_tutorial_close_button_content_description" translatable="false">Close</string>
+
<!-- Hotseat migration notification title -->
- <string translatable="false" name="hotseat_migrate_prompt_title">Easily access your most-used apps</string>
+ <string translatable="false" name="hotseat_edu_prompt_title">Get app suggestions based on your routines</string>
<!-- Hotseat migration notification content -->
- <string translatable="false" name="hotseat_migrate_prompt_content">Pixel suggests your favorite apps based on your routines. Tap to learn more.</string>
- <!-- Hotseat migration wizard title -->
- <string translatable="false" name="hotseat_migrate_title">Suggested apps replace the bottom row of apps</string>
- <!-- Hotseat migration wizard message -->
- <string translatable="false" name="hotseat_migrate_message">Your current apps will move to the last screen. To pin or block a suggested app, drag it off the bottom row.</string>
+ <string translatable="false" name="hotseat_edu_prompt_content">Tap to set up</string>
+
+
+ <!-- Hotseat educational strings for users who don't qualify for migration -->
+ <string translatable="false" name="hotseat_edu_title_migrate">Suggested apps replace the bottom row of apps</string>
+ <string translatable="false" name="hotseat_edu_message_migrate">Your hotseat items will be moved up on the homescreen</string>
+ <string translatable="false" name="hotseat_edu_message_migrate_alt">Your hotseat items will be moved to the last page of your workspace</string>
+
+
+ <!-- Hotseat educational strings for users who don't qualify -->
+ <string translatable="false" name="hotseat_edu_title_no_migrate">Suggested apps will be found at the bottom row of your home screen</string>
+ <string translatable="false" name="hotseat_edu_message_no_migrate">Drag one or many apps off the bottom row of home screen to see app suggestions</string>
+
<!-- Toast message user sees after opting into fully predicted hybrid hotseat -->
- <string translatable="false" name="hotseat_items_migrated">Bottom row of apps moved to last screen</string>
+ <string translatable="false" name="hotseat_items_migrated">Bottom row of apps moved up.</string>
+ <string translatable="false" name="hotseat_items_migrated_alt">Bottom row of apps moved to last page.</string>
<!-- Toast message user sees after opting into fully predicted hybrid hotseat -->
<string translatable="false" name="hotseat_no_migration">Bottom row won\'t be replaced. Manually drag apps for predictions.</string>
<!-- Button text to opt in for fully predicted hotseat -->
- <string translatable="false" name="hotseat_migrate_accept">Turn On</string>
+ <string translatable="false" name="hotseat_edu_accept">Got it</string>
<!-- Button text to dismiss opt in for fully predicted hotseat -->
- <string translatable="false" name="hotseat_migrate_dismiss">No thanks</string>
- <!-- Hotseat onboard notification title -->
- <string translatable="false" name="hotseat_onboard_notification_title">Your hotseat just got smarter</string>
- <!-- Hotseat onboard notification detail -->
- <string translatable="false" name="hotseat_onboard_notification_detail">Tap here to set it up</string>
-
+ <string translatable="false" name="hotseat_edu_dismiss">No thanks</string>
<!-- Title shown during interactive part of Back gesture tutorial for right edge. [CHAR LIMIT=30] -->
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index fa0e840..c5d7c95 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -196,7 +196,10 @@
if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(this)) {
// Overview is above all other launcher elements, including qsb, so move it to the top.
- getOverviewPanelContainer().bringToFront();
+ getOverviewPanel().bringToFront();
+ if (getActionsView() != null) {
+ getActionsView().bringToFront();
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index 174e49b..7481445 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -52,10 +52,12 @@
implements StateHandler {
protected final T mRecentsView;
protected final Launcher mLauncher;
+ protected final View mActionsView;
public BaseRecentsViewStateController(@NonNull Launcher launcher) {
mLauncher = launcher;
mRecentsView = launcher.getOverviewPanel();
+ mActionsView = launcher.getActionsView();
}
@Override
@@ -72,6 +74,10 @@
getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0);
OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
SCRIM_PROGRESS.set(scrim, state.getOverviewScrimAlpha(mLauncher));
+ if (mActionsView != null) {
+ mActionsView.setTranslationX(translationX);
+ mActionsView.setAlpha(state.overviewUi ? 1f : 0);
+ }
}
@Override
@@ -118,6 +124,11 @@
OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
setter.setFloat(scrim, SCRIM_PROGRESS, toState.getOverviewScrimAlpha(mLauncher),
builder.getInterpolator(ANIM_OVERVIEW_SCRIM_FADE, LINEAR));
+ if (mActionsView != null) {
+ setter.setFloat(mActionsView, View.TRANSLATION_X, translationX, translateXInterpolator);
+ setter.setFloat(mActionsView, View.ALPHA, toState.overviewUi ? 1 : 0,
+ builder.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
+ }
}
/**
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index 832baf5..92eb036 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -49,7 +49,7 @@
class OrientationTouchTransformer {
private static final String TAG = "OrientationTouchTransformer";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static final int MAX_ORIENTATIONS = 4;
private SparseArray<OrientationRectF> mSwipeTouchRegions = new SparseArray<>(MAX_ORIENTATIONS);
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index 6c66897..196eb0f 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -44,8 +44,13 @@
layout="@layout/hotseat" />
<include
- android:id="@+id/overview_panel_container"
- layout="@layout/overview_panel"/>
+ android:id="@+id/overview_panel"
+ layout="@layout/overview_panel"
+ android:visibility="gone" />
+
+ <include
+ android:id="@+id/overview_actions_view"
+ layout="@layout/overview_actions_holder" />
<!-- Keep these behind the workspace so that they are not visible when
we go into AllApps -->
diff --git a/res/layout/overview_actions_holder.xml b/res/layout/overview_actions_holder.xml
new file mode 100644
index 0000000..5946bf6
--- /dev/null
+++ b/res/layout/overview_actions_holder.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 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.
+-->
+<Space
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="0dp"
+ android:layout_height="0dp" />
diff --git a/res/layout/overview_panel.xml b/res/layout/overview_panel.xml
index 7fff711..2637f03 100644
--- a/res/layout/overview_panel.xml
+++ b/res/layout/overview_panel.xml
@@ -14,9 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/overview_panel_recents"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:visibility="gone" />
\ No newline at end of file
+<Space
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="0dp"
+ android:layout_height="0dp" />
\ No newline at end of file
diff --git a/res/values/config.xml b/res/values/config.xml
index 35e5e6d..df0f233 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -133,12 +133,21 @@
<item name="horizontal_spring_damping_ratio" type="dimen" format="float">0.75</item>
<item name="horizontal_spring_stiffness" type="dimen" format="float">200</item>
- <item name="swipe_up_rect_damping_ratio" type="dimen" format="float">0.75</item>
- <item name="swipe_up_rect_stiffness" type="dimen" format="float">200</item>
+ <item name="swipe_up_rect_scale_damping_ratio" type="dimen" format="float">0.75</item>
+ <item name="swipe_up_rect_scale_stiffness" type="dimen" format="float">200</item>
+
+ <item name="swipe_up_rect_xy_fling_friction" type="dimen" format="float">1.5</item>
+ <item name="swipe_up_rect_xy_damping_ratio" type="dimen" format="float">0.8</item>
+ <item name="swipe_up_rect_xy_stiffness" type="dimen" format="float">200</item>
<item name="staggered_damping_ratio" type="dimen" format="float">0.7</item>
<item name="staggered_stiffness" type="dimen" format="float">150</item>
+ <!-- Swipe up to home related -->
+ <dimen name="swipe_up_fling_min_visible_change">18dp</dimen>
+ <dimen name="swipe_up_y_overshoot">10dp</dimen>
+ <dimen name="swipe_up_max_workspace_trans_y">-60dp</dimen>
+
<array name="dynamic_resources">
<item>@dimen/all_apps_spring_damping_ratio</item>
<item>@dimen/all_apps_spring_stiffness</item>
@@ -152,10 +161,17 @@
<item>@dimen/horizontal_spring_damping_ratio</item>
<item>@dimen/horizontal_spring_stiffness</item>
- <item>@dimen/swipe_up_rect_damping_ratio</item>
- <item>@dimen/swipe_up_rect_stiffness</item>
+ <item>@dimen/swipe_up_rect_scale_damping_ratio</item>
+ <item>@dimen/swipe_up_rect_scale_stiffness</item>
+
+ <item>@dimen/swipe_up_rect_xy_fling_friction</item>
+ <item>@dimen/swipe_up_rect_xy_damping_ratio</item>
+ <item>@dimen/swipe_up_rect_xy_stiffness</item>
<item>@dimen/staggered_damping_ratio</item>
<item>@dimen/staggered_stiffness</item>
+
+ <item>@dimen/swipe_up_fling_min_visible_change</item>
+ <item>@dimen/swipe_up_y_overshoot</item>
</array>
</resources>
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 8718820..e3eb387 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -2783,6 +2783,26 @@
return false;
}
+ /**
+ * Finds solution to accept hotseat migration to cell layout. commits solution if commitConfig
+ */
+ public boolean makeSpaceForHotseatMigration(boolean commitConfig) {
+ if (FeatureFlags.HOTSEAT_MIGRATE_NEW_PAGE.get()) return false;
+ int[] cellPoint = new int[2];
+ int[] directionVector = new int[]{0, -1};
+ cellToPoint(0, mCountY, cellPoint);
+ ItemConfiguration configuration = new ItemConfiguration();
+ if (findReorderSolution(cellPoint[0], cellPoint[1], mCountX, 1, mCountX, 1,
+ directionVector, null, false, configuration).isSolution) {
+ if (commitConfig) {
+ copySolutionToTempState(configuration, null);
+ commitTempPlacement();
+ }
+ return true;
+ }
+ return false;
+ }
+
public boolean isRegionVacant(int x, int y, int spanX, int spanY) {
return mOccupied.isRegionVacant(x, y, spanX, spanY);
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 33f5a95..7c85bb7 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -80,7 +80,6 @@
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
-import android.widget.FrameLayout;
import android.widget.Toast;
import androidx.annotation.Nullable;
@@ -274,7 +273,7 @@
// UI and state for the overview panel
private View mOverviewPanel;
- private FrameLayout mOverviewPanelContainer;
+ private View mActionsView;
@Thunk
boolean mWorkspaceLoading = true;
@@ -1145,8 +1144,8 @@
mFocusHandler = mDragLayer.getFocusIndicatorHelper();
mWorkspace = mDragLayer.findViewById(R.id.workspace);
mWorkspace.initParentViews(mDragLayer);
- mOverviewPanel = findViewById(R.id.overview_panel_recents);
- mOverviewPanelContainer = findViewById(R.id.overview_panel_container);
+ mOverviewPanel = findViewById(R.id.overview_panel);
+ mActionsView = findViewById(R.id.overview_actions_view);
mHotseat = findViewById(R.id.hotseat);
mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
@@ -1389,8 +1388,8 @@
return (T) mOverviewPanel;
}
- public FrameLayout getOverviewPanelContainer() {
- return mOverviewPanelContainer;
+ public View getActionsView() {
+ return mActionsView;
}
public DropTargetBar getDropTargetBar() {
@@ -2305,6 +2304,13 @@
item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED;
getModelWriter().updateItemInDatabase(item);
}
+ else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY)
+ && appWidgetInfo.configure != null) {
+ if (mAppWidgetManager.isAppWidgetRestored(item.appWidgetId)) {
+ item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED;
+ getModelWriter().updateItemInDatabase(item);
+ }
+ }
}
if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
@@ -2318,6 +2324,11 @@
item.minSpanX = appWidgetInfo.minSpanX;
item.minSpanY = appWidgetInfo.minSpanY;
view = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo);
+ } else if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)
+ && appWidgetInfo != null) {
+ mAppWidgetHost.addPendingView(item.appWidgetId,
+ new PendingAppWidgetHostView(this, item, mIconCache, false));
+ view = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo);
} else {
view = new PendingAppWidgetHostView(this, item, mIconCache, false);
}
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index 4e29a95..9921f76 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -32,6 +32,7 @@
import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.widget.DeferredAppWidgetHostView;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.PendingAppWidgetHostView;
import com.android.launcher3.widget.custom.CustomWidgetManager;
import java.util.ArrayList;
@@ -53,12 +54,14 @@
private final ArrayList<ProviderChangedListener> mProviderChangeListeners = new ArrayList<>();
private final SparseArray<LauncherAppWidgetHostView> mViews = new SparseArray<>();
+ private final SparseArray<PendingAppWidgetHostView> mPendingViews = new SparseArray<>();
private final Context mContext;
private int mFlags = FLAG_RESUMED;
private IntConsumer mAppWidgetRemovedCallback = null;
+
public LauncherAppWidgetHost(Context context) {
this(context, null);
}
@@ -73,7 +76,13 @@
@Override
protected LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId,
AppWidgetProviderInfo appWidget) {
- LauncherAppWidgetHostView view = new LauncherAppWidgetHostView(context);
+ final LauncherAppWidgetHostView view;
+ if (mPendingViews.get(appWidgetId) != null) {
+ view = mPendingViews.get(appWidgetId);
+ mPendingViews.remove(appWidgetId);
+ } else {
+ view = new LauncherAppWidgetHostView(context);
+ }
mViews.put(appWidgetId, view);
return view;
}
@@ -189,6 +198,10 @@
}
}
+ void addPendingView(int appWidgetId, PendingAppWidgetHostView view) {
+ mPendingViews.put(appWidgetId, view);
+ }
+
public AppWidgetHostView createView(Context context, int appWidgetId,
LauncherAppWidgetProviderInfo appWidget) {
if (appWidget.isCustomWidget()) {
@@ -238,8 +251,8 @@
/**
* Called on an appWidget is removed for a widgetId
- * @param appWidgetId
- * TODO: make this override when SDK is updated
+ *
+ * @param appWidgetId TODO: make this override when SDK is updated
*/
public void onAppWidgetRemoved(int appWidgetId) {
if (mAppWidgetRemovedCallback == null) {
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index ef6bd3d..a6180a6 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -47,6 +47,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.PagedViewOrientedState;
import com.android.launcher3.pageindicators.PageIndicator;
+import com.android.launcher3.states.RotationHelper;
import com.android.launcher3.touch.PortraitPagedViewHandler;
import com.android.launcher3.touch.OverScroll;
import com.android.launcher3.touch.PagedOrientationHandler;
diff --git a/src/com/android/launcher3/anim/FlingSpringAnim.java b/src/com/android/launcher3/anim/FlingSpringAnim.java
index eaf3b1c..06d0f1c 100644
--- a/src/com/android/launcher3/anim/FlingSpringAnim.java
+++ b/src/com/android/launcher3/anim/FlingSpringAnim.java
@@ -15,32 +15,40 @@
*/
package com.android.launcher3.anim;
+import android.content.Context;
+
import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
import androidx.dynamicanimation.animation.FlingAnimation;
import androidx.dynamicanimation.animation.FloatPropertyCompat;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
+import com.android.launcher3.R;
+import com.android.launcher3.util.DynamicResource;
+import com.android.systemui.plugins.ResourceProvider;
+
/**
* Given a property to animate and a target value and starting velocity, first apply friction to
* the fling until we pass the target, then apply a spring force to pull towards the target.
*/
public class FlingSpringAnim {
- private static final float FLING_FRICTION = 1.5f;
- private static final float SPRING_STIFFNESS = 200;
- private static final float SPRING_DAMPING = 0.8f;
-
private final FlingAnimation mFlingAnim;
private SpringAnimation mSpringAnim;
private float mTargetPosition;
- public <K> FlingSpringAnim(K object, FloatPropertyCompat<K> property, float startPosition,
- float targetPosition, float startVelocity, float minVisChange, float minValue,
- float maxValue, float springVelocityFactor, OnAnimationEndListener onEndListener) {
+ public <K> FlingSpringAnim(K object, Context context, FloatPropertyCompat<K> property,
+ float startPosition, float targetPosition, float startVelocity, float minVisChange,
+ float minValue, float maxValue, float springVelocityFactor,
+ OnAnimationEndListener onEndListener) {
+ ResourceProvider rp = DynamicResource.provider(context);
+ float damping = rp.getFloat(R.dimen.swipe_up_rect_xy_damping_ratio);
+ float stiffness = rp.getFloat(R.dimen.swipe_up_rect_xy_stiffness);
+ float friction = rp.getFloat(R.dimen.swipe_up_rect_xy_fling_friction);
+
mFlingAnim = new FlingAnimation(object, property)
- .setFriction(FLING_FRICTION)
+ .setFriction(friction)
// Have the spring pull towards the target if we've slowed down too much before
// reaching it.
.setMinimumVisibleChange(minVisChange)
@@ -54,8 +62,8 @@
.setStartValue(value)
.setStartVelocity(velocity * springVelocityFactor)
.setSpring(new SpringForce(mTargetPosition)
- .setStiffness(SPRING_STIFFNESS)
- .setDampingRatio(SPRING_DAMPING));
+ .setStiffness(stiffness)
+ .setDampingRatio(damping));
mSpringAnim.addEndListener(onEndListener);
mSpringAnim.animateToFinalPosition(mTargetPosition);
}));
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 6762435..b689a0a 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -113,6 +113,10 @@
public static final BooleanFlag ENABLE_HYBRID_HOTSEAT = new DeviceFlag(
"ENABLE_HYBRID_HOTSEAT", false, "Fill gaps in hotseat with predicted apps");
+ public static final BooleanFlag HOTSEAT_MIGRATE_NEW_PAGE = new DeviceFlag(
+ "HOTSEAT_MIGRATE_NEW_PAGE", true,
+ "Migrates hotseat to a new workspace page instead of same page");
+
public static final BooleanFlag ENABLE_DEEP_SHORTCUT_ICON_CACHE = getDebugFlag(
"ENABLE_DEEP_SHORTCUT_ICON_CACHE", true, "R/W deep shortcut in IconCache");
diff --git a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
index 049fda9..8dc2e61 100644
--- a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
+++ b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
@@ -96,6 +96,7 @@
initFlags();
loadPluginPrefs();
+ maybeAddSandboxCategory();
}
@Override
@@ -203,6 +204,31 @@
});
}
+ private void maybeAddSandboxCategory() {
+ Context context = getContext();
+ if (context == null) {
+ return;
+ }
+ Intent launchSandboxIntent =
+ new Intent("com.android.quickstep.action.GESTURE_SANDBOX")
+ .setPackage(context.getPackageName())
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ if (launchSandboxIntent.resolveActivity(context.getPackageManager()) == null) {
+ return;
+ }
+ PreferenceCategory sandboxCategory = newCategory("Sandbox");
+ Preference launchSandboxPreference = new Preference(context);
+ launchSandboxPreference.setKey("launchSandbox");
+ launchSandboxPreference.setTitle("Launch Gesture Navigation Sandbox");
+ launchSandboxPreference.setSummary(
+ "This provides tutorials and a place to practice navigation gestures.");
+ launchSandboxPreference.setOnPreferenceClickListener(preference -> {
+ startActivity(launchSandboxIntent);
+ return true;
+ });
+ sandboxCategory.addPreference(launchSandboxPreference);
+ }
+
private String toName(String action) {
String str = action.replace("com.android.systemui.action.PLUGIN_", "")
.replace("com.android.launcher3.action.PLUGIN_", "");
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
index 3b134b0..43d54eb 100644
--- a/src/com/android/launcher3/states/RotationHelper.java
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -20,6 +20,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
+
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.content.ContentResolver;
@@ -42,6 +43,9 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.UiThreadHelper;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Utility class to manage launcher rotation
*/
@@ -50,16 +54,38 @@
public static final String ALLOW_ROTATION_PREFERENCE_KEY = "pref_allowRotation";
public static final String FIXED_ROTATION_TRANSFORM_SETTING_NAME = "fixed_rotation_transform";
+ private final ContentResolver mContentResolver;
+
+ /**
+ * Listener to receive changes when {@link #FIXED_ROTATION_TRANSFORM_SETTING_NAME} flag changes.
+ */
+ public interface ForcedRotationChangedListener {
+ void onForcedRotationChanged(boolean isForcedRotation);
+ }
public static boolean getAllowRotationDefaultValue() {
- // If the device was scaled, used the original dimensions to determine if rotation
- // is allowed of not.
+ // If the device's pixel density was scaled (usually via settings for A11y), use the
+ // original dimensions to determine if rotation is allowed of not.
Resources res = Resources.getSystem();
int originalSmallestWidth = res.getConfiguration().smallestScreenWidthDp
* res.getDisplayMetrics().densityDpi / DENSITY_DEVICE_STABLE;
return originalSmallestWidth >= 600;
}
+
+ private final ContentObserver mContentObserver =
+ new ContentObserver(MAIN_EXECUTOR.getHandler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ boolean forcedRotation = Utilities.isForcedRotation(mLauncher);
+ PagedView.sFlagForcedRotation = forcedRotation;
+ updateForcedRotation();
+ for (ForcedRotationChangedListener listener : mForcedRotationChangedListeners) {
+ listener.onForcedRotationChanged(forcedRotation);
+ }
+ }
+ };
+
public static final int REQUEST_NONE = 0;
public static final int REQUEST_ROTATE = 1;
public static final int REQUEST_LOCK = 2;
@@ -69,6 +95,8 @@
private boolean mIgnoreAutoRotateSettings;
private boolean mAutoRotateEnabled;
+ private boolean mForcedRotation;
+ private List<ForcedRotationChangedListener> mForcedRotationChangedListeners = new ArrayList<>();
/**
* Rotation request made by
@@ -97,6 +125,7 @@
// On large devices we do not handle auto-rotate differently.
mIgnoreAutoRotateSettings = mLauncher.getResources().getBoolean(R.bool.allow_rotation);
+ updateForcedRotation();
if (!mIgnoreAutoRotateSettings) {
mPrefs = Utilities.getPrefs(mLauncher);
mPrefs.registerOnSharedPreferenceChangeListener(this);
@@ -107,16 +136,24 @@
}
// TODO(b/150260456) Add this in home settings as well
- final ContentResolver resolver = launcher.getContentResolver();
- final ContentObserver observer = new ContentObserver(MAIN_EXECUTOR.getHandler()) {
- @Override
- public void onChange(boolean selfChange) {
- PagedView.sFlagForcedRotation = Utilities.isForcedRotation(mLauncher);
- }
- };
- resolver.registerContentObserver(Settings.Global.getUriFor(
- FIXED_ROTATION_TRANSFORM_SETTING_NAME),
- false, observer);
+ mContentResolver = launcher.getContentResolver();
+ mContentResolver.registerContentObserver(Settings.Global.getUriFor(
+ FIXED_ROTATION_TRANSFORM_SETTING_NAME), false, mContentObserver);
+ }
+
+ private void updateForcedRotation() {
+ mForcedRotation = !getAllowRotationDefaultValue() && Utilities.isForcedRotation(mLauncher);
+ }
+
+ /**
+ * will not be called when first registering the listener.
+ */
+ public void addForcedRotationCallback(ForcedRotationChangedListener listener) {
+ mForcedRotationChangedListeners.add(listener);
+ }
+
+ public void removeForcedRotationCallback(ForcedRotationChangedListener listener) {
+ mForcedRotationChangedListeners.remove(listener);
}
public void setRotationHadDifferentUI(boolean rotationHasDifferentUI) {
@@ -198,6 +235,10 @@
if (mPrefs != null) {
mPrefs.unregisterOnSharedPreferenceChangeListener(this);
}
+ if (mContentResolver != null) {
+ mContentResolver.unregisterContentObserver(mContentObserver);
+ }
+ mForcedRotationChangedListeners.clear();
}
}
@@ -207,7 +248,10 @@
}
final int activityFlags;
- if (mStateHandlerRequest != REQUEST_NONE) {
+ if (mForcedRotation) {
+ // TODO(b/150214193) Properly address this
+ activityFlags = SCREEN_ORIENTATION_PORTRAIT;
+ } else if (mStateHandlerRequest != REQUEST_NONE) {
activityFlags = mStateHandlerRequest == REQUEST_LOCK ?
SCREEN_ORIENTATION_LOCKED : SCREEN_ORIENTATION_UNSPECIFIED;
} else if (mCurrentTransitionRequest != REQUEST_NONE) {
@@ -277,7 +321,7 @@
* Creates a matrix to transform the given motion event specified by degrees.
* If {@param inverse} is {@code true}, the inverse of that matrix will be applied
*/
- public static void transformEvent(int degrees, MotionEvent ev, boolean inverse) {
+ public static void transformEvent(float degrees, MotionEvent ev, boolean inverse) {
Matrix transform = new Matrix();
transform.setRotate(degrees);
if (inverse) {
diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index 6038873..895f8de 100644
--- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -33,6 +33,7 @@
import android.view.ContextThemeWrapper;
import android.view.View;
import android.view.View.OnClickListener;
+import android.widget.RemoteViews;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.FastBitmapDrawable;
@@ -94,6 +95,15 @@
}
@Override
+ public void updateAppWidget(RemoteViews remoteViews) {
+ super.updateAppWidget(remoteViews);
+ WidgetManagerHelper widgetManagerHelper = new WidgetManagerHelper(getContext());
+ if (widgetManagerHelper.isAppWidgetRestored(mInfo.appWidgetId)) {
+ reInflate();
+ }
+ }
+
+ @Override
public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth,
int maxHeight) {
// No-op
diff --git a/src/com/android/launcher3/widget/WidgetManagerHelper.java b/src/com/android/launcher3/widget/WidgetManagerHelper.java
index 8b08d77..f3c7822 100644
--- a/src/com/android/launcher3/widget/WidgetManagerHelper.java
+++ b/src/com/android/launcher3/widget/WidgetManagerHelper.java
@@ -49,6 +49,9 @@
*/
public class WidgetManagerHelper {
+ //TODO: replace this with OPTION_APPWIDGET_RESTORE_COMPLETED b/63667276
+ public static final String WIDGET_OPTION_RESTORE_COMPLETED = "appWidgetRestoreCompleted";
+
final AppWidgetManager mAppWidgetManager;
final Context mContext;
@@ -127,6 +130,14 @@
return null;
}
+ /**
+ * Returns if a AppWidgetProvider has marked a widget restored
+ */
+ public boolean isAppWidgetRestored(int appWidgetId) {
+ return !WidgetsModel.GO_DISABLE_WIDGETS && mAppWidgetManager.getAppWidgetOptions(
+ appWidgetId).getBoolean(WIDGET_OPTION_RESTORE_COMPLETED);
+ }
+
public static Map<ComponentKey, AppWidgetProviderInfo> getAllProvidersMap(Context context) {
if (WidgetsModel.GO_DISABLE_WIDGETS) {
return Collections.emptyMap();
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index e93df96..c6192bc 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -35,9 +35,11 @@
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
+import android.os.Debug;
import android.os.Process;
import android.os.RemoteException;
import android.os.StrictMode;
+import android.util.Log;
import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.By;
@@ -117,6 +119,14 @@
// so let's just mark the fact that the leak has happened.
if (sDetectedActivityLeak == null) {
sDetectedActivityLeak = violation.toString();
+ try {
+ Debug.dumpHprofData(
+ getInstrumentation().getTargetContext()
+ .getFilesDir().getPath()
+ + "/ActivityLeakHeapDump.hprof");
+ } catch (IOException e) {
+ Log.e(TAG, "dumpHprofData failed", e);
+ }
}
});
StrictMode.setVmPolicy(builder.build());
@@ -126,18 +136,6 @@
public static void checkDetectedLeaks() {
if (sDetectedActivityLeak != null && !sActivityLeakReported) {
sActivityLeakReported = true;
-
- final UiDevice device = UiDevice.getInstance(getInstrumentation());
- try {
- device.executeShellCommand(
- "am dumpheap "
- + device.getLauncherPackageName()
- + " "
- + getInstrumentation().getTargetContext().getFilesDir().getPath()
- + "/ActivityLeakHeapDump.hprof");
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
}
}
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index 21a654f..793af48 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.appwidget.AppWidgetHost;
@@ -33,6 +34,7 @@
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
+import android.widget.RemoteViews;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -41,6 +43,7 @@
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.R;
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.tapl.Workspace;
import com.android.launcher3.ui.AbstractLauncherUiTest;
@@ -86,7 +89,8 @@
// Clear all existing data
LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
- LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG);
+ LauncherSettings.Settings.call(mResolver,
+ LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG);
}
@After
@@ -172,6 +176,26 @@
assertNotNull(AppWidgetManager.getInstance(mTargetContext)
.getAppWidgetInfo(mCursor.getInt(mCursor.getColumnIndex(
LauncherSettings.Favorites.APPWIDGET_ID))));
+
+ // send OPTION_APPWIDGET_RESTORE_COMPLETED
+ int appWidgetId = mCursor.getInt(
+ mCursor.getColumnIndex(LauncherSettings.Favorites.APPWIDGET_ID));
+ AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mTargetContext);
+
+ Bundle b = new Bundle();
+ b.putBoolean(WidgetManagerHelper.WIDGET_OPTION_RESTORE_COMPLETED, true);
+ RemoteViews remoteViews = new RemoteViews(mTargetPackage, R.layout.appwidget_not_ready);
+ appWidgetManager.updateAppWidgetOptions(appWidgetId, b);
+ appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
+
+
+ // verify changes are reflected
+ waitForLauncherCondition("App widget options did not update",
+ l -> appWidgetManager.getAppWidgetOptions(appWidgetId).getBoolean(
+ WidgetManagerHelper.WIDGET_OPTION_RESTORE_COMPLETED));
+ executeOnLauncher(l -> l.getAppWidgetHost().startListening());
+ verifyWidgetPresent(info);
+ assertNull(mLauncher.getWorkspace().tryGetPendingWidget(DEFAULT_UI_TIMEOUT));
}
@Test
@@ -254,6 +278,7 @@
/**
* Creates a LauncherAppWidgetInfo corresponding to {@param info}
+ *
* @param bindWidget if true the info is bound and a valid widgetId is assigned to
* the LauncherAppWidgetInfo
*/
@@ -306,7 +331,7 @@
.keySet().forEach(packageUserKey -> packages.add(packageUserKey.mPackageName));
return packages;
});
- while(true) {
+ while (true) {
try {
mTargetContext.getPackageManager().getPackageInfo(
pkg, PackageManager.GET_UNINSTALLED_PACKAGES);
@@ -316,7 +341,7 @@
}
}
pkg = invalidPackage + count;
- count ++;
+ count++;
}
LauncherAppWidgetInfo item = new LauncherAppWidgetInfo(10,
new ComponentName(pkg, "com.test.widgetprovider"));
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 17858a0..9b12a62 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -145,7 +145,7 @@
private static final String WORKSPACE_RES_ID = "workspace";
private static final String APPS_RES_ID = "apps_view";
- private static final String OVERVIEW_RES_ID = "overview_panel_recents";
+ private static final String OVERVIEW_RES_ID = "overview_panel";
private static final String WIDGETS_RES_ID = "widgets_list_view";
private static final String CONTEXT_MENU_RES_ID = "deep_shortcuts_container";
public static final int WAIT_TIME_MS = 10000;