Merge "Migrating prediction_undo to aconfig" into main
This commit is contained in:
@@ -398,3 +398,10 @@ flag {
|
||||
purpose: PURPOSE_BUGFIX
|
||||
}
|
||||
}
|
||||
|
||||
flag {
|
||||
name: "enable_dismiss_prediction_undo"
|
||||
namespace: "launcher"
|
||||
description: "Show an 'Undo' snackbar when users dismiss a predicted hotseat item"
|
||||
bug: "270394476"
|
||||
}
|
||||
|
||||
@@ -35,8 +35,7 @@ class DropTargetHandler(launcher: Launcher) {
|
||||
target?.let {
|
||||
deferred.mPackageName = it.packageName
|
||||
mLauncher.addEventCallback(EVENT_RESUMED) { deferred.onLauncherResume() }
|
||||
}
|
||||
?: deferred.sendFailure()
|
||||
} ?: deferred.sendFailure()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,19 +46,10 @@ class DropTargetHandler(launcher: Launcher) {
|
||||
mLauncher.appWidgetHolder.startConfigActivity(
|
||||
mLauncher,
|
||||
widgetId,
|
||||
ActivityCodes.REQUEST_RECONFIGURE_APPWIDGET
|
||||
ActivityCodes.REQUEST_RECONFIGURE_APPWIDGET,
|
||||
)
|
||||
}
|
||||
|
||||
fun dismissPrediction(
|
||||
announcement: CharSequence,
|
||||
onActionClicked: Runnable,
|
||||
onDismiss: Runnable?
|
||||
) {
|
||||
mLauncher.dragLayer.announceForAccessibility(announcement)
|
||||
Snackbar.show(mLauncher, R.string.item_removed, R.string.undo, onDismiss, onActionClicked)
|
||||
}
|
||||
|
||||
fun getViewUnderDrag(info: ItemInfo): View? {
|
||||
return if (
|
||||
info is LauncherAppWidgetInfo &&
|
||||
@@ -95,7 +85,7 @@ class DropTargetHandler(launcher: Launcher) {
|
||||
R.string.item_removed,
|
||||
R.string.undo,
|
||||
mLauncher.modelWriter::commitDelete,
|
||||
onUndoClicked
|
||||
onUndoClicked,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.
|
||||
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.INVALID;
|
||||
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.RECONFIGURE;
|
||||
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.UNINSTALL;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DISMISS_PREDICTION_UNDO;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_UNINSTALL;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_UNINSTALL_CANCELLED;
|
||||
@@ -36,7 +35,6 @@ import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.dragndrop.DragOptions;
|
||||
import com.android.launcher3.logging.FileLog;
|
||||
import com.android.launcher3.logging.InstanceId;
|
||||
@@ -242,8 +240,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
|
||||
|
||||
@Override
|
||||
public void completeDrop(final DragObject d) {
|
||||
ComponentName target = performDropAction(getViewUnderDrag(d.dragInfo), d.dragInfo,
|
||||
d.logInstanceId);
|
||||
ComponentName target = performDropAction(getViewUnderDrag(d.dragInfo), d.dragInfo);
|
||||
mDropTargetHandler.onSecondaryTargetCompleteDrop(target, d);
|
||||
}
|
||||
|
||||
@@ -275,7 +272,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
|
||||
* Performs the drop action and returns the target component for the dragObject or null if
|
||||
* the action was not performed.
|
||||
*/
|
||||
protected ComponentName performDropAction(View view, ItemInfo info, InstanceId instanceId) {
|
||||
protected ComponentName performDropAction(View view, ItemInfo info) {
|
||||
if (mCurrentAccessibilityAction == RECONFIGURE) {
|
||||
int widgetId = getReconfigurableWidgetId(view);
|
||||
if (widgetId != INVALID_APPWIDGET_ID) {
|
||||
@@ -283,21 +280,6 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (mCurrentAccessibilityAction == DISMISS_PREDICTION) {
|
||||
if (FeatureFlags.ENABLE_DISMISS_PREDICTION_UNDO.get()) {
|
||||
CharSequence announcement = getContext().getString(R.string.item_removed);
|
||||
mDropTargetHandler
|
||||
.dismissPrediction(announcement, () -> {
|
||||
}, () -> {
|
||||
mStatsLogManager.logger()
|
||||
.withInstanceId(instanceId)
|
||||
.withItemInfo(info)
|
||||
.log(LAUNCHER_DISMISS_PREDICTION_UNDO);
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return performUninstall(getContext(), getUninstallTarget(getContext(), info), info);
|
||||
}
|
||||
|
||||
@@ -332,9 +314,8 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
|
||||
|
||||
@Override
|
||||
public void onAccessibilityDrop(View view, ItemInfo item) {
|
||||
InstanceId instanceId = new InstanceIdSequence().newInstanceId();
|
||||
doLog(instanceId, item);
|
||||
performDropAction(view, item, instanceId);
|
||||
doLog(new InstanceIdSequence().newInstanceId(), item);
|
||||
performDropAction(view, item);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -63,10 +63,6 @@ public final class FeatureFlags {
|
||||
* <p>
|
||||
*/
|
||||
// TODO(Block 3): Clean up flags
|
||||
public static final BooleanFlag ENABLE_DISMISS_PREDICTION_UNDO = getDebugFlag(270394476,
|
||||
"ENABLE_DISMISS_PREDICTION_UNDO", DISABLED,
|
||||
"Show an 'Undo' snackbar when users dismiss a predicted hotseat item");
|
||||
|
||||
public static final BooleanFlag ENABLE_WORKSPACE_LOADING_OPTIMIZATION = getDebugFlag(251502424,
|
||||
"ENABLE_WORKSPACE_LOADING_OPTIMIZATION", DISABLED,
|
||||
"load the current workspace screen visible to the user before the rest rather than "
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.android.launcher3.popup;
|
||||
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DISMISS_PREDICTION_UNDO;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_INSTALL_SYSTEM_SHORTCUT_TAP;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNINSTALL_SYSTEM_SHORTCUT_TAP;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP;
|
||||
@@ -41,6 +42,7 @@ import com.android.launcher3.util.InstantAppResolver;
|
||||
import com.android.launcher3.util.PackageManagerHelper;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
import com.android.launcher3.views.Snackbar;
|
||||
import com.android.launcher3.widget.WidgetsBottomSheet;
|
||||
import com.android.launcher3.widget.picker.model.data.WidgetPickerData;
|
||||
|
||||
@@ -336,6 +338,14 @@ public abstract class SystemShortcut<T extends ActivityContext> extends ItemInfo
|
||||
mTarget.getStatsLogManager().logger()
|
||||
.withItemInfo(mItemInfo)
|
||||
.log(LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP);
|
||||
if (Flags.enableDismissPredictionUndo()) {
|
||||
Snackbar.show(mTarget,
|
||||
view.getContext().getString(R.string.item_removed), R.string.undo,
|
||||
() -> { }, () ->
|
||||
mTarget.getStatsLogManager().logger()
|
||||
.withItemInfo(mItemInfo)
|
||||
.log(LAUNCHER_DISMISS_PREDICTION_UNDO));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,19 +19,26 @@ package com.android.launcher3.popup;
|
||||
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_SNACKBAR;
|
||||
import static com.android.launcher3.Flags.FLAG_ENABLE_DISMISS_PREDICTION_UNDO;
|
||||
import static com.android.launcher3.Flags.FLAG_ENABLE_PRIVATE_SPACE;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DISMISS_PREDICTION_UNDO;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP;
|
||||
import static com.android.launcher3.model.data.WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.atLeast;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -50,8 +57,13 @@ import android.view.View;
|
||||
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.allapps.PrivateProfileManager;
|
||||
import com.android.launcher3.logging.StatsLogManager;
|
||||
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
|
||||
import com.android.launcher3.model.data.AppInfo;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
@@ -61,8 +73,9 @@ import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext;
|
||||
import com.android.launcher3.util.LauncherMultivalentJUnit;
|
||||
import com.android.launcher3.util.TestSandboxModelContextWrapper;
|
||||
import com.android.launcher3.util.TestUtil;
|
||||
import com.android.launcher3.util.UserIconInfo;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.launcher3.views.Snackbar;
|
||||
import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider;
|
||||
import com.android.launcher3.widget.picker.model.data.WidgetPickerData;
|
||||
|
||||
@@ -72,6 +85,7 @@ import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@@ -88,25 +102,31 @@ public class SystemShortcutTest {
|
||||
private PrivateProfileManager mPrivateProfileManager;
|
||||
private WidgetPickerDataProvider mWidgetPickerDataProvider;
|
||||
private AppInfo mAppInfo;
|
||||
|
||||
@Mock UserCache mUserCache;
|
||||
@Mock ApiWrapper mApiWrapper;
|
||||
@Mock BaseDragLayer mBaseDragLayer;
|
||||
@Mock UserIconInfo mUserIconInfo;
|
||||
@Mock LauncherActivityInfo mLauncherActivityInfo;
|
||||
@Mock ApplicationInfo mApplicationInfo;
|
||||
@Mock Intent mIntent;
|
||||
@Mock StatsLogManager mStatsLogManager;
|
||||
@Mock(answer = Answers.RETURNS_SELF) StatsLogger mStatsLogger;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mSandboxContext.putObject(UserCache.INSTANCE, mUserCache);
|
||||
mSandboxContext.putObject(ApiWrapper.INSTANCE, mApiWrapper);
|
||||
mTestContext = new TestSandboxModelContextWrapper(mSandboxContext);
|
||||
mView = new View(mSandboxContext);
|
||||
spyOn(mTestContext);
|
||||
mTestContext = new TestSandboxModelContextWrapper(mSandboxContext) {
|
||||
@Override
|
||||
public StatsLogManager getStatsLogManager() {
|
||||
return mStatsLogManager;
|
||||
}
|
||||
};
|
||||
spyOn(mSandboxContext);
|
||||
doReturn(mBaseDragLayer).when(mTestContext).getDragLayer();
|
||||
doReturn(mStatsLogger).when(mStatsLogManager).logger();
|
||||
|
||||
mView = new View(mTestContext);
|
||||
mItemInfo = new ItemInfo();
|
||||
|
||||
LauncherApps mLauncherApps = mSandboxContext.spyService(LauncherApps.class);
|
||||
@@ -114,7 +134,6 @@ public class SystemShortcutTest {
|
||||
when(mLauncherActivityInfo.getApplicationInfo()).thenReturn(mApplicationInfo);
|
||||
|
||||
when(mUserCache.getUserInfo(any())).thenReturn(mUserIconInfo);
|
||||
when(mBaseDragLayer.getChildCount()).thenReturn(0);
|
||||
mPrivateProfileManager = mTestContext.getAppsView().getPrivateProfileManager();
|
||||
spyOn(mPrivateProfileManager);
|
||||
when(mPrivateProfileManager.getProfileUser()).thenReturn(PRIVATE_HANDLE);
|
||||
@@ -168,6 +187,7 @@ public class SystemShortcutTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisableFlags(FLAG_ENABLE_DISMISS_PREDICTION_UNDO)
|
||||
public void testDontSuggestAppForPredictedItem() {
|
||||
mAppInfo = new AppInfo();
|
||||
mAppInfo.componentName = new ComponentName(mTestContext, getClass());
|
||||
@@ -176,7 +196,36 @@ public class SystemShortcutTest {
|
||||
SystemShortcut systemShortcut = SystemShortcut.DONT_SUGGEST_APP
|
||||
.getShortcut(mTestContext, mAppInfo, mView);
|
||||
assertNotNull(systemShortcut);
|
||||
systemShortcut.onClick(mView);
|
||||
|
||||
TestUtil.runOnExecutorSync(MAIN_EXECUTOR, () -> systemShortcut.onClick(mView));
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
verify(mStatsLogger).log(eq(LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP));
|
||||
assertFalse(AbstractFloatingView.hasOpenView(mTestContext, TYPE_SNACKBAR));
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableFlags(FLAG_ENABLE_DISMISS_PREDICTION_UNDO)
|
||||
public void testDontSuggestAppForPredictedItemWithUndo() {
|
||||
mAppInfo = new AppInfo();
|
||||
mAppInfo.componentName = new ComponentName(mTestContext, getClass());
|
||||
mAppInfo.container = CONTAINER_HOTSEAT_PREDICTION;
|
||||
assertTrue(mAppInfo.isPredictedItem());
|
||||
SystemShortcut systemShortcut = SystemShortcut.DONT_SUGGEST_APP
|
||||
.getShortcut(mTestContext, mAppInfo, mView);
|
||||
assertNotNull(systemShortcut);
|
||||
|
||||
TestUtil.runOnExecutorSync(MAIN_EXECUTOR, () -> systemShortcut.onClick(mView));
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
verify(mStatsLogger).log(eq(LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP));
|
||||
|
||||
// Undo bar shown
|
||||
Snackbar snackbar = AbstractFloatingView.getOpenView(mTestContext, TYPE_SNACKBAR);
|
||||
assertNotNull(snackbar);
|
||||
reset(mStatsLogger);
|
||||
TestUtil.runOnExecutorSync(MAIN_EXECUTOR, snackbar.findViewById(
|
||||
R.id.action)::performClick);
|
||||
verify(mStatsLogger).log(eq(LAUNCHER_DISMISS_PREDICTION_UNDO));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user