Merge "Merging from ub-launcher3-rvc-dev @ build 6396980" into rvc-dev am: ce6f43f0df am: 2e9cdc6e40 am: a629f7adb5

Change-Id: I0cdc0d6a6e063611c9f745f26a74e01c7cecb218
This commit is contained in:
Hyunyoung Song
2020-04-16 21:48:02 +00:00
committed by Automerger Merge Worker
226 changed files with 2160 additions and 1545 deletions
+8 -4
View File
@@ -63,14 +63,14 @@ message Target {
// Note: proto does not support duplicate enum values, even if they belong to different enum type. // Note: proto does not support duplicate enum values, even if they belong to different enum type.
// Hence "FROM" and "TO" prefix added. // Hence "FROM" and "TO" prefix added.
enum FromFolderLabelState{ enum FromFolderLabelState {
FROM_FOLDER_LABEL_STATE_UNSPECIFIED = 0; FROM_FOLDER_LABEL_STATE_UNSPECIFIED = 0;
FROM_EMPTY = 1; FROM_EMPTY = 1;
FROM_CUSTOM = 2; FROM_CUSTOM = 2;
FROM_SUGGESTED = 3; FROM_SUGGESTED = 3;
} }
enum ToFolderLabelState{ enum ToFolderLabelState {
TO_FOLDER_LABEL_STATE_UNSPECIFIED = 0; TO_FOLDER_LABEL_STATE_UNSPECIFIED = 0;
TO_SUGGESTION0_WITH_VALID_PRIMARY = 1; TO_SUGGESTION0_WITH_VALID_PRIMARY = 1;
TO_SUGGESTION1_WITH_VALID_PRIMARY = 2; TO_SUGGESTION1_WITH_VALID_PRIMARY = 2;
@@ -79,10 +79,14 @@ message Target {
TO_SUGGESTION2_WITH_EMPTY_PRIMARY = 5; TO_SUGGESTION2_WITH_EMPTY_PRIMARY = 5;
TO_SUGGESTION3_WITH_VALID_PRIMARY = 6; TO_SUGGESTION3_WITH_VALID_PRIMARY = 6;
TO_SUGGESTION3_WITH_EMPTY_PRIMARY = 7; TO_SUGGESTION3_WITH_EMPTY_PRIMARY = 7;
TO_EMPTY_WITH_VALID_SUGGESTIONS = 8; TO_EMPTY_WITH_VALID_SUGGESTIONS = 8 [deprecated = true];
TO_EMPTY_WITH_VALID_PRIMARY = 15;
TO_EMPTY_WITH_VALID_SUGGESTIONS_AND_EMPTY_PRIMARY = 16;
TO_EMPTY_WITH_EMPTY_SUGGESTIONS = 9; TO_EMPTY_WITH_EMPTY_SUGGESTIONS = 9;
TO_EMPTY_WITH_SUGGESTIONS_DISABLED = 10; TO_EMPTY_WITH_SUGGESTIONS_DISABLED = 10;
TO_CUSTOM_WITH_VALID_SUGGESTIONS = 11; TO_CUSTOM_WITH_VALID_SUGGESTIONS = 11 [deprecated = true];
TO_CUSTOM_WITH_VALID_PRIMARY = 17;
TO_CUSTOM_WITH_VALID_SUGGESTIONS_AND_EMPTY_PRIMARY = 18;
TO_CUSTOM_WITH_EMPTY_SUGGESTIONS = 12; TO_CUSTOM_WITH_EMPTY_SUGGESTIONS = 12;
TO_CUSTOM_WITH_SUGGESTIONS_DISABLED = 13; TO_CUSTOM_WITH_SUGGESTIONS_DISABLED = 13;
UNCHANGED = 14; UNCHANGED = 14;
@@ -18,10 +18,9 @@ package com.android.launcher3.appprediction;
import static com.android.quickstep.InstantAppResolverImpl.COMPONENT_CLASS_MARKER; import static com.android.quickstep.InstantAppResolverImpl.COMPONENT_CLASS_MARKER;
import com.android.launcher3.AppInfo;
import com.android.launcher3.ItemInfoWithIcon;
import com.android.launcher3.allapps.AllAppsStore; import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.ComponentKey;
public class ComponentKeyMapper { public class ComponentKeyMapper {
@@ -57,9 +56,8 @@ public class ComponentKeyMapper {
return item; return item;
} else if (getComponentClass().equals(COMPONENT_CLASS_MARKER)) { } else if (getComponentClass().equals(COMPONENT_CLASS_MARKER)) {
return mCache.getInstantApp(componentKey.componentName.getPackageName()); return mCache.getInstantApp(componentKey.componentName.getPackageName());
} else if (componentKey instanceof ShortcutKey) { } else {
return mCache.getShortcutInfo((ShortcutKey) componentKey); return mCache.getShortcutInfo(componentKey);
} }
return null;
} }
} }
@@ -38,13 +38,14 @@ import androidx.annotation.Nullable;
import androidx.annotation.UiThread; import androidx.annotation.UiThread;
import androidx.annotation.WorkerThread; import androidx.annotation.WorkerThread;
import com.android.launcher3.AppInfo;
import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppState;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.allapps.AllAppsStore; import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest; import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.InstantAppResolver; import com.android.launcher3.util.InstantAppResolver;
import java.util.ArrayList; import java.util.ArrayList;
@@ -76,7 +77,7 @@ public class DynamicItemCache {
private final Runnable mOnUpdateCallback; private final Runnable mOnUpdateCallback;
private final IconCache mIconCache; private final IconCache mIconCache;
private final Map<ShortcutKey, WorkspaceItemInfo> mShortcuts; private final Map<ComponentKey, WorkspaceItemInfo> mShortcuts;
private final Map<String, InstantAppItemInfo> mInstantApps; private final Map<String, InstantAppItemInfo> mInstantApps;
public DynamicItemCache(Context context, Runnable onUpdateCallback) { public DynamicItemCache(Context context, Runnable onUpdateCallback) {
@@ -230,7 +231,7 @@ public class DynamicItemCache {
} }
@MainThread @MainThread
public WorkspaceItemInfo getShortcutInfo(ShortcutKey key) { public WorkspaceItemInfo getShortcutInfo(ComponentKey key) {
return mShortcuts.get(key); return mShortcuts.get(key);
} }
@@ -21,9 +21,9 @@ import static com.android.quickstep.InstantAppResolverImpl.COMPONENT_CLASS_MARKE
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Intent; import android.content.Intent;
import com.android.launcher3.AppInfo;
import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings;
import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
public class InstantAppItemInfo extends AppInfo { public class InstantAppItemInfo extends AppInfo {
@@ -44,7 +44,7 @@ public class InstantAppItemInfo extends AppInfo {
workspaceItemInfo.status = WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON workspaceItemInfo.status = WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON
| WorkspaceItemInfo.FLAG_RESTORE_STARTED | WorkspaceItemInfo.FLAG_RESTORE_STARTED
| WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI; | WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI;
workspaceItemInfo.intent.setPackage(componentName.getPackageName()); workspaceItemInfo.getIntent().setPackage(componentName.getPackageName());
return workspaceItemInfo; return workspaceItemInfo;
} }
} }
@@ -38,18 +38,14 @@ import android.widget.LinearLayout;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.android.launcher3.AppInfo;
import com.android.launcher3.BubbleTextView; import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.ItemInfoWithIcon;
import com.android.launcher3.Launcher; import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherState;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.allapps.AllAppsStore; import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.allapps.FloatingHeaderRow; import com.android.launcher3.allapps.FloatingHeaderRow;
import com.android.launcher3.allapps.FloatingHeaderView; import com.android.launcher3.allapps.FloatingHeaderView;
@@ -60,6 +56,10 @@ import com.android.launcher3.keyboard.FocusIndicatorHelper;
import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorHelper; import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorHelper;
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider; import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
import com.android.launcher3.model.AppLaunchTracker; import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemLongClickListener; import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -28,8 +28,6 @@ import androidx.annotation.NonNull;
import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.InvariantDeviceProfile.OnIDPChangeListener; import com.android.launcher3.InvariantDeviceProfile.OnIDPChangeListener;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.ItemInfoWithIcon;
import com.android.launcher3.Launcher; import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings;
@@ -40,6 +38,8 @@ import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsStore.OnUpdateListener; import com.android.launcher3.allapps.AllAppsStore.OnUpdateListener;
import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.hybridhotseat.HotseatPredictionController;
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver; import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.ComponentKey;
@@ -27,16 +27,16 @@ import android.view.View;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import com.android.launcher3.CellLayout; import com.android.launcher3.CellLayout;
import com.android.launcher3.FolderInfo;
import com.android.launcher3.Hotseat; import com.android.launcher3.Hotseat;
import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher; import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.Workspace; import com.android.launcher3.Workspace;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.ActivityTracker; import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.GridOccupancy;
@@ -200,6 +200,7 @@ public class HotseatEduController {
pageId = LauncherSettings.Settings.call(mLauncher.getContentResolver(), pageId = LauncherSettings.Settings.call(mLauncher.getContentResolver(),
LauncherSettings.Settings.METHOD_NEW_SCREEN_ID) LauncherSettings.Settings.METHOD_NEW_SCREEN_ID)
.getInt(LauncherSettings.Settings.EXTRA_VALUE); .getInt(LauncherSettings.Settings.EXTRA_VALUE);
mNewScreens = IntArray.wrap(pageId);
} }
for (int i = 0; i < mLauncher.getDeviceProfile().inv.numHotseatIcons; i++) { for (int i = 0; i < mLauncher.getDeviceProfile().inv.numHotseatIcons; i++) {
View child = mHotseat.getChildAt(i, 0); View child = mHotseat.getChildAt(i, 0);
@@ -16,8 +16,7 @@
package com.android.launcher3.hybridhotseat; package com.android.launcher3.hybridhotseat;
import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent; import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.HYBRID_HOTSEAT_CANCELED;
.HYBRID_HOTSEAT_CANCELED;
import android.animation.PropertyValuesHolder; import android.animation.PropertyValuesHolder;
import android.content.Context; import android.content.Context;
@@ -34,10 +33,11 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable; import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher; import com.android.launcher3.Launcher;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.Workspace;
import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.uioverrides.PredictedAppIcon; import com.android.launcher3.uioverrides.PredictedAppIcon;
import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.views.AbstractSlideInView; import com.android.launcher3.views.AbstractSlideInView;
@@ -153,6 +153,12 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
private void logUserAction(boolean migrated, int pageIndex) { private void logUserAction(boolean migrated, int pageIndex) {
LauncherLogProto.Action action = new LauncherLogProto.Action(); LauncherLogProto.Action action = new LauncherLogProto.Action();
LauncherLogProto.Target target = new LauncherLogProto.Target(); LauncherLogProto.Target target = new LauncherLogProto.Target();
int hotseatItemsCount = mLauncher.getHotseat().getShortcutsAndWidgets().getChildCount();
// -1 to exclude smart space
int workspaceItemCount = mLauncher.getWorkspace().getScreenWithId(
Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets().getChildCount() - 1;
action.type = LauncherLogProto.Action.Type.TOUCH; action.type = LauncherLogProto.Action.Type.TOUCH;
action.touch = LauncherLogProto.Action.Touch.TAP; action.touch = LauncherLogProto.Action.Touch.TAP;
target.containerType = LauncherLogProto.ContainerType.TIP; target.containerType = LauncherLogProto.ContainerType.TIP;
@@ -162,7 +168,7 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
target.rank = MIGRATION_EXPERIMENT_IDENTIFIER; target.rank = MIGRATION_EXPERIMENT_IDENTIFIER;
// encoding migration type on pageIndex // encoding migration type on pageIndex
target.pageIndex = pageIndex; target.pageIndex = pageIndex;
target.cardinality = HotseatPredictionController.MAX_ITEMS_FOR_MIGRATION; target.cardinality = (workspaceItemCount * 1000) + hotseatItemsCount;
LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target); LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null); UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null);
} }
@@ -31,6 +31,7 @@ import android.app.prediction.AppTargetEvent;
import android.app.prediction.AppTargetId; import android.app.prediction.AppTargetId;
import android.content.ComponentName; import android.content.ComponentName;
import android.os.Bundle; import android.os.Bundle;
import android.os.Process;
import android.provider.DeviceConfig; import android.provider.DeviceConfig;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
@@ -39,22 +40,18 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.android.launcher3.AppInfo;
import com.android.launcher3.BubbleTextView; import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DragSource; import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget; import com.android.launcher3.DropTarget;
import com.android.launcher3.FolderInfo;
import com.android.launcher3.Hotseat; import com.android.launcher3.Hotseat;
import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.ItemInfoWithIcon;
import com.android.launcher3.Launcher; import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherState;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.Utilities; import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace; import com.android.launcher3.Workspace;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.allapps.AllAppsStore; import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.appprediction.ComponentKeyMapper; import com.android.launcher3.appprediction.ComponentKeyMapper;
@@ -64,6 +61,12 @@ import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.IconCache;
import com.android.launcher3.logging.FileLog; import com.android.launcher3.logging.FileLog;
import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.touch.ItemLongClickListener; import com.android.launcher3.touch.ItemLongClickListener;
@@ -76,6 +79,7 @@ import com.android.launcher3.util.ComponentKey;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.OptionalInt; import java.util.OptionalInt;
import java.util.stream.IntStream; import java.util.stream.IntStream;
@@ -91,18 +95,19 @@ public class HotseatPredictionController implements DragController.DragListener,
private static final String TAG = "PredictiveHotseat"; private static final String TAG = "PredictiveHotseat";
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
public static final int MAX_ITEMS_FOR_MIGRATION = DeviceConfig.getInt(
DeviceFlag.NAMESPACE_LAUNCHER, "max_homepage_items_for_migration", 5);
//TODO: replace this with AppTargetEvent.ACTION_UNPIN (b/144119543) //TODO: replace this with AppTargetEvent.ACTION_UNPIN (b/144119543)
private static final int APPTARGET_ACTION_UNPIN = 4; private static final int APPTARGET_ACTION_UNPIN = 4;
private static final String PREDICTED_ITEMS_CACHE_KEY = "predicted_item_keys";
private static final String APP_LOCATION_HOTSEAT = "hotseat"; private static final String APP_LOCATION_HOTSEAT = "hotseat";
private static final String APP_LOCATION_WORKSPACE = "workspace"; private static final String APP_LOCATION_WORKSPACE = "workspace";
private static final String BUNDLE_KEY_HOTSEAT = "hotseat_apps"; private static final String BUNDLE_KEY_HOTSEAT = "hotseat_apps";
private static final String BUNDLE_KEY_WORKSPACE = "workspace_apps"; private static final String BUNDLE_KEY_WORKSPACE = "workspace_apps";
private static final String BUNDLE_KEY_PIN_EVENTS = "pin_events";
private static final String PREDICTION_CLIENT = "hotseat"; private static final String PREDICTION_CLIENT = "hotseat";
private DropTarget.DragObject mDragObject; private DropTarget.DragObject mDragObject;
private int mHotSeatItemsCount; private int mHotSeatItemsCount;
@@ -119,6 +124,7 @@ public class HotseatPredictionController implements DragController.DragListener,
private AllAppsStore mAllAppsStore; private AllAppsStore mAllAppsStore;
private AnimatorSet mIconRemoveAnimators; private AnimatorSet mIconRemoveAnimators;
private boolean mUIUpdatePaused = false; private boolean mUIUpdatePaused = false;
private boolean mRequiresCacheUpdate = false;
private HotseatEduController mHotseatEduController; private HotseatEduController mHotseatEduController;
@@ -145,6 +151,7 @@ public class HotseatPredictionController implements DragController.DragListener,
if (mHotseat.isAttachedToWindow()) { if (mHotseat.isAttachedToWindow()) {
onViewAttachedToWindow(mHotseat); onViewAttachedToWindow(mHotseat);
} }
showCachedItems();
} }
/** /**
@@ -294,17 +301,57 @@ public class HotseatPredictionController implements DragController.DragListener,
mAppPredictor.requestPredictionUpdate(); mAppPredictor.requestPredictionUpdate();
} }
private void showCachedItems() {
ArrayList<ComponentKey> componentKeys = getCachedComponentKeys();
mComponentKeyMappers.clear();
for (ComponentKey key : componentKeys) {
mComponentKeyMappers.add(new ComponentKeyMapper(key, mDynamicItemCache));
}
updateDependencies();
fillGapsWithPrediction();
}
private Bundle getAppPredictionContextExtra() { private Bundle getAppPredictionContextExtra() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
//TODO: remove this way of reporting items
bundle.putParcelableArrayList(BUNDLE_KEY_HOTSEAT, bundle.putParcelableArrayList(BUNDLE_KEY_HOTSEAT,
getPinnedAppTargetsInViewGroup((mHotseat.getShortcutsAndWidgets()))); getPinnedAppTargetsInViewGroup((mHotseat.getShortcutsAndWidgets())));
bundle.putParcelableArrayList(BUNDLE_KEY_WORKSPACE, getPinnedAppTargetsInViewGroup( bundle.putParcelableArrayList(BUNDLE_KEY_WORKSPACE, getPinnedAppTargetsInViewGroup(
mLauncher.getWorkspace().getScreenWithId( mLauncher.getWorkspace().getScreenWithId(
Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets())); Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets()));
ArrayList<AppTargetEvent> pinEvents = new ArrayList<>();
getPinEventsForViewGroup(pinEvents, mHotseat.getShortcutsAndWidgets(),
APP_LOCATION_HOTSEAT);
getPinEventsForViewGroup(pinEvents, mLauncher.getWorkspace().getScreenWithId(
Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets(), APP_LOCATION_WORKSPACE);
bundle.putParcelableArrayList(BUNDLE_KEY_PIN_EVENTS, pinEvents);
return bundle; return bundle;
} }
private ArrayList<AppTargetEvent> getPinEventsForViewGroup(ArrayList<AppTargetEvent> pinEvents,
ViewGroup views, String root) {
for (int i = 0; i < views.getChildCount(); i++) {
View child = views.getChildAt(i);
final AppTargetEvent event;
if (child.getTag() instanceof ItemInfo && getAppTargetFromInfo(
(ItemInfo) child.getTag()) != null) {
ItemInfo info = (ItemInfo) child.getTag();
event = wrapAppTargetWithLocation(getAppTargetFromInfo(info),
AppTargetEvent.ACTION_PIN, info);
} else {
CellLayout.LayoutParams params = (CellLayout.LayoutParams) views.getLayoutParams();
event = wrapAppTargetWithLocation(getBlockAppTarget(), AppTargetEvent.ACTION_PIN,
root, 0, params.cellX, params.cellY, params.cellHSpan, params.cellVSpan);
}
pinEvents.add(event);
}
return pinEvents;
}
private ArrayList<AppTarget> getPinnedAppTargetsInViewGroup(ViewGroup viewGroup) { private ArrayList<AppTarget> getPinnedAppTargetsInViewGroup(ViewGroup viewGroup) {
ArrayList<AppTarget> pinnedApps = new ArrayList<>(); ArrayList<AppTarget> pinnedApps = new ArrayList<>();
for (int i = 0; i < viewGroup.getChildCount(); i++) { for (int i = 0; i < viewGroup.getChildCount(); i++) {
@@ -320,6 +367,7 @@ public class HotseatPredictionController implements DragController.DragListener,
private void setPredictedApps(List<AppTarget> appTargets) { private void setPredictedApps(List<AppTarget> appTargets) {
mComponentKeyMappers.clear(); mComponentKeyMappers.clear();
StringBuilder predictionLog = new StringBuilder("predictedApps: [\n"); StringBuilder predictionLog = new StringBuilder("predictedApps: [\n");
ArrayList<ComponentKey> componentKeys = new ArrayList<>();
for (AppTarget appTarget : appTargets) { for (AppTarget appTarget : appTargets) {
ComponentKey key; ComponentKey key;
if (appTarget.getShortcutInfo() != null) { if (appTarget.getShortcutInfo() != null) {
@@ -328,6 +376,7 @@ public class HotseatPredictionController implements DragController.DragListener,
key = new ComponentKey(new ComponentName(appTarget.getPackageName(), key = new ComponentKey(new ComponentName(appTarget.getPackageName(),
appTarget.getClassName()), appTarget.getUser()); appTarget.getClassName()), appTarget.getUser());
} }
componentKeys.add(key);
predictionLog.append(key.toString()); predictionLog.append(key.toString());
predictionLog.append(",rank:"); predictionLog.append(",rank:");
predictionLog.append(appTarget.getRank()); predictionLog.append(appTarget.getRank());
@@ -342,6 +391,35 @@ public class HotseatPredictionController implements DragController.DragListener,
} else if (mHotseatEduController != null) { } else if (mHotseatEduController != null) {
mHotseatEduController.setPredictedApps(mapToWorkspaceItemInfo(mComponentKeyMappers)); mHotseatEduController.setPredictedApps(mapToWorkspaceItemInfo(mComponentKeyMappers));
} }
// should invalidate cache if AiAi sends empty list of AppTargets
if (appTargets.isEmpty()) {
mRequiresCacheUpdate = true;
}
cachePredictionComponentKeys(componentKeys);
}
private void cachePredictionComponentKeys(ArrayList<ComponentKey> componentKeys) {
if (!mRequiresCacheUpdate) return;
StringBuilder builder = new StringBuilder();
for (ComponentKey componentKey : componentKeys) {
builder.append(componentKey);
builder.append("\n");
}
mLauncher.getDevicePrefs().edit().putString(PREDICTED_ITEMS_CACHE_KEY,
builder.toString()).apply();
mRequiresCacheUpdate = false;
}
private ArrayList<ComponentKey> getCachedComponentKeys() {
String cachedBlob = mLauncher.getDevicePrefs().getString(PREDICTED_ITEMS_CACHE_KEY, "");
ArrayList<ComponentKey> results = new ArrayList<>();
for (String line : cachedBlob.split("\n")) {
ComponentKey key = ComponentKey.fromString(line);
if (key != null) {
results.add(key);
}
}
return results;
} }
private void updateDependencies() { private void updateDependencies() {
@@ -367,6 +445,7 @@ public class HotseatPredictionController implements DragController.DragListener,
icon.pin(workspaceItemInfo); icon.pin(workspaceItemInfo);
AppTarget appTarget = getAppTargetFromItemInfo(workspaceItemInfo); AppTarget appTarget = getAppTargetFromItemInfo(workspaceItemInfo);
notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, AppTargetEvent.ACTION_PIN); notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, AppTargetEvent.ACTION_PIN);
mRequiresCacheUpdate = true;
} }
private List<WorkspaceItemInfo> mapToWorkspaceItemInfo( private List<WorkspaceItemInfo> mapToWorkspaceItemInfo(
@@ -533,6 +612,7 @@ public class HotseatPredictionController implements DragController.DragListener,
} }
mDragObject = null; mDragObject = null;
fillGapsWithPrediction(true, this::removeOutlineDrawings); fillGapsWithPrediction(true, this::removeOutlineDrawings);
mRequiresCacheUpdate = true;
} }
@Nullable @Nullable
@@ -606,6 +686,9 @@ public class HotseatPredictionController implements DragController.DragListener,
if (isReady()) return; if (isReady()) return;
int hotseatItemsCount = mHotseat.getShortcutsAndWidgets().getChildCount(); int hotseatItemsCount = mHotseat.getShortcutsAndWidgets().getChildCount();
int maxItems = DeviceConfig.getInt(
DeviceFlag.NAMESPACE_LAUNCHER, "max_homepage_items_for_migration", 5);
// -1 to exclude smart space // -1 to exclude smart space
int workspaceItemCount = mLauncher.getWorkspace().getScreenWithId( int workspaceItemCount = mLauncher.getWorkspace().getScreenWithId(
Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets().getChildCount() - 1; Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets().getChildCount() - 1;
@@ -614,7 +697,7 @@ public class HotseatPredictionController implements DragController.DragListener,
// open spots in their hotseat and have more than maxItems in their hotseat + workspace // open spots in their hotseat and have more than maxItems in their hotseat + workspace
if (hotseatItemsCount == mHotSeatItemsCount && workspaceItemCount + hotseatItemsCount if (hotseatItemsCount == mHotSeatItemsCount && workspaceItemCount + hotseatItemsCount
> MAX_ITEMS_FOR_MIGRATION) { > maxItems) {
mLauncher.getSharedPrefs().edit().putBoolean(HotseatEduController.KEY_HOTSEAT_EDU_SEEN, mLauncher.getSharedPrefs().edit().putBoolean(HotseatEduController.KEY_HOTSEAT_EDU_SEEN,
true).apply(); true).apply();
@@ -626,8 +709,8 @@ public class HotseatPredictionController implements DragController.DragListener,
// temporarily encode details in log target (go/hotseat_migration) // temporarily encode details in log target (go/hotseat_migration)
target.rank = 2; target.rank = 2;
target.cardinality = MAX_ITEMS_FOR_MIGRATION; target.cardinality = (workspaceItemCount * 1000) + hotseatItemsCount;
target.pageIndex = (workspaceItemCount * 1000) + hotseatItemsCount; target.pageIndex = maxItems;
LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target); LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
UserEventDispatcher.newInstance(mLauncher).dispatchUserEvent(event, null); UserEventDispatcher.newInstance(mLauncher).dispatchUserEvent(event, null);
@@ -689,4 +772,52 @@ public class HotseatPredictionController implements DragController.DragListener,
return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()), return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()),
cn.getPackageName(), info.user).setClassName(cn.getClassName()).build(); cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
} }
private AppTarget getAppTargetFromInfo(ItemInfo info) {
if (info == null) return null;
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
&& info instanceof LauncherAppWidgetInfo
&& ((LauncherAppWidgetInfo) info).providerName != null) {
ComponentName cn = ((LauncherAppWidgetInfo) info).providerName;
return new AppTarget.Builder(new AppTargetId("widget:" + cn.getPackageName()),
cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
&& info.getTargetComponent() != null) {
ComponentName cn = info.getTargetComponent();
return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()),
cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
&& info instanceof WorkspaceItemInfo) {
ShortcutKey shortcutKey = ShortcutKey.fromItemInfo(info);
//TODO: switch to using full shortcut info
return new AppTarget.Builder(new AppTargetId("shortcut:" + shortcutKey.getId()),
shortcutKey.componentName.getPackageName(), shortcutKey.user).build();
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
return new AppTarget.Builder(new AppTargetId("folder:" + info.id),
mLauncher.getPackageName(), info.user).build();
}
return null;
}
private AppTargetEvent wrapAppTargetWithLocation(AppTarget target, int action, ItemInfo info) {
return wrapAppTargetWithLocation(target, action,
info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
? APP_LOCATION_HOTSEAT : APP_LOCATION_WORKSPACE, info.screenId, info.cellX,
info.cellY, info.spanX, info.spanY);
}
private AppTargetEvent wrapAppTargetWithLocation(AppTarget target, int action, String root,
int screenId, int x, int y, int spanX, int spanY) {
return new AppTargetEvent.Builder(target, action).setLaunchLocation(
String.format(Locale.ENGLISH, "%s/%d/[%d,%d]/[%d,%d]", root, screenId, x, y, spanX,
spanY)).build();
}
/**
* A helper method to generate an AppTarget that's used to communicate workspace layout
*/
private AppTarget getBlockAppTarget() {
return new AppTarget.Builder(new AppTargetId("block"),
mLauncher.getPackageName(), Process.myUserHandle()).build();
}
} }
@@ -33,14 +33,14 @@ import androidx.core.graphics.ColorUtils;
import com.android.launcher3.CellLayout; import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher; import com.android.launcher3.Launcher;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.graphics.IconPalette; import com.android.launcher3.graphics.IconPalette;
import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.hybridhotseat.HotseatPredictionController;
import com.android.launcher3.icons.IconNormalizer; import com.android.launcher3.icons.IconNormalizer;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemLongClickListener; import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.views.DoubleShadowBubbleTextView; import com.android.launcher3.views.DoubleShadowBubbleTextView;
@@ -136,9 +136,11 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView implements
@Override @Override
public void addSupportedAccessibilityActions(AccessibilityNodeInfo accessibilityNodeInfo) { public void addSupportedAccessibilityActions(AccessibilityNodeInfo accessibilityNodeInfo) {
accessibilityNodeInfo.addAction( if (!mIsPinned) {
new AccessibilityNodeInfo.AccessibilityAction(PIN_PREDICTION, accessibilityNodeInfo.addAction(
getContext().getText(R.string.pin_prediction))); new AccessibilityNodeInfo.AccessibilityAction(PIN_PREDICTION,
getContext().getText(R.string.pin_prediction)));
}
} }
@Override @Override
@@ -28,14 +28,14 @@ import androidx.annotation.Nullable;
import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher; import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherState;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.Folder;
import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.hybridhotseat.HotseatPredictionController;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.uioverrides.touchcontrollers.FlingAndHoldTouchController; import com.android.launcher3.uioverrides.touchcontrollers.FlingAndHoldTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.LandscapeEdgeSwipeController; import com.android.launcher3.uioverrides.touchcontrollers.LandscapeEdgeSwipeController;
@@ -46,11 +46,8 @@ import com.android.launcher3.R;
import com.android.launcher3.Utilities; import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.model.PagedViewOrientedState;
import com.android.launcher3.states.RotationHelper;
import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.touch.PortraitPagedViewHandler;
import com.android.launcher3.util.VibratorWrapper; import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.views.FloatingIconView; import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory; import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory;
@@ -59,6 +56,7 @@ import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams; import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.RectFSpringAnim; import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView; import com.android.quickstep.views.TaskView;
@@ -127,7 +125,7 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
protected boolean mCanceled; protected boolean mCanceled;
protected int mFinishingRecentsAnimationForNewTaskId = -1; protected int mFinishingRecentsAnimationForNewTaskId = -1;
private PagedViewOrientedState mOrientedState; private RecentsOrientedState mOrientedState;
protected BaseSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState, protected BaseSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState,
GestureState gestureState, InputConsumerController inputConsumer) { GestureState gestureState, InputConsumerController inputConsumer) {
@@ -199,18 +197,12 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
} }
protected void startNewTask(int successStateFlag, Consumer<Boolean> resultCallback) { protected void startNewTask(int successStateFlag, Consumer<Boolean> resultCallback) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_START_FROM_RECENTS, "startNewTask1");
}
// Launch the task user scrolled to (mRecentsView.getNextPage()). // Launch the task user scrolled to (mRecentsView.getNextPage()).
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
// We finish recents animation inside launchTask() when live tile is enabled. // We finish recents animation inside launchTask() when live tile is enabled.
mRecentsView.getNextPageTaskView().launchTask(false /* animate */, mRecentsView.getNextPageTaskView().launchTask(false /* animate */,
true /* freezeTaskList */); true /* freezeTaskList */);
} else { } else {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_START_FROM_RECENTS, "startNewTask2");
}
int taskId = mRecentsView.getNextPageTaskView().getTask().key.id; int taskId = mRecentsView.getNextPageTaskView().getTask().key.id;
if (!mCanceled) { if (!mCanceled) {
TaskView nextTask = mRecentsView.getTaskView(taskId); TaskView nextTask = mRecentsView.getTaskView(taskId);
@@ -337,9 +329,11 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
// TODO(b/150300347): The first recents animation after launcher is started with the // TODO(b/150300347): The first recents animation after launcher is started with the
// foreground app not in landscape will look funky until that bug is fixed // foreground app not in landscape will look funky until that bug is fixed
displayRotation = mOrientedState.getDisplayRotation(); displayRotation = mOrientedState.getDisplayRotation();
RectF tempRectF = new RectF(TEMP_RECT);
mOrientedState.mapRectFromNormalOrientation(tempRectF, dp.widthPx, dp.heightPx);
tempRectF.roundOut(TEMP_RECT);
} }
RotationHelper.getTargetRectForRotation(TEMP_RECT, dp.widthPx, dp.heightPx,
displayRotation);
mAppWindowAnimationHelper.updateTargetRect(TEMP_RECT); mAppWindowAnimationHelper.updateTargetRect(TEMP_RECT);
if (mDeviceState.isFullyGesturalNavMode()) { if (mDeviceState.isFullyGesturalNavMode()) {
// We can drag all the way to the top of the screen. // We can drag all the way to the top of the screen.
@@ -434,7 +428,7 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
protected PagedOrientationHandler getOrientationHandler() { protected PagedOrientationHandler getOrientationHandler() {
if (mOrientedState == null) { if (mOrientedState == null) {
return new PortraitPagedViewHandler(); return PagedOrientationHandler.PORTRAIT;
} }
return mOrientedState.getOrientationHandler(); return mOrientedState.getOrientationHandler();
} }
@@ -455,8 +449,8 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
.setTargetSet(mRecentsAnimationTargets) .setTargetSet(mRecentsAnimationTargets)
.setLauncherOnTop(false))); .setLauncherOnTop(false)));
if (isFloatingIconView) { if (isFloatingIconView) {
RotationHelper.mapInverseRectFromNormalOrientation(startRect, mOrientedState.mapInverseRectFromNormalOrientation(
mDp.widthPx, mDp.heightPx, mOrientedState.getDisplayRotation()); startRect, mDp.widthPx, mDp.heightPx);
} }
RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext); RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext);
if (isFloatingIconView) { if (isFloatingIconView) {
@@ -487,8 +481,8 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
rotatedRect.set(currentRect); rotatedRect.set(currentRect);
if (isFloatingIconView) { if (isFloatingIconView) {
RotationHelper.mapRectFromNormalOrientation(rotatedRect, mOrientedState.mapRectFromNormalOrientation(
mDp.widthPx, mDp.heightPx, mOrientedState.getDisplayRotation()); rotatedRect, mDp.widthPx, mDp.heightPx);
mTransformParams.setCornerRadius(endRadius * progress + startRadius mTransformParams.setCornerRadius(endRadius * progress + startRadius
* (1f - progress)); * (1f - progress));
} }
@@ -33,8 +33,6 @@ import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile;
import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.touch.PortraitPagedViewHandler;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.fallback.FallbackRecentsView; import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.ActivityInitListener;
@@ -40,9 +40,7 @@ import android.view.MotionEvent;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.touch.LandscapePagedViewHandler;
import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.touch.PortraitPagedViewHandler;
import com.android.launcher3.util.ObjectWrapper; import com.android.launcher3.util.ObjectWrapper;
import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory; import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory;
import com.android.quickstep.GestureState.GestureEndTarget; import com.android.quickstep.GestureState.GestureEndTarget;
@@ -503,8 +501,8 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
PagedOrientationHandler orientationHandler = mRecentsView != null PagedOrientationHandler orientationHandler = mRecentsView != null
? mRecentsView.getPagedOrientationHandler() ? mRecentsView.getPagedOrientationHandler()
: (mDp.isLandscape : (mDp.isLandscape
? new LandscapePagedViewHandler() ? PagedOrientationHandler.LANDSCAPE
: new PortraitPagedViewHandler()); : PagedOrientationHandler.PORTRAIT);
return HomeAnimationFactory return HomeAnimationFactory
.getDefaultWindowTargetRect(orientationHandler, mDp); .getDefaultWindowTargetRect(orientationHandler, mDp);
} }
@@ -984,9 +984,6 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
windowAnim.addListener(new AnimationSuccessListener() { windowAnim.addListener(new AnimationSuccessListener() {
@Override @Override
public void onAnimationSuccess(Animator animator) { public void onAnimationSuccess(Animator animator) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_START_FROM_RECENTS, "onAnimationSuccess");
}
if (mRecentsAnimationController == null) { if (mRecentsAnimationController == null) {
// If the recents animation is interrupted, we still end the running // If the recents animation is interrupted, we still end the running
// animation (not canceled) so this is still called. In that case, we can // animation (not canceled) so this is still called. In that case, we can
@@ -1210,9 +1207,6 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
} }
private void switchToScreenshot() { private void switchToScreenshot() {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_START_FROM_RECENTS, "switchToScreenshot");
}
final int runningTaskId = mGestureState.getRunningTaskId(); final int runningTaskId = mGestureState.getRunningTaskId();
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (mRecentsAnimationController != null) { if (mRecentsAnimationController != null) {
@@ -35,8 +35,8 @@ import android.view.View;
import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.model.WellbeingModel; import com.android.launcher3.model.WellbeingModel;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.popup.SystemShortcut.AppInfo; import com.android.launcher3.popup.SystemShortcut.AppInfo;
import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -71,7 +71,7 @@ public interface TaskShortcutFactory {
WorkspaceItemInfo dummyInfo = new WorkspaceItemInfo(); WorkspaceItemInfo dummyInfo = new WorkspaceItemInfo();
dummyInfo.intent = new Intent(); dummyInfo.intent = new Intent();
ComponentName component = task.getTopComponent(); ComponentName component = task.getTopComponent();
dummyInfo.intent.setComponent(component); dummyInfo.getIntent().setComponent(component);
dummyInfo.user = UserHandle.of(task.key.userId); dummyInfo.user = UserHandle.of(task.key.userId);
dummyInfo.title = TaskUtils.getTitle(view.getContext(), task); dummyInfo.title = TaskUtils.getTitle(view.getContext(), task);
return dummyInfo; return dummyInfo;
@@ -33,8 +33,8 @@ import android.view.View;
import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Utilities; import com.android.launcher3.Utilities;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.statehandlers.DepthController;
import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.util.MultiValueUpdateListener; import com.android.quickstep.util.MultiValueUpdateListener;
@@ -26,11 +26,12 @@ import static com.android.quickstep.GestureState.DEFAULT_STATE;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.RunningTaskInfo;
import android.app.PendingIntent;
import android.app.RemoteAction;
import android.app.Service; import android.app.Service;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
@@ -38,6 +39,7 @@ import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.graphics.Region; import android.graphics.Region;
import android.graphics.drawable.Icon;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
@@ -46,6 +48,7 @@ import android.util.Log;
import android.view.Choreographer; import android.view.Choreographer;
import android.view.InputEvent; import android.view.InputEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.accessibility.AccessibilityManager;
import androidx.annotation.BinderThread; import androidx.annotation.BinderThread;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@@ -53,8 +56,8 @@ import androidx.annotation.UiThread;
import androidx.annotation.WorkerThread; import androidx.annotation.WorkerThread;
import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.launcher3.Utilities; import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.model.AppLaunchTracker; import com.android.launcher3.model.AppLaunchTracker;
@@ -64,6 +67,7 @@ import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.tracing.nano.LauncherTraceProto; import com.android.launcher3.tracing.nano.LauncherTraceProto;
import com.android.launcher3.tracing.nano.TouchInteractionServiceProto; import com.android.launcher3.tracing.nano.TouchInteractionServiceProto;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.TraceHelper; import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.inputconsumers.AccessibilityInputConsumer; import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
import com.android.quickstep.inputconsumers.AssistantInputConsumer; import com.android.quickstep.inputconsumers.AssistantInputConsumer;
@@ -126,6 +130,12 @@ public class TouchInteractionService extends Service implements PluginListener<O
private static final String HAS_ENABLED_QUICKSTEP_ONCE = "launcher.has_enabled_quickstep_once"; private static final String HAS_ENABLED_QUICKSTEP_ONCE = "launcher.has_enabled_quickstep_once";
private static final int MAX_BACK_NOTIFICATION_COUNT = 3; private static final int MAX_BACK_NOTIFICATION_COUNT = 3;
/**
* System Action ID to show all apps. This ID should follow the ones in
* com.android.systemui.accessibility.SystemActions.
*/
private static final int SYSTEM_ACTION_ID_ALL_APPS = 100;
private int mBackGestureNotificationCounter = -1; private int mBackGestureNotificationCounter = -1;
@Nullable @Nullable
private OverscrollPlugin mOverscrollPlugin; private OverscrollPlugin mOverscrollPlugin;
@@ -351,6 +361,9 @@ public class TouchInteractionService extends Service implements PluginListener<O
PluginManagerWrapper.INSTANCE.get(getBaseContext()).addPluginListener(this, PluginManagerWrapper.INSTANCE.get(getBaseContext()).addPluginListener(this,
OverscrollPlugin.class, false /* allowMultiple */); OverscrollPlugin.class, false /* allowMultiple */);
mOverviewComponentObserver.setOverviewChangeListener(this::onOverviewTargetChange);
onOverviewTargetChange(mOverviewComponentObserver.isHomeAndOverviewSame());
} }
private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() { private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() {
@@ -365,11 +378,29 @@ public class TouchInteractionService extends Service implements PluginListener<O
if (!sharedPrefs.getBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)) { if (!sharedPrefs.getBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)) {
sharedPrefs.edit() sharedPrefs.edit()
.putBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true) .putBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)
.putBoolean(DiscoveryBounce.HOME_BOUNCE_SEEN, false) .putBoolean(OnboardingPrefs.HOME_BOUNCE_SEEN, false)
.apply(); .apply();
} }
} }
private void onOverviewTargetChange(boolean isHomeAndOverviewSame) {
AccessibilityManager am = getSystemService(AccessibilityManager.class);
if (isHomeAndOverviewSame) {
Intent intent = new Intent(mOverviewComponentObserver.getHomeIntent())
.setAction(Intent.ACTION_ALL_APPS);
RemoteAction allAppsAction = new RemoteAction(
Icon.createWithResource(this, R.drawable.ic_apps),
getString(R.string.all_apps_label),
getString(R.string.all_apps_label),
PendingIntent.getActivity(this, SYSTEM_ACTION_ID_ALL_APPS, intent,
PendingIntent.FLAG_UPDATE_CURRENT));
am.registerSystemAction(allAppsAction, SYSTEM_ACTION_ID_ALL_APPS);
} else {
am.unregisterSystemAction(SYSTEM_ACTION_ID_ALL_APPS);
}
}
@UiThread @UiThread
private void onSystemUiFlagsChanged() { private void onSystemUiFlagsChanged() {
if (mDeviceState.isUserUnlocked()) { if (mDeviceState.isUserUnlocked()) {
@@ -408,6 +439,9 @@ public class TouchInteractionService extends Service implements PluginListener<O
ProtoTracer.INSTANCE.get(TouchInteractionService.this).stop(); ProtoTracer.INSTANCE.get(TouchInteractionService.this).stop();
ProtoTracer.INSTANCE.get(this).remove(this); ProtoTracer.INSTANCE.get(this).remove(this);
getSystemService(AccessibilityManager.class)
.unregisterSystemAction(SYSTEM_ACTION_ID_ALL_APPS);
sConnected = false; sConnected = false;
super.onDestroy(); super.onDestroy();
} }
@@ -451,7 +485,7 @@ public class TouchInteractionService extends Service implements PluginListener<O
mConsumer.onConsumerAboutToBeSwitched(); mConsumer.onConsumerAboutToBeSwitched();
mConsumer = newConsumer(prevGestureState, newGestureState, event); mConsumer = newConsumer(prevGestureState, newGestureState, event);
ActiveGestureLog.INSTANCE.addLog("setInputConsumer", mConsumer.getType()); ActiveGestureLog.INSTANCE.addLog("setInputConsumer: " + mConsumer.getName());
mUncheckedConsumer = mConsumer; mUncheckedConsumer = mConsumer;
} else if (mDeviceState.isUserUnlocked() } else if (mDeviceState.isUserUnlocked()
&& mDeviceState.isFullyGesturalNavMode() && mDeviceState.isFullyGesturalNavMode()
@@ -481,14 +515,14 @@ public class TouchInteractionService extends Service implements PluginListener<O
} }
ActiveGestureLog.INSTANCE.addLog("onMotionEvent", event.getActionMasked()); ActiveGestureLog.INSTANCE.addLog("onMotionEvent", event.getActionMasked());
boolean cleanUpConsumer = (action == ACTION_UP || action == ACTION_CANCEL)
&& mConsumer != null
&& !mConsumer.getActiveConsumerInHierarchy().isConsumerDetachedFromGesture();
mUncheckedConsumer.onMotionEvent(event); mUncheckedConsumer.onMotionEvent(event);
if (action == ACTION_UP || action == ACTION_CANCEL) { if (cleanUpConsumer) {
if (mConsumer != null && !mConsumer.isConsumerDetachedFromGesture()) { reset();
onConsumerInactive(mConsumer);
}
} }
TraceHelper.INSTANCE.endFlagsOverride(traceToken); TraceHelper.INSTANCE.endFlagsOverride(traceToken);
} }
@@ -496,7 +530,7 @@ public class TouchInteractionService extends Service implements PluginListener<O
GestureState gestureState = new GestureState(mOverviewComponentObserver, GestureState gestureState = new GestureState(mOverviewComponentObserver,
ActiveGestureLog.INSTANCE.generateAndSetLogId()); ActiveGestureLog.INSTANCE.generateAndSetLogId());
gestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.0", gestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.0",
() -> mAM.getRunningTask(true /* filterOnlyVisibleRecents */))); () -> mAM.getRunningTask(false /* filterOnlyVisibleRecents */)));
return gestureState; return gestureState;
} }
@@ -505,6 +539,8 @@ public class TouchInteractionService extends Service implements PluginListener<O
boolean canStartSystemGesture = mDeviceState.canStartSystemGesture(); boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
if (!mDeviceState.isUserUnlocked()) { if (!mDeviceState.isUserUnlocked()) {
Log.d(TAG, "User locked. Can start system gesture? " + canStartSystemGesture
+ " sysUiFlags: " + mDeviceState.getSystemUiStateFlags());
if (canStartSystemGesture) { if (canStartSystemGesture) {
// This handles apps launched in direct boot mode (e.g. dialer) as well as apps // This handles apps launched in direct boot mode (e.g. dialer) as well as apps
// launched while device is locked even after exiting direct boot mode (e.g. camera). // launched while device is locked even after exiting direct boot mode (e.g. camera).
@@ -596,10 +632,18 @@ public class TouchInteractionService extends Service implements PluginListener<O
return createDeviceLockedInputConsumer(gestureState); return createDeviceLockedInputConsumer(gestureState);
} }
RunningTaskInfo runningTask = gestureState.getRunningTask(); boolean forceOverviewInputConsumer = false;
ComponentName homeComponent = mOverviewComponentObserver.getHomeIntent().getComponent(); if (AssistantUtilities.isExcludedAssistant(gestureState.getRunningTask())) {
boolean forceOverviewInputConsumer = runningTask != null // In the case where we are in the excluded assistant state, ignore it and treat the
&& runningTask.baseIntent.getComponent().equals(homeComponent); // running activity as the task behind the assistant
gestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.assistant",
() -> mAM.getRunningTask(true /* filterOnlyVisibleRecents */)));
ComponentName homeComponent = mOverviewComponentObserver.getHomeIntent().getComponent();
ComponentName runningComponent =
gestureState.getRunningTask().baseIntent.getComponent();
forceOverviewInputConsumer =
runningComponent != null && runningComponent.equals(homeComponent);
}
if (previousGestureState.getFinishingRecentsAnimationTaskId() > 0) { if (previousGestureState.getFinishingRecentsAnimationTaskId() > 0) {
// If the finish animation was interrupted, then continue using the other activity input // If the finish animation was interrupted, then continue using the other activity input
@@ -678,15 +722,21 @@ public class TouchInteractionService extends Service implements PluginListener<O
} }
/** /**
* To be called by the consumer when it's no longer active. * To be called by the consumer when it's no longer active. This can be called by any consumer
* in the hierarchy at any point during the gesture (ie. if a delegate consumer starts
* intercepting touches, the base consumer can try to call this).
*/ */
private void onConsumerInactive(InputConsumer caller) { private void onConsumerInactive(InputConsumer caller) {
if (mConsumer != null && mConsumer.isInConsumerHierarchy(caller)) { if (mConsumer != null && mConsumer.getActiveConsumerInHierarchy() == caller) {
mConsumer = mUncheckedConsumer = mResetGestureInputConsumer; reset();
mGestureState = new GestureState();
} }
} }
private void reset() {
mConsumer = mUncheckedConsumer = mResetGestureInputConsumer;
mGestureState = new GestureState();
}
private void preloadOverview(boolean fromInit) { private void preloadOverview(boolean fromInit) {
if (!mDeviceState.isUserUnlocked()) { if (!mDeviceState.isUserUnlocked()) {
return; return;
@@ -25,13 +25,11 @@ public abstract class DelegateInputConsumer implements InputConsumer {
} }
@Override @Override
public boolean isConsumerDetachedFromGesture() { public InputConsumer getActiveConsumerInHierarchy() {
return mDelegate.isConsumerDetachedFromGesture(); if (mState == STATE_ACTIVE) {
} return this;
}
@Override return mDelegate.getActiveConsumerInHierarchy();
public boolean isInConsumerHierarchy(InputConsumer candidate) {
return this == candidate || mDelegate.isInConsumerHierarchy(candidate);
} }
@Override @Override
@@ -19,8 +19,8 @@ import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.appprediction.PredictionUiStateManager; import com.android.launcher3.appprediction.PredictionUiStateManager;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto;
import java.util.ArrayList; import java.util.ArrayList;
@@ -15,6 +15,13 @@
*/ */
package com.android.quickstep.util; package com.android.quickstep.util;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
@@ -33,7 +40,6 @@ import com.android.launcher3.LauncherState;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.Utilities; import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.model.PagedViewOrientedState;
import com.android.launcher3.views.BaseDragLayer; import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.RemoteAnimationTargets; import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.SystemUiProxy; import com.android.quickstep.SystemUiProxy;
@@ -47,13 +53,6 @@ import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.
import com.android.systemui.shared.system.TransactionCompat; import com.android.systemui.shared.system.TransactionCompat;
import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.shared.system.WindowManagerWrapper;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
/** /**
* Utility class to handle window clip animation * Utility class to handle window clip animation
*/ */
@@ -86,7 +85,7 @@ public class AppWindowAnimationHelper {
private final Rect mTmpRect = new Rect(); private final Rect mTmpRect = new Rect();
private final RectF mTmpRectF = new RectF(); private final RectF mTmpRectF = new RectF();
private final RectF mCurrentRectWithInsets = new RectF(); private final RectF mCurrentRectWithInsets = new RectF();
private PagedViewOrientedState mOrientedState; private RecentsOrientedState mOrientedState;
// Corner radius of windows, in pixels // Corner radius of windows, in pixels
private final float mWindowCornerRadius; private final float mWindowCornerRadius;
// Corner radius of windows when they're in overview mode. // Corner radius of windows when they're in overview mode.
@@ -105,7 +104,7 @@ public class AppWindowAnimationHelper {
private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a; private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a;
private TargetAlphaProvider mBaseAlphaCallback = (t, a) -> 1; private TargetAlphaProvider mBaseAlphaCallback = (t, a) -> 1;
public AppWindowAnimationHelper(PagedViewOrientedState orientedState, Context context) { public AppWindowAnimationHelper(RecentsOrientedState orientedState, Context context) {
Resources res = context.getResources(); Resources res = context.getResources();
mOrientedState = orientedState; mOrientedState = orientedState;
mWindowCornerRadius = getWindowCornerRadius(res); mWindowCornerRadius = getWindowCornerRadius(res);
@@ -78,21 +78,6 @@ public class ClearAllButton extends Button implements PageCallbacks {
} }
} }
public void onLayoutChanged() {
if (mParent == null) {
return;
}
setRotation(mParent.getPagedOrientationHandler().getDegreesRotated());
}
public void setRtl(boolean rtl) {
if (mIsRtl == rtl) {
return;
}
mIsRtl = rtl;
invalidate();
}
public void setVisibilityAlpha(float alpha) { public void setVisibilityAlpha(float alpha) {
if (mVisibilityAlpha != alpha) { if (mVisibilityAlpha != alpha) {
mVisibilityAlpha = alpha; mVisibilityAlpha = alpha;
@@ -100,8 +100,8 @@ import com.android.launcher3.anim.SpringProperty;
import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.states.RotationHelper;
import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.touch.PagedOrientationHandler.CurveProperties; import com.android.launcher3.touch.PagedOrientationHandler.CurveProperties;
import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
@@ -122,6 +122,7 @@ import com.android.quickstep.TaskUtils;
import com.android.quickstep.ViewUtils; import com.android.quickstep.ViewUtils;
import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.systemui.plugins.ResourceProvider; import com.android.systemui.plugins.ResourceProvider;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener; import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.Task;
@@ -171,6 +172,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
} }
}; };
protected final RecentsOrientedState mOrientationState = new RecentsOrientedState();
private OrientationEventListener mOrientationListener; private OrientationEventListener mOrientationListener;
private int mPreviousRotation; private int mPreviousRotation;
protected RecentsAnimationController mRecentsAnimationController; protected RecentsAnimationController mRecentsAnimationController;
@@ -383,7 +386,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
mOrientationListener = new OrientationEventListener(getContext()) { mOrientationListener = new OrientationEventListener(getContext()) {
@Override @Override
public void onOrientationChanged(int i) { public void onOrientationChanged(int i) {
int rotation = RotationHelper.getRotationFromDegrees(i); int rotation = RecentsOrientedState.getRotationForUserDegreesRotated(i);
if (mPreviousRotation != rotation) { if (mPreviousRotation != rotation) {
animateRecentsRotationInPlace(rotation); animateRecentsRotationInPlace(rotation);
if (rotation == 0) { if (rotation == 0) {
@@ -505,6 +508,29 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
mHasVisibleTaskData.delete(taskView.getTask().key.id); mHasVisibleTaskData.delete(taskView.getTask().key.id);
mTaskViewPool.recycle(taskView); mTaskViewPool.recycle(taskView);
} }
updateTaskStartIndex(child);
}
@Override
public void onViewAdded(View child) {
super.onViewAdded(child);
child.setAlpha(mContentAlpha);
// RecentsView is set to RTL in the constructor when system is using LTR. Here we set the
// child direction back to match system settings.
child.setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_LTR : View.LAYOUT_DIRECTION_RTL);
updateTaskStartIndex(child);
}
private void updateTaskStartIndex(View affectingView) {
if (!(affectingView instanceof TaskView) && !(affectingView instanceof ClearAllButton)) {
int childCount = getChildCount();
mTaskViewStartIndex = 0;
while (mTaskViewStartIndex < childCount
&& !(getChildAt(mTaskViewStartIndex) instanceof TaskView)) {
mTaskViewStartIndex++;
}
}
} }
public boolean isTaskViewVisible(TaskView tv) { public boolean isTaskViewVisible(TaskView tv) {
@@ -661,7 +687,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
final int pageIndex = requiredTaskCount - i - 1 + mTaskViewStartIndex; final int pageIndex = requiredTaskCount - i - 1 + mTaskViewStartIndex;
final Task task = tasks.get(i); final Task task = tasks.get(i);
final TaskView taskView = (TaskView) getChildAt(pageIndex); final TaskView taskView = (TaskView) getChildAt(pageIndex);
taskView.bind(task, mLayoutRotation); taskView.bind(task, mOrientationState);
} }
if (mNextPage == INVALID_PAGE) { if (mNextPage == INVALID_PAGE) {
@@ -710,11 +736,15 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
int currentIndex = indexOfChild(taskView); int currentIndex = indexOfChild(taskView);
TaskView previousTask = getTaskViewAt(currentIndex - 1); TaskView previousTask = getTaskViewAt(currentIndex - 1);
TaskView nextTask = getTaskViewAt(currentIndex + 1); TaskView nextTask = getTaskViewAt(currentIndex + 1);
float alpha = isTaskOverlayModal ? 0.0f : 1.0f;
if (previousTask != null) { if (previousTask != null) {
previousTask.setVisibility(isTaskOverlayModal ? View.INVISIBLE : View.VISIBLE); previousTask.animate().alpha(alpha)
.translationX(isTaskOverlayModal ? previousTask.getWidth() / 2 : 0);
} }
if (nextTask != null) { if (nextTask != null) {
nextTask.setVisibility(isTaskOverlayModal ? View.INVISIBLE : View.VISIBLE); nextTask.animate().alpha(alpha)
.translationX(isTaskOverlayModal ? -nextTask.getWidth() / 2 : 0);
} }
} }
@@ -819,7 +849,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
final int pageCount = getPageCount(); final int pageCount = getPageCount();
for (int i = 0; i < pageCount; i++) { for (int i = 0; i < pageCount; i++) {
View page = getPageAt(i); View page = getPageAt(i);
mScrollState.updateInterpolation(mOrientationHandler.getChildStart(page), mPageSpacing); mScrollState.updateInterpolation(mOrientationHandler.getChildStartWithTranslation(page),
mPageSpacing);
((PageCallbacks) page).onPageScroll(mScrollState); ((PageCallbacks) page).onPageScroll(mScrollState);
} }
} }
@@ -973,7 +1004,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
AnimatorSet pa = setRecentsChangedOrientation(true); AnimatorSet pa = setRecentsChangedOrientation(true);
pa.addListener(AnimationSuccessListener.forRunnable(() -> { pa.addListener(AnimationSuccessListener.forRunnable(() -> {
updateLayoutRotation(newRotation); setLayoutRotation(newRotation, mOrientationState.getDisplayRotation());
mActivity.getDragLayer().recreateControllers(); mActivity.getDragLayer().recreateControllers();
rotateAllChildTasks(); rotateAllChildTasks();
setRecentsChangedOrientation(false).start(); setRecentsChangedOrientation(false).start();
@@ -999,8 +1030,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
private void rotateAllChildTasks() { private void rotateAllChildTasks() {
for (int i = 0; i < getTaskViewCount(); i++) { for (int i = 0; i < getTaskViewCount(); i++) {
TaskView taskView = getTaskViewAt(i); getTaskViewAt(i).setOrientationState(mOrientationState);
taskView.setOverviewRotation(mLayoutRotation);
} }
} }
@@ -1041,7 +1071,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
new ComponentName(getContext(), getClass()), 0, 0), null, null, "", "", 0, 0, new ComponentName(getContext(), getClass()), 0, 0), null, null, "", "", 0, 0,
false, true, false, false, new ActivityManager.TaskDescription(), 0, false, true, false, false, new ActivityManager.TaskDescription(), 0,
new ComponentName("", ""), false); new ComponentName("", ""), false);
taskView.bind(mTmpRunningTask, mLayoutRotation); taskView.bind(mTmpRunningTask, mOrientationState);
} }
boolean runningTaskTileHidden = mRunningTaskTileHidden; boolean runningTaskTileHidden = mRunningTaskTileHidden;
@@ -1207,7 +1237,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
/** /**
* Updates linearInterpolation for the provided child position * Updates linearInterpolation for the provided child position
*/ */
public void updateInterpolation(int childStart, int pageSpacing) { public void updateInterpolation(float childStart, int pageSpacing) {
float pageCenter = childStart + halfPageSize; float pageCenter = childStart + halfPageSize;
float distanceFromScreenCenter = screenCenter - pageCenter; float distanceFromScreenCenter = screenCenter - pageCenter;
float distanceToReachEdge = halfScreenSize + halfPageSize + pageSpacing; float distanceToReachEdge = halfScreenSize + halfPageSize + pageSpacing;
@@ -1530,22 +1560,28 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
} }
} }
@Override
public void setLayoutRotation(int touchRotation, int displayRotation) { public void setLayoutRotation(int touchRotation, int displayRotation) {
if (!FeatureFlags.ENABLE_FIXED_ROTATION_TRANSFORM.get()) { if (mOrientationState.update(touchRotation, displayRotation)) {
return; mOrientationHandler = mOrientationState.getOrientationHandler();
mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
mClearAllButton.setRotation(mOrientationHandler.getDegreesRotated());
requestLayout();
} }
super.setLayoutRotation(touchRotation, displayRotation);
mClearAllButton.onLayoutChanged();
mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
} }
@Override public void disableMultipleLayoutRotations(boolean disable) {
public void onViewAdded(View child) { mOrientationState.disableMultipleOrientations(disable);
super.onViewAdded(child); mOrientationHandler = mOrientationState.getOrientationHandler();
child.setAlpha(mContentAlpha); requestLayout();
}
public RecentsOrientedState getPagedViewOrientedState() {
return mOrientationState;
}
public PagedOrientationHandler getPagedOrientationHandler() {
return mOrientationHandler;
} }
@Nullable @Nullable
@@ -1986,8 +2022,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) { public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
float degreesRotated; float degreesRotated;
if (navbarRotation == 0) { if (navbarRotation == 0) {
degreesRotated = mOrientationState.areMultipleLayoutOrientationsDisabled() ? 0 : degreesRotated = mOrientationState.getTouchRotationDegrees();
RotationHelper.getDegreesFromRotation(mLayoutRotation);
} else { } else {
degreesRotated = -navbarRotation; degreesRotated = -navbarRotation;
} }
@@ -2001,14 +2036,14 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
return e -> { return e -> {
if (navbarRotation != 0 if (navbarRotation != 0
&& !mOrientationState.areMultipleLayoutOrientationsDisabled()) { && !mOrientationState.areMultipleLayoutOrientationsDisabled()) {
RotationHelper.transformEventForNavBar(e, true); mOrientationState.flipVertical(e);
super.onTouchEvent(e); super.onTouchEvent(e);
RotationHelper.transformEventForNavBar(e, false); mOrientationState.flipVertical(e);
return; return;
} }
RotationHelper.transformEvent(-degreesRotated, e, true); mOrientationState.transformEvent(-degreesRotated, e, true);
super.onTouchEvent(e); super.onTouchEvent(e);
RotationHelper.transformEvent(-degreesRotated, e, false); mOrientationState.transformEvent(-degreesRotated, e, false);
}; };
} }
@@ -2056,37 +2091,11 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
} }
} }
@Override
public void addView(View child, int index) {
// RecentsView is set to RTL in the constructor when system is using LTR. Here we set the
// child direction back to match system settings.
child.setLayoutDirection(
Utilities.isRtl(getResources())
? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
super.addView(child, index);
if (isExtraCardView(child, index)) {
mTaskViewStartIndex++;
}
}
@Override
public void removeView(View view) {
if (isExtraCardView(view, indexOfChild(view))) {
mTaskViewStartIndex--;
}
super.removeView(view);
}
@Nullable @Nullable
protected DepthController getDepthController() { protected DepthController getDepthController() {
return null; return null;
} }
private boolean isExtraCardView(View view, int index) {
return !(view instanceof TaskView) && !(view instanceof ClearAllButton)
&& index <= mTaskViewStartIndex;
}
/** /**
* Used to register callbacks for when our empty message state changes. * Used to register callbacks for when our empty message state changes.
* *
@@ -2131,13 +2140,15 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
&& SysUINavigationMode.removeShelfFromOverview(mActivity)) { && SysUINavigationMode.removeShelfFromOverview(mActivity)) {
mActionsView = ((ViewGroup) getParent()).findViewById(R.id.overview_actions_view); mActionsView = ((ViewGroup) getParent()).findViewById(R.id.overview_actions_view);
if (mActionsView != null) { if (mActionsView != null) {
Rect rect = new Rect();
getTaskSize(rect);
InsettableFrameLayout.LayoutParams layoutParams = InsettableFrameLayout.LayoutParams layoutParams =
new InsettableFrameLayout.LayoutParams(rect.width(), new InsettableFrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
getResources().getDimensionPixelSize( getResources().getDimensionPixelSize(
R.dimen.overview_actions_height)); R.dimen.overview_actions_height));
layoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; layoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
int margin = getResources().getDimensionPixelSize(
R.dimen.overview_actions_horizontal_margin);
layoutParams.setMarginStart(margin);
layoutParams.setMarginEnd(margin);
mActionsView.setLayoutParams(layoutParams); mActionsView.setLayoutParams(layoutParams);
showActionsView(); showActionsView();
} }
@@ -64,7 +64,6 @@ import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.states.RotationHelper;
import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.touch.PagedOrientationHandler;
@@ -79,6 +78,7 @@ import com.android.quickstep.TaskOverlayFactory;
import com.android.quickstep.TaskThumbnailCache; import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.TaskUtils; import com.android.quickstep.TaskUtils;
import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.TaskCornerRadius; import com.android.quickstep.util.TaskCornerRadius;
import com.android.quickstep.views.RecentsView.PageCallbacks; import com.android.quickstep.views.RecentsView.PageCallbacks;
import com.android.quickstep.views.RecentsView.ScrollState; import com.android.quickstep.views.RecentsView.ScrollState;
@@ -119,19 +119,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
private static final List<Rect> SYSTEM_GESTURE_EXCLUSION_RECT = private static final List<Rect> SYSTEM_GESTURE_EXCLUSION_RECT =
Collections.singletonList(new Rect()); Collections.singletonList(new Rect());
public static final FloatProperty<TaskView> FULLSCREEN_PROGRESS =
new FloatProperty<TaskView>("fullscreenProgress") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setFullscreenProgress(v);
}
@Override
public Float get(TaskView taskView) {
return taskView.mFullscreenProgress;
}
};
private static final FloatProperty<TaskView> FOCUS_TRANSITION = private static final FloatProperty<TaskView> FOCUS_TRANSITION =
new FloatProperty<TaskView>("focusTransition") { new FloatProperty<TaskView>("focusTransition") {
@Override @Override
@@ -180,6 +167,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
private float mStableAlpha = 1; private float mStableAlpha = 1;
private boolean mShowScreenshot; private boolean mShowScreenshot;
private boolean mRunningModalAnimation = false;
// The current background requests to load the task thumbnail and icon // The current background requests to load the task thumbnail and icon
private TaskThumbnailCache.ThumbnailLoadRequest mThumbnailLoadRequest; private TaskThumbnailCache.ThumbnailLoadRequest mThumbnailLoadRequest;
@@ -262,17 +250,39 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
/** Updates UI based on whether the task is modal. */ /** Updates UI based on whether the task is modal. */
public void updateUiForModalTask() { public void updateUiForModalTask() {
boolean isOverlayModal = isTaskOverlayModal(); boolean isOverlayModal = isTaskOverlayModal();
mRunningModalAnimation = true;
if (getRecentsView() != null) { if (getRecentsView() != null) {
getRecentsView().updateUiForModalTask(this, isOverlayModal); getRecentsView().updateUiForModalTask(this, isOverlayModal);
} }
// Hide footers when overlay is modal.
// Hides footers and icon when overlay is modal.
if (isOverlayModal) { if (isOverlayModal) {
for (FooterWrapper footer : mFooters) { for (FooterWrapper footer : mFooters) {
if (footer != null) { if (footer != null) {
footer.animateHide(); footer.animateHide();
} }
} }
mIconView.animate().alpha(0.0f);
} else {
mIconView.animate().alpha(1.0f);
} }
// Sets animations for modal UI. We will remove the margins to zoom in the snapshot.
float topMargin = getResources().getDimension(R.dimen.task_thumbnail_top_margin);
float bottomMargin =
getResources().getDimension(R.dimen.task_thumbnail_bottom_margin_with_actions);
float newHeight = mSnapshotView.getHeight() + topMargin + bottomMargin;
float scale = isOverlayModal ? newHeight / mSnapshotView.getHeight() : 1.0f;
float centerDifference = (bottomMargin - topMargin) / 2;
float translationY = isOverlayModal ? centerDifference : 0;
this.animate().scaleX(scale).scaleY(scale).translationY(translationY)
.withEndAction(new Runnable() {
@Override
public void run() {
setCurveScale(scale);
mRunningModalAnimation = false;
}
});
} }
public TaskMenuView getMenuView() { public TaskMenuView getMenuView() {
@@ -286,11 +296,11 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
/** /**
* Updates this task view to the given {@param task}. * Updates this task view to the given {@param task}.
*/ */
public void bind(Task task, int recentsRotation) { public void bind(Task task, RecentsOrientedState orientedState) {
cancelPendingLoadTasks(); cancelPendingLoadTasks();
mTask = task; mTask = task;
mSnapshotView.bind(task); mSnapshotView.bind(task);
setOverviewRotation(recentsRotation); setOrientationState(orientedState);
} }
public Task getTask() { public Task getTask() {
@@ -459,14 +469,15 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
} }
} }
void setOverviewRotation(int iconRotation) { public void setOrientationState(RecentsOrientedState orientationState) {
PagedOrientationHandler orientationHandler = getRecentsView().getPagedOrientationHandler(); int iconRotation = orientationState.getTouchRotation();
PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
boolean isRtl = orientationHandler.getRecentsRtlSetting(getResources()); boolean isRtl = orientationHandler.getRecentsRtlSetting(getResources());
LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams(); LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
snapshotParams.bottomMargin = LayoutUtils.thumbnailBottomMargin(getContext()); snapshotParams.bottomMargin = LayoutUtils.thumbnailBottomMargin(getContext());
int thumbnailPadding = (int) getResources().getDimension(R.dimen.task_thumbnail_top_margin); int thumbnailPadding = (int) getResources().getDimension(R.dimen.task_thumbnail_top_margin);
LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams(); LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
int rotation = RotationHelper.getDegreesFromRotation(iconRotation); int rotation = orientationState.getTouchRotationDegrees();
switch (iconRotation) { switch (iconRotation) {
case Surface.ROTATION_90: case Surface.ROTATION_90:
iconParams.gravity = (isRtl ? END : START) | CENTER_VERTICAL; iconParams.gravity = (isRtl ? END : START) | CENTER_VERTICAL;
@@ -579,11 +590,15 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
@Override @Override
public void onPageScroll(ScrollState scrollState) { public void onPageScroll(ScrollState scrollState) {
// Don't do anything if it's modal.
if (mRunningModalAnimation || isTaskOverlayModal()) {
return;
}
float curveInterpolation = float curveInterpolation =
CURVE_INTERPOLATOR.getInterpolation(scrollState.linearInterpolation); CURVE_INTERPOLATOR.getInterpolation(scrollState.linearInterpolation);
float curveScaleForCurveInterpolation = getCurveScaleForCurveInterpolation( float curveScaleForCurveInterpolation = getCurveScaleForCurveInterpolation(
curveInterpolation); curveInterpolation);
mSnapshotView.setDimAlpha(curveInterpolation * MAX_PAGE_SCRIM_ALPHA); mSnapshotView.setDimAlpha(curveInterpolation * MAX_PAGE_SCRIM_ALPHA);
setCurveScale(curveScaleForCurveInterpolation); setCurveScale(curveScaleForCurveInterpolation);
+2
View File
@@ -17,6 +17,7 @@
<resources> <resources>
<dimen name="task_thumbnail_top_margin">24dp</dimen> <dimen name="task_thumbnail_top_margin">24dp</dimen>
<dimen name="task_thumbnail_bottom_margin_with_actions">44dp</dimen>
<dimen name="task_thumbnail_half_top_margin">12dp</dimen> <dimen name="task_thumbnail_half_top_margin">12dp</dimen>
<dimen name="task_thumbnail_icon_size">48dp</dimen> <dimen name="task_thumbnail_icon_size">48dp</dimen>
<!-- For screens without rounded corners --> <!-- For screens without rounded corners -->
@@ -24,6 +25,7 @@
<!-- Overrideable in overlay that provides the Overview Actions. --> <!-- Overrideable in overlay that provides the Overview Actions. -->
<dimen name="overview_actions_height">110dp</dimen> <dimen name="overview_actions_height">110dp</dimen>
<dimen name="overview_actions_horizontal_margin">16dp</dimen>
<dimen name="recents_page_spacing">10dp</dimen> <dimen name="recents_page_spacing">10dp</dimen>
<dimen name="recents_clear_all_deadzone_vertical_margin">70dp</dimen> <dimen name="recents_clear_all_deadzone_vertical_margin">70dp</dimen>
@@ -17,14 +17,7 @@ package com.android.launcher3;
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL; import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
import static com.android.launcher3.AbstractFloatingView.TYPE_HIDE_BACK_BUTTON; import static com.android.launcher3.AbstractFloatingView.TYPE_HIDE_BACK_BUTTON;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.allapps.DiscoveryBounce.BOUNCE_MAX_COUNT;
import static com.android.launcher3.allapps.DiscoveryBounce.HOME_BOUNCE_COUNT;
import static com.android.launcher3.allapps.DiscoveryBounce.HOME_BOUNCE_SEEN;
import static com.android.launcher3.allapps.DiscoveryBounce.SHELF_BOUNCE_COUNT;
import static com.android.launcher3.allapps.DiscoveryBounce.SHELF_BOUNCE_SEEN;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview; import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
@@ -32,13 +25,13 @@ import android.animation.AnimatorSet;
import android.animation.ValueAnimator; import android.animation.ValueAnimator;
import android.content.Intent; import android.content.Intent;
import android.content.IntentSender; import android.content.IntentSender;
import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.os.CancellationSignal; import android.os.CancellationSignal;
import android.view.View; import android.view.View;
import com.android.launcher3.LauncherState.ScaleAndTranslation; import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.LauncherStateManager.StateHandler; import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.accessibility.SystemActions;
import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.WellbeingModel; import com.android.launcher3.model.WellbeingModel;
import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.popup.SystemShortcut;
@@ -48,12 +41,14 @@ import com.android.launcher3.statehandlers.BackButtonAlphaHandler;
import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.uioverrides.RecentsViewStateController; import com.android.launcher3.uioverrides.RecentsViewStateController;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.UiThreadHelper; import com.android.launcher3.util.UiThreadHelper;
import com.android.quickstep.RecentsModel; import com.android.quickstep.RecentsModel;
import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener; import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
import com.android.quickstep.SystemUiProxy; import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.QuickstepOnboardingPrefs;
import com.android.quickstep.util.RemoteAnimationProvider; import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.quickstep.util.RemoteFadeOutAnimationListener; import com.android.quickstep.util.RemoteFadeOutAnimationListener;
import com.android.quickstep.util.ShelfPeekAnim; import com.android.quickstep.util.ShelfPeekAnim;
@@ -70,7 +65,6 @@ public abstract class BaseQuickstepLauncher extends Launcher
implements NavigationModeChangeListener { implements NavigationModeChangeListener {
private DepthController mDepthController = new DepthController(this); private DepthController mDepthController = new DepthController(this);
protected SystemActions mSystemActions;
/** /**
* Reusable command for applying the back button alpha on the background thread. * Reusable command for applying the back button alpha on the background thread.
@@ -86,48 +80,8 @@ public abstract class BaseQuickstepLauncher extends Launcher
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
mSystemActions = new SystemActions(this);
SysUINavigationMode.INSTANCE.get(this).addModeChangeListener(this); SysUINavigationMode.INSTANCE.get(this).addModeChangeListener(this);
if (!getSharedPrefs().getBoolean(HOME_BOUNCE_SEEN, false)) {
getStateManager().addStateListener(new LauncherStateManager.StateListener() {
@Override
public void onStateTransitionStart(LauncherState toState) { }
@Override
public void onStateTransitionComplete(LauncherState finalState) {
boolean swipeUpEnabled = SysUINavigationMode.INSTANCE
.get(BaseQuickstepLauncher.this).getMode().hasGestures;
LauncherState prevState = getStateManager().getLastState();
if (((swipeUpEnabled && finalState == OVERVIEW) || (!swipeUpEnabled
&& finalState == ALL_APPS && prevState == NORMAL) || BOUNCE_MAX_COUNT
<= getSharedPrefs().getInt(HOME_BOUNCE_COUNT, 0))) {
getSharedPrefs().edit().putBoolean(HOME_BOUNCE_SEEN, true).apply();
getStateManager().removeStateListener(this);
}
}
});
}
if (!getSharedPrefs().getBoolean(SHELF_BOUNCE_SEEN, false)) {
getStateManager().addStateListener(new LauncherStateManager.StateListener() {
@Override
public void onStateTransitionStart(LauncherState toState) { }
@Override
public void onStateTransitionComplete(LauncherState finalState) {
LauncherState prevState = getStateManager().getLastState();
if ((finalState == ALL_APPS && prevState == OVERVIEW) || BOUNCE_MAX_COUNT
<= getSharedPrefs().getInt(SHELF_BOUNCE_COUNT, 0)) {
getSharedPrefs().edit().putBoolean(SHELF_BOUNCE_SEEN, true).apply();
getStateManager().removeStateListener(this);
}
}
});
}
} }
@Override @Override
@@ -141,12 +95,6 @@ public abstract class BaseQuickstepLauncher extends Launcher
getDragLayer().recreateControllers(); getDragLayer().recreateControllers();
} }
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
mSystemActions.onActivityResult(requestCode);
}
@Override @Override
public void onEnterAnimationComplete() { public void onEnterAnimationComplete() {
super.onEnterAnimationComplete(); super.onEnterAnimationComplete();
@@ -210,15 +158,6 @@ public abstract class BaseQuickstepLauncher extends Launcher
// removes the task itself. // removes the task itself.
startActivity(ProxyActivityStarter.getLaunchIntent(this, null)); startActivity(ProxyActivityStarter.getLaunchIntent(this, null));
} }
// Register all system actions once they are available
mSystemActions.register();
}
@Override
protected void onPause() {
super.onPause();
mSystemActions.unregister();
} }
@Override @Override
@@ -261,6 +200,12 @@ public abstract class BaseQuickstepLauncher extends Launcher
return mDepthController; return mDepthController;
} }
@Override
protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs,
LauncherStateManager stateManager) {
return new QuickstepOnboardingPrefs(this, sharedPrefs, stateManager);
}
@Override @Override
protected ScaleAndTranslation getOverviewScaleAndTranslationForNormalState() { protected ScaleAndTranslation getOverviewScaleAndTranslationForNormalState() {
if (SysUINavigationMode.getMode(this) == Mode.NO_BUTTON) { if (SysUINavigationMode.getMode(this) == Mode.NO_BUTTON) {
@@ -1,90 +0,0 @@
/*
* 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.
*/
package com.android.launcher3.accessibility;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import android.app.PendingIntent;
import android.app.RemoteAction;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.drawable.Icon;
import android.view.accessibility.AccessibilityManager;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
/**
* Manages the launcher system actions presented to accessibility services.
*/
public class SystemActions {
/**
* System Action ID to show all apps. This ID should follow the ones in
* com.android.systemui.accessibility.SystemActions.
*/
private static final int SYSTEM_ACTION_ID_ALL_APPS = 100;
private Launcher mLauncher;
private AccessibilityManager mAccessibilityManager;
private RemoteAction mAllAppsAction;
private boolean mRegistered;
public SystemActions(Launcher launcher) {
mLauncher = launcher;
mAccessibilityManager = (AccessibilityManager) launcher.getSystemService(
Context.ACCESSIBILITY_SERVICE);
mAllAppsAction = new RemoteAction(
Icon.createWithResource(launcher, R.drawable.ic_apps),
launcher.getString(R.string.all_apps_label),
launcher.getString(R.string.all_apps_label),
launcher.createPendingResult(SYSTEM_ACTION_ID_ALL_APPS, new Intent(),
0 /* flags */));
}
public void register() {
if (mRegistered) {
return;
}
mAccessibilityManager.registerSystemAction(mAllAppsAction, SYSTEM_ACTION_ID_ALL_APPS);
mRegistered = true;
}
public void unregister() {
if (!mRegistered) {
return;
}
mAccessibilityManager.unregisterSystemAction(SYSTEM_ACTION_ID_ALL_APPS);
mRegistered = false;
}
public void onActivityResult(int requestCode) {
if (requestCode == SYSTEM_ACTION_ID_ALL_APPS) {
showAllApps();
}
}
private void showAllApps() {
LauncherStateManager stateManager = mLauncher.getStateManager();
stateManager.goToState(NORMAL);
stateManager.goToState(ALL_APPS);
}
}
@@ -45,8 +45,8 @@ import android.util.Log;
import androidx.annotation.MainThread; import androidx.annotation.MainThread;
import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.popup.RemoteActionShortcut; import com.android.launcher3.popup.RemoteActionShortcut;
import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.MainThreadInitializedObject;
@@ -62,10 +62,13 @@ public abstract class BaseRecentsViewStateController<T extends View>
@Override @Override
public void setState(@NonNull LauncherState state) { public void setState(@NonNull LauncherState state) {
ScaleAndTranslation scaleAndTranslation = state ScaleAndTranslation scaleAndTranslation = state.getOverviewScaleAndTranslation(mLauncher);
.getOverviewScaleAndTranslation(mLauncher); float translationX = scaleAndTranslation.translationX;
if (mRecentsView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
translationX = -translationX;
}
SCALE_PROPERTY.set(mRecentsView, scaleAndTranslation.scale); SCALE_PROPERTY.set(mRecentsView, scaleAndTranslation.scale);
mRecentsView.setTranslationX(scaleAndTranslation.translationX); mRecentsView.setTranslationX(translationX);
mRecentsView.setTranslationY(scaleAndTranslation.translationY); mRecentsView.setTranslationY(scaleAndTranslation.translationY);
getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0); getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0);
@@ -96,9 +99,13 @@ public abstract class BaseRecentsViewStateController<T extends View>
void setStateWithAnimationInternal(@NonNull final LauncherState toState, void setStateWithAnimationInternal(@NonNull final LauncherState toState,
@NonNull StateAnimationConfig config, @NonNull PendingAnimation setter) { @NonNull StateAnimationConfig config, @NonNull PendingAnimation setter) {
ScaleAndTranslation scaleAndTranslation = toState.getOverviewScaleAndTranslation(mLauncher); ScaleAndTranslation scaleAndTranslation = toState.getOverviewScaleAndTranslation(mLauncher);
float translationX = scaleAndTranslation.translationX;
if (mRecentsView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
translationX = -translationX;
}
setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleAndTranslation.scale, setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleAndTranslation.scale,
config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR)); config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR));
setter.setFloat(mRecentsView, VIEW_TRANSLATE_X, scaleAndTranslation.translationX, setter.setFloat(mRecentsView, VIEW_TRANSLATE_X, translationX,
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR)); config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR));
setter.setFloat(mRecentsView, VIEW_TRANSLATE_Y, scaleAndTranslation.translationY, setter.setFloat(mRecentsView, VIEW_TRANSLATE_Y, scaleAndTranslation.translationY,
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR)); config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
@@ -1,48 +0,0 @@
/*
* 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.
*/
package com.android.launcher3.uioverrides;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.content.Context;
import android.os.Bundle;
import android.util.Size;
import android.view.View;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.graphics.LauncherPreviewRenderer;
import com.android.systemui.shared.system.SurfaceViewRequestReceiver;
/** Render preview using surface view. */
public class PreviewSurfaceRenderer {
/** Handle a received surface view request. */
public static void render(Context context, Bundle bundle) {
String gridName = bundle.getString("name");
bundle.remove("name");
if (gridName == null) {
gridName = InvariantDeviceProfile.getCurrentGridName(context);
}
final InvariantDeviceProfile idp = new InvariantDeviceProfile(context, gridName);
MAIN_EXECUTOR.execute(() -> {
View view = new LauncherPreviewRenderer(context, idp).getRenderedView();
new SurfaceViewRequestReceiver().onReceive(context, bundle, view,
new Size(view.getMeasuredWidth(), view.getMeasuredHeight()));
});
}
}
@@ -70,10 +70,10 @@ public interface InputConsumer {
} }
/** /**
* Returns true if the given input consumer is in the hierarchy of this input consumer. * Returns the active input consumer is in the hierarchy of this input consumer.
*/ */
default boolean isInConsumerHierarchy(InputConsumer candidate) { default InputConsumer getActiveConsumerInHierarchy() {
return this == candidate; return this;
} }
/** /**
@@ -96,15 +96,15 @@ public interface InputConsumer {
} }
default String getName() { default String getName() {
String name = ""; StringBuilder name = new StringBuilder();
for (int i = 0; i < NAMES.length; i++) { for (int i = 0; i < NAMES.length; i++) {
if ((getType() & (1 << i)) != 0) { if ((getType() & (1 << i)) != 0) {
if (name.length() > 0) { if (name.length() > 0) {
name += ":"; name.append(":");
} }
name += NAMES[i]; name.append(NAMES[i]);
} }
} }
return name; return name.toString();
} }
} }
@@ -21,7 +21,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import com.android.launcher3.AppInfo; import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.util.InstantAppResolver; import com.android.launcher3.util.InstantAppResolver;
/** /**
@@ -22,6 +22,8 @@ import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_POINTER_DOWN; import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.ACTION_UP; import static android.view.MotionEvent.ACTION_UP;
import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Matrix; import android.graphics.Matrix;
import android.graphics.Point; import android.graphics.Point;
@@ -33,8 +35,8 @@ import android.view.Surface;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.ResourceUtils; import com.android.launcher3.ResourceUtils;
import com.android.launcher3.states.RotationHelper;
import com.android.launcher3.util.DefaultDisplay; import com.android.launcher3.util.DefaultDisplay;
import com.android.quickstep.util.RecentsOrientedState.SurfaceRotation;
import java.io.PrintWriter; import java.io.PrintWriter;
@@ -52,15 +54,30 @@ class OrientationTouchTransformer {
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
private static final int MAX_ORIENTATIONS = 4; private static final int MAX_ORIENTATIONS = 4;
private final Matrix mTmpMatrix = new Matrix();
private final float[] mTmpPoint = new float[2];
private SparseArray<OrientationRectF> mSwipeTouchRegions = new SparseArray<>(MAX_ORIENTATIONS); private SparseArray<OrientationRectF> mSwipeTouchRegions = new SparseArray<>(MAX_ORIENTATIONS);
private final RectF mAssistantLeftRegion = new RectF(); private final RectF mAssistantLeftRegion = new RectF();
private final RectF mAssistantRightRegion = new RectF(); private final RectF mAssistantRightRegion = new RectF();
private int mCurrentRotation; private int mCurrentDisplayRotation;
private boolean mEnableMultipleRegions; private boolean mEnableMultipleRegions;
private Resources mResources; private Resources mResources;
private OrientationRectF mLastRectTouched; private OrientationRectF mLastRectTouched;
private SysUINavigationMode.Mode mMode; private SysUINavigationMode.Mode mMode;
private QuickStepContractInfo mContractInfo; private QuickStepContractInfo mContractInfo;
/**
* Represents if we're currently in a swipe "session" of sorts. If value is -1, then user
* has not tapped on an active nav region. Otherwise it will be the rotation of the display
* when the user first interacted with the active nav bar region.
* The "session" ends when {@link #enableMultipleRegions(boolean, DefaultDisplay.Info)} is
* called - usually from a timeout or if user starts interacting w/ the foreground app.
*
* This is different than {@link #mLastRectTouched} as it can get reset by the system whereas
* the rect is purely used for tracking touch interactions and usually this "session" will
* outlast the touch interaction.
*/
private int mQuickStepStartingRotation = -1; private int mQuickStepStartingRotation = -1;
/** For testability */ /** For testability */
@@ -68,6 +85,7 @@ class OrientationTouchTransformer {
float getWindowCornerRadius(); float getWindowCornerRadius();
} }
OrientationTouchTransformer(Resources resources, SysUINavigationMode.Mode mode, OrientationTouchTransformer(Resources resources, SysUINavigationMode.Mode mode,
QuickStepContractInfo contractInfo) { QuickStepContractInfo contractInfo) {
mResources = resources; mResources = resources;
@@ -92,20 +110,21 @@ class OrientationTouchTransformer {
* @see #enableMultipleRegions(boolean, DefaultDisplay.Info) * @see #enableMultipleRegions(boolean, DefaultDisplay.Info)
*/ */
void createOrAddTouchRegion(DefaultDisplay.Info info) { void createOrAddTouchRegion(DefaultDisplay.Info info) {
mCurrentRotation = info.rotation; mCurrentDisplayRotation = info.rotation;
if (mQuickStepStartingRotation > -1 && mCurrentRotation == mQuickStepStartingRotation) { if (mQuickStepStartingRotation > -1
// Ignore nav bars in other rotations except for the one we started out in && mCurrentDisplayRotation == mQuickStepStartingRotation) {
// User already was swiping and the current screen is same rotation as the starting one
// Remove active nav bars in other rotations except for the one we started out in
resetSwipeRegions(info); resetSwipeRegions(info);
return; return;
} }
OrientationRectF region = mSwipeTouchRegions.get(mCurrentDisplayRotation);
OrientationRectF region = mSwipeTouchRegions.get(mCurrentRotation);
if (region != null) { if (region != null) {
return; return;
} }
if (mEnableMultipleRegions) { if (mEnableMultipleRegions) {
mSwipeTouchRegions.put(mCurrentRotation, createRegionForDisplay(info)); mSwipeTouchRegions.put(mCurrentDisplayRotation, createRegionForDisplay(info));
} else { } else {
resetSwipeRegions(info); resetSwipeRegions(info);
} }
@@ -123,12 +142,6 @@ class OrientationTouchTransformer {
if (!enableMultipleRegions) { if (!enableMultipleRegions) {
mQuickStepStartingRotation = -1; mQuickStepStartingRotation = -1;
resetSwipeRegions(info); resetSwipeRegions(info);
} else {
if (mLastRectTouched != null) {
// mLastRectTouched can be null if gesture type is changed (ex. from settings)
// but nav bar hasn't been interacted with yet.
mQuickStepStartingRotation = mLastRectTouched.mRotation;
}
} }
} }
@@ -140,17 +153,25 @@ class OrientationTouchTransformer {
*/ */
private void resetSwipeRegions(DefaultDisplay.Info region) { private void resetSwipeRegions(DefaultDisplay.Info region) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "clearing all regions except rotation: " + mCurrentRotation); Log.d(TAG, "clearing all regions except rotation: " + mCurrentDisplayRotation);
} }
mCurrentRotation = region.rotation; mCurrentDisplayRotation = region.rotation;
OrientationRectF regionToKeep = mSwipeTouchRegions.get(mCurrentDisplayRotation);
mSwipeTouchRegions.clear(); mSwipeTouchRegions.clear();
mSwipeTouchRegions.put(mCurrentRotation, createRegionForDisplay(region)); mSwipeTouchRegions.put(mCurrentDisplayRotation,
regionToKeep != null ? regionToKeep : createRegionForDisplay(region));
}
private void resetSwipeRegions() {
OrientationRectF regionToKeep = mSwipeTouchRegions.get(mCurrentDisplayRotation);
mSwipeTouchRegions.clear();
mSwipeTouchRegions.put(mCurrentDisplayRotation, regionToKeep);
} }
private OrientationRectF createRegionForDisplay(DefaultDisplay.Info display) { private OrientationRectF createRegionForDisplay(DefaultDisplay.Info display) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "creating rotation region for: " + mCurrentRotation); Log.d(TAG, "creating rotation region for: " + mCurrentDisplayRotation);
} }
Point size = display.realSize; Point size = display.realSize;
@@ -220,6 +241,10 @@ class OrientationTouchTransformer {
} }
} }
int getQuickStepStartingRotation() {
return mQuickStepStartingRotation;
}
public void transform(MotionEvent event) { public void transform(MotionEvent event) {
int eventAction = event.getActionMasked(); int eventAction = event.getActionMasked();
switch (eventAction) { switch (eventAction) {
@@ -252,6 +277,11 @@ class OrientationTouchTransformer {
} }
if (rect.applyTransform(event, false)) { if (rect.applyTransform(event, false)) {
mLastRectTouched = rect; mLastRectTouched = rect;
if (mCurrentDisplayRotation == mLastRectTouched.mRotation) {
// Start a touch session for the default nav region for the display
mQuickStepStartingRotation = mLastRectTouched.mRotation;
resetSwipeRegions();
}
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "set active region: " + rect); Log.d(TAG, "set active region: " + rect);
} }
@@ -304,42 +334,46 @@ class OrientationTouchTransformer {
} }
boolean applyTransform(MotionEvent event, boolean forceTransform) { boolean applyTransform(MotionEvent event, boolean forceTransform) {
// TODO(b/149658423): See if we can use RotationHelper.getRotationMatrix here mTmpMatrix.reset();
MotionEvent tmp = MotionEvent.obtain(event); postDisplayRotation(deltaRotation(mCurrentDisplayRotation, mRotation),
Matrix outMatrix = new Matrix(); mHeight, mWidth, mTmpMatrix);
int delta = RotationHelper.deltaRotation(mCurrentRotation, mRotation); if (forceTransform) {
switch (delta) { if (DEBUG) {
case Surface.ROTATION_0: Log.d(TAG, "Transforming rotation due to forceTransform, "
outMatrix.reset(); + "mCurrentRotation: " + mCurrentDisplayRotation
break; + "mRotation: " + mRotation);
case Surface.ROTATION_90: }
outMatrix.setRotate(270); event.transform(mTmpMatrix);
outMatrix.postTranslate(0, mHeight); return true;
break;
case Surface.ROTATION_180:
outMatrix.setRotate(180);
outMatrix.postTranslate(mHeight, mWidth);
break;
case Surface.ROTATION_270:
outMatrix.setRotate(90);
outMatrix.postTranslate(mWidth, 0);
break;
} }
mTmpPoint[0] = event.getX();
mTmpPoint[1] = event.getY();
mTmpMatrix.mapPoints(mTmpPoint);
tmp.transform(outMatrix);
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "original: " + event.getX() + ", " + event.getY() Log.d(TAG, "original: " + event.getX() + ", " + event.getY()
+ " new: " + tmp.getX() + ", " + tmp.getY() + " new: " + mTmpPoint[0] + ", " + mTmpPoint[1]
+ " rect: " + this + " forceTransform: " + forceTransform + " rect: " + this + " forceTransform: " + forceTransform
+ " contains: " + contains(tmp.getX(), tmp.getY())); + " contains: " + contains(mTmpPoint[0], mTmpPoint[1]));
} }
if (forceTransform || contains(tmp.getX(), tmp.getY())) { if (contains(mTmpPoint[0], mTmpPoint[1])) {
event.transform(outMatrix); event.transform(mTmpMatrix);
tmp.recycle();
return true; return true;
} }
return false; return false;
} }
} }
/**
* @return how many factors {@param newRotation} is rotated 90 degrees clockwise.
* E.g. 1->Rotated by 90 degrees clockwise, 2->Rotated 180 clockwise...
* A value of 0 means no rotation has been applied
*/
@SurfaceRotation
private static int deltaRotation(int oldRotation, int newRotation) {
int delta = newRotation - oldRotation;
if (delta < 0) delta += 4;
return delta;
}
} }
@@ -40,6 +40,7 @@ import com.android.systemui.shared.system.PackageManagerWrapper;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Objects; import java.util.Objects;
import java.util.function.Consumer;
/** /**
* Class to keep track of the current overview component based off user preferences and app updates * Class to keep track of the current overview component based off user preferences and app updates
@@ -57,6 +58,9 @@ public final class OverviewComponentObserver {
private final Intent mMyHomeIntent; private final Intent mMyHomeIntent;
private final Intent mFallbackIntent; private final Intent mFallbackIntent;
private final SparseIntArray mConfigChangesMap = new SparseIntArray(); private final SparseIntArray mConfigChangesMap = new SparseIntArray();
private Consumer<Boolean> mOverviewChangeListener = b -> { };
private String mUpdateRegisteredPackage; private String mUpdateRegisteredPackage;
private BaseActivityInterface mActivityInterface; private BaseActivityInterface mActivityInterface;
private Intent mOverviewIntent; private Intent mOverviewIntent;
@@ -64,10 +68,10 @@ public final class OverviewComponentObserver {
private boolean mIsDefaultHome; private boolean mIsDefaultHome;
private boolean mIsHomeDisabled; private boolean mIsHomeDisabled;
public OverviewComponentObserver(Context context, RecentsAnimationDeviceState deviceState) { public OverviewComponentObserver(Context context, RecentsAnimationDeviceState deviceState) {
mContext = context; mContext = context;
mDeviceState = deviceState; mDeviceState = deviceState;
mCurrentHomeIntent = new Intent(Intent.ACTION_MAIN) mCurrentHomeIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME) .addCategory(Intent.CATEGORY_HOME)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -95,6 +99,13 @@ public final class OverviewComponentObserver {
updateOverviewTargets(); updateOverviewTargets();
} }
/**
* Sets a listener for changes in {@link #isHomeAndOverviewSame()}
*/
public void setOverviewChangeListener(Consumer<Boolean> overviewChangeListener) {
mOverviewChangeListener = overviewChangeListener;
}
public void onSystemUiStateChanged() { public void onSystemUiStateChanged() {
if (mDeviceState.isHomeDisabled() != mIsHomeDisabled) { if (mDeviceState.isHomeDisabled() != mIsHomeDisabled) {
updateOverviewTargets(); updateOverviewTargets();
@@ -159,6 +170,7 @@ public final class OverviewComponentObserver {
ACTION_PACKAGE_REMOVED)); ACTION_PACKAGE_REMOVED));
} }
} }
mOverviewChangeListener.accept(mIsHomeAndOverviewSame);
} }
/** /**
@@ -123,6 +123,17 @@ public class RecentTasksList extends TaskStackChangeListener {
mChangeId++; mChangeId++;
} }
@Override
public void onRecentTaskListUpdated() {
// In some cases immediately after booting, the tasks in the system recent task list may be
// loaded, but not in the active task hierarchy in the system. These tasks are displayed in
// overview, but removing them don't result in a onTaskStackChanged() nor a onTaskRemoved()
// callback (those are for changes to the active tasks), but the task list is still updated,
// so we should also invalidate the change id to ensure we load a new list instead of
// reusing a stale list.
mChangeId++;
}
@Override @Override
public void onTaskRemoved(int taskId) { public void onTaskRemoved(int taskId) {
mTasks = loadTasksInBackground(Integer.MAX_VALUE, false); mTasks = loadTasksInBackground(Integer.MAX_VALUE, false);
@@ -91,9 +91,6 @@ public class RecentsAnimationCallbacks implements
RemoteAnimationTargetCompat[] appTargets, RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets, RemoteAnimationTargetCompat[] wallpaperTargets,
Rect homeContentInsets, Rect minimizedHomeBounds) { Rect homeContentInsets, Rect minimizedHomeBounds) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_START_FROM_RECENTS, "onAnimationStart");
}
RecentsAnimationTargets targets = new RecentsAnimationTargets(appTargets, RecentsAnimationTargets targets = new RecentsAnimationTargets(appTargets,
wallpaperTargets, homeContentInsets, minimizedHomeBounds); wallpaperTargets, homeContentInsets, minimizedHomeBounds);
mController = new RecentsAnimationController(animationController, mController = new RecentsAnimationController(animationController,
@@ -22,13 +22,13 @@ import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.annotation.NonNull;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.Log; import android.util.Log;
import android.view.InputEvent; import android.view.InputEvent;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import androidx.annotation.NonNull;
import androidx.annotation.UiThread; import androidx.annotation.UiThread;
import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.Preconditions;
@@ -17,6 +17,7 @@ package com.android.quickstep;
import static android.content.Intent.ACTION_USER_UNLOCKED; import static android.content.Intent.ACTION_USER_UNLOCKED;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS; import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS; import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
@@ -73,6 +74,8 @@ public class RecentsAnimationDeviceState implements
NavigationModeChangeListener, NavigationModeChangeListener,
DefaultDisplay.DisplayInfoChangeListener { DefaultDisplay.DisplayInfoChangeListener {
private static final String TAG = "RecentsAnimationDeviceState";
private final Context mContext; private final Context mContext;
private final SysUINavigationMode mSysUiNavMode; private final SysUINavigationMode mSysUiNavMode;
private final DefaultDisplay mDefaultDisplay; private final DefaultDisplay mDefaultDisplay;
@@ -95,6 +98,7 @@ public class RecentsAnimationDeviceState implements
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if (ACTION_USER_UNLOCKED.equals(intent.getAction())) { if (ACTION_USER_UNLOCKED.equals(intent.getAction())) {
Log.d(TAG, "User Unlocked Broadcast Received");
mIsUserUnlocked = true; mIsUserUnlocked = true;
notifyUserUnlocked(); notifyUserUnlocked();
} }
@@ -120,7 +124,6 @@ public class RecentsAnimationDeviceState implements
private Runnable mOnDestroyFrozenTaskRunnable; private Runnable mOnDestroyFrozenTaskRunnable;
public RecentsAnimationDeviceState(Context context) { public RecentsAnimationDeviceState(Context context) {
final ContentResolver resolver = context.getContentResolver();
mContext = context; mContext = context;
mSysUiNavMode = SysUINavigationMode.INSTANCE.get(context); mSysUiNavMode = SysUINavigationMode.INSTANCE.get(context);
mDefaultDisplay = DefaultDisplay.INSTANCE.get(context); mDefaultDisplay = DefaultDisplay.INSTANCE.get(context);
@@ -511,8 +514,16 @@ public class RecentsAnimationDeviceState implements
mOrientationTouchTransformer.transform(event); mOrientationTouchTransformer.transform(event);
} }
public void enableMultipleRegions(boolean enable) { void enableMultipleRegions(boolean enable) {
mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo()); mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo());
if (enable) {
UI_HELPER_EXECUTOR.execute(() -> {
int quickStepStartingRotation =
mOrientationTouchTransformer.getQuickStepStartingRotation();
SystemUiProxy.INSTANCE.get(mContext)
.onQuickSwitchToNewTask(quickStepStartingRotation);
});
}
} }
public int getCurrentActiveRotation() { public int getCurrentActiveRotation() {
@@ -334,6 +334,7 @@ public class SystemUiProxy implements ISystemUiProxy {
} }
} }
@Override
public void onQuickSwitchToNewTask(int rotation) { public void onQuickSwitchToNewTask(int rotation) {
if (mSystemUiProxy != null) { if (mSystemUiProxy != null) {
try { try {
@@ -53,9 +53,6 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
@UiThread @UiThread
public RecentsAnimationCallbacks startRecentsAnimation(GestureState gestureState, public RecentsAnimationCallbacks startRecentsAnimation(GestureState gestureState,
Intent intent, RecentsAnimationCallbacks.RecentsAnimationListener listener) { Intent intent, RecentsAnimationCallbacks.RecentsAnimationListener listener) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_START_FROM_RECENTS, "startRecentsAnimation");
}
// Notify if recents animation is still running // Notify if recents animation is still running
if (mController != null) { if (mController != null) {
String msg = "New recents animation started before old animation completed"; String msg = "New recents animation started before old animation completed";
@@ -35,7 +35,7 @@ final class BackGestureTutorialEngagedController extends BackGestureTutorialCont
@Override @Override
void transitToController() { void transitToController() {
super.transitToController(); super.transitToController();
mHandCoachingAnimation.maybeStartLoopedAnimation(mTutorialTypeInfo.get().getTutorialType()); mHandCoachingAnimation.startLoopedAnimation(mTutorialTypeInfo.get().getTutorialType());
} }
@Override @Override
@@ -38,8 +38,6 @@ final class BackGestureTutorialHandAnimation {
private final ImageView mHandCoachingView; private final ImageView mHandCoachingView;
private final AnimatedVectorDrawable mGestureAnimation; private final AnimatedVectorDrawable mGestureAnimation;
private boolean mIsAnimationPlayed = false;
BackGestureTutorialHandAnimation(Context context, View rootView) { BackGestureTutorialHandAnimation(Context context, View rootView) {
mHandCoachingView = rootView.findViewById( mHandCoachingView = rootView.findViewById(
R.id.back_gesture_tutorial_fragment_hand_coaching); R.id.back_gesture_tutorial_fragment_hand_coaching);
@@ -47,20 +45,15 @@ final class BackGestureTutorialHandAnimation {
R.drawable.back_gesture); R.drawable.back_gesture);
} }
boolean isRunning() {
return mGestureAnimation.isRunning();
}
/** /**
* Starts animation if the playground is launched for the first time. * [Re]starts animation for the given tutorial.
*/ */
void maybeStartLoopedAnimation(TutorialType tutorialType) { void startLoopedAnimation(TutorialType tutorialType) {
if (isRunning() || mIsAnimationPlayed) { if (mGestureAnimation.isRunning()) {
return; stop();
} }
mIsAnimationPlayed = true; mGestureAnimation.clearAnimationCallbacks();
clearAnimationCallbacks();
mGestureAnimation.registerAnimationCallback( mGestureAnimation.registerAnimationCallback(
new Animatable2.AnimationCallback() { new Animatable2.AnimationCallback() {
@Override @Override
@@ -78,17 +71,11 @@ final class BackGestureTutorialHandAnimation {
float rotationY = tutorialType == TutorialType.LEFT_EDGE_BACK_NAVIGATION ? 180f : 0f; float rotationY = tutorialType == TutorialType.LEFT_EDGE_BACK_NAVIGATION ? 180f : 0f;
mHandCoachingView.setRotationY(rotationY); mHandCoachingView.setRotationY(rotationY);
mHandCoachingView.setImageDrawable(mGestureAnimation); mHandCoachingView.setImageDrawable(mGestureAnimation);
mHandCoachingView.postDelayed(() -> mGestureAnimation.start(), mHandCoachingView.postDelayed(mGestureAnimation::start, ANIMATION_START_DELAY.toMillis());
ANIMATION_START_DELAY.toMillis());
}
private void clearAnimationCallbacks() {
mGestureAnimation.clearAnimationCallbacks();
} }
void stop() { void stop() {
mIsAnimationPlayed = false; mGestureAnimation.clearAnimationCallbacks();
clearAnimationCallbacks();
mGestureAnimation.stop(); mGestureAnimation.stop();
} }
} }
@@ -23,16 +23,16 @@ import static android.stats.launcher.nano.Launcher.OVERVIEW;
import android.content.Context; import android.content.Context;
import com.android.launcher3.FolderInfo;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogUtils; import com.android.launcher3.logging.StatsLogUtils;
import com.android.launcher3.model.AllAppsList; import com.android.launcher3.model.AllAppsList;
import com.android.launcher3.model.BaseModelUpdateTask; import com.android.launcher3.model.BaseModelUpdateTask;
import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.util.IntSparseArrayMap; import com.android.launcher3.util.IntSparseArrayMap;
import java.util.ArrayList; import java.util.ArrayList;
@@ -0,0 +1,96 @@
/*
* 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.
*/
package com.android.quickstep.util;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import android.content.SharedPreferences;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.LauncherStateManager.StateListener;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.quickstep.SysUINavigationMode;
/**
* Extends {@link OnboardingPrefs} for quickstep-specific onboarding data.
*/
public class QuickstepOnboardingPrefs extends OnboardingPrefs<BaseQuickstepLauncher> {
public QuickstepOnboardingPrefs(BaseQuickstepLauncher launcher, SharedPreferences sharedPrefs,
LauncherStateManager stateManager) {
super(launcher, sharedPrefs, stateManager);
if (!getBoolean(HOME_BOUNCE_SEEN)) {
mStateManager.addStateListener(new StateListener() {
@Override
public void onStateTransitionStart(LauncherState toState) { }
@Override
public void onStateTransitionComplete(LauncherState finalState) {
boolean swipeUpEnabled = SysUINavigationMode.INSTANCE
.get(mLauncher).getMode().hasGestures;
LauncherState prevState = mStateManager.getLastState();
if (((swipeUpEnabled && finalState == OVERVIEW) || (!swipeUpEnabled
&& finalState == ALL_APPS && prevState == NORMAL) ||
hasReachedMaxCount(HOME_BOUNCE_COUNT))) {
mSharedPrefs.edit().putBoolean(HOME_BOUNCE_SEEN, true).apply();
mStateManager.removeStateListener(this);
}
}
});
}
if (!getBoolean(SHELF_BOUNCE_SEEN)) {
mStateManager.addStateListener(new StateListener() {
@Override
public void onStateTransitionStart(LauncherState toState) { }
@Override
public void onStateTransitionComplete(LauncherState finalState) {
LauncherState prevState = mStateManager.getLastState();
if ((finalState == ALL_APPS && prevState == OVERVIEW) ||
hasReachedMaxCount(SHELF_BOUNCE_COUNT)) {
mSharedPrefs.edit().putBoolean(SHELF_BOUNCE_SEEN, true).apply();
mStateManager.removeStateListener(this);
}
}
});
}
if (!hasReachedMaxCount(ALL_APPS_COUNT)) {
mStateManager.addStateListener(new StateListener() {
@Override
public void onStateTransitionStart(LauncherState toState) { }
@Override
public void onStateTransitionComplete(LauncherState finalState) {
if (finalState == ALL_APPS) {
if (incrementEventCount(ALL_APPS_COUNT)) {
mStateManager.removeStateListener(this);
mLauncher.getScrimView().updateDragHandleVisibility();
}
}
}
});
}
}
}
@@ -0,0 +1,217 @@
/*
* 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.
*/
package com.android.quickstep.util;
import static android.hardware.camera2.params.OutputConfiguration.ROTATION_180;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.view.MotionEvent;
import android.view.Surface;
import androidx.annotation.IntDef;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.touch.PortraitPagedViewHandler;
import java.lang.annotation.Retention;
/**
* Container to hold orientation/rotation related information for Launcher.
* This is not meant to be an abstraction layer for applying different functionality between
* the different orientation/rotations. For that see {@link PagedOrientationHandler}
*
* This class has initial default state assuming the device and foreground app have
* no ({@link Surface#ROTATION_0} rotation.
*/
public final class RecentsOrientedState {
@Retention(SOURCE)
@IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
public @interface SurfaceRotation {}
private PagedOrientationHandler mOrientationHandler = PagedOrientationHandler.PORTRAIT;
private @SurfaceRotation int mTouchRotation = ROTATION_0;
private @SurfaceRotation int mDisplayRotation = ROTATION_0;
/**
* If {@code true} we default to {@link PortraitPagedViewHandler} and don't support any fake
* launcher orientations.
*/
private boolean mDisableMultipleOrientations;
private final Matrix mTmpMatrix = new Matrix();
private final Matrix mTmpInverseMatrix = new Matrix();
/**
* Sets the appropriate {@link PagedOrientationHandler} for {@link #mOrientationHandler}
* @param touchRotation The rotation the nav bar region that is touched is in
* @param displayRotation Rotation of the display/device
*
* @return true if there was any change in the internal state as a result of this call,
* false otherwise
*/
public boolean update(
@SurfaceRotation int touchRotation, @SurfaceRotation int displayRotation) {
if (!FeatureFlags.ENABLE_FIXED_ROTATION_TRANSFORM.get()) {
return false;
}
if (mDisableMultipleOrientations) {
return false;
}
if (mDisplayRotation == displayRotation && mTouchRotation == touchRotation) {
return false;
}
mDisplayRotation = displayRotation;
mTouchRotation = touchRotation;
if (mTouchRotation == ROTATION_90) {
mOrientationHandler = PagedOrientationHandler.LANDSCAPE;
} else if (mTouchRotation == ROTATION_270) {
mOrientationHandler = PagedOrientationHandler.SEASCAPE;
} else {
mOrientationHandler = PagedOrientationHandler.PORTRAIT;
}
return true;
}
public boolean areMultipleLayoutOrientationsDisabled() {
return mDisableMultipleOrientations;
}
/**
* Setting this preference will render future calls to {@link #update(int, int)} as a no-op.
*/
public void disableMultipleOrientations(boolean disable) {
mDisableMultipleOrientations = disable;
if (disable) {
mDisplayRotation = mTouchRotation = ROTATION_0;
mOrientationHandler = PagedOrientationHandler.PORTRAIT;
}
}
@SurfaceRotation
public int getDisplayRotation() {
return mDisplayRotation;
}
@SurfaceRotation
public int getTouchRotation() {
return mTouchRotation;
}
public int getTouchRotationDegrees() {
switch (mTouchRotation) {
case ROTATION_90:
return 90;
case ROTATION_180:
return 180;
case ROTATION_270:
return 270;
case ROTATION_0:
default:
return 0;
}
}
public PagedOrientationHandler getOrientationHandler() {
return mOrientationHandler;
}
/**
* For landscape, since the navbar is already in a vertical position, we don't have to do any
* rotations as the change in Y coordinate is what is read. We only flip the sign of the
* y coordinate to make it match existing behavior of swipe to the top to go previous
*/
public void flipVertical(MotionEvent ev) {
mTmpMatrix.setScale(1, -1);
ev.transform(mTmpMatrix);
}
/**
* Creates a matrix to transform the given motion event specified by degrees.
* If inverse is {@code true}, the inverse of that matrix will be applied
*/
public void transformEvent(float degrees, MotionEvent ev, boolean inverse) {
mTmpMatrix.setRotate(inverse ? -degrees : degrees);
ev.transform(mTmpMatrix);
// TODO: Add scaling back in based on degrees
/*
if (getWidth() > 0 && getHeight() > 0) {
float scale = ((float) getWidth()) / getHeight();
transform.postScale(scale, 1 / scale);
}
*/
}
public void mapRectFromNormalOrientation(RectF src, int screenWidth, int screenHeight) {
mTmpMatrix.reset();
postDisplayRotation(mDisplayRotation, screenWidth, screenHeight, mTmpMatrix);
mTmpMatrix.mapRect(src);
}
public void mapInverseRectFromNormalOrientation(RectF src, int screenWidth, int screenHeight) {
mTmpMatrix.reset();
postDisplayRotation(mDisplayRotation, screenWidth, screenHeight, mTmpMatrix);
mTmpMatrix.invert(mTmpInverseMatrix);
mTmpInverseMatrix.mapRect(src);
}
@SurfaceRotation
public static int getRotationForUserDegreesRotated(float degrees) {
int threshold = 70;
if (degrees >= (360 - threshold) || degrees < (threshold)) {
return ROTATION_0;
} else if (degrees < (90 + threshold)) {
return ROTATION_270;
} else if (degrees < 180 + threshold) {
return ROTATION_180;
} else {
return ROTATION_90;
}
}
/**
* Posts the transformation on the matrix representing the provided display rotation
*/
public static void postDisplayRotation(@SurfaceRotation int displayRotation,
float screenWidth, float screenHeight, Matrix out) {
switch (displayRotation) {
case ROTATION_0:
return;
case ROTATION_90:
out.postRotate(270);
out.postTranslate(0, screenWidth);
break;
case ROTATION_180:
out.postRotate(180);
out.postTranslate(screenHeight, screenWidth);
break;
case ROTATION_270:
out.postRotate(90);
out.postTranslate(screenHeight, 0);
break;
}
}
}
@@ -43,6 +43,7 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.uioverrides.states.OverviewState; import com.android.launcher3.uioverrides.states.OverviewState;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.Themes; import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ScrimView; import com.android.launcher3.views.ScrimView;
import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode;
@@ -75,6 +76,7 @@ public class ShelfScrimView extends ScrimView<BaseQuickstepLauncher>
private final float mRadius; private final float mRadius;
private final int mMaxScrimAlpha; private final int mMaxScrimAlpha;
private final Paint mPaint; private final Paint mPaint;
private final OnboardingPrefs mOnboardingPrefs;
// Mid point where the alpha changes // Mid point where the alpha changes
private int mMidAlpha; private int mMidAlpha;
@@ -100,6 +102,7 @@ public class ShelfScrimView extends ScrimView<BaseQuickstepLauncher>
private boolean mRemainingScreenPathValid = false; private boolean mRemainingScreenPathValid = false;
private Mode mSysUINavigationMode; private Mode mSysUINavigationMode;
private boolean mIsTwoZoneSwipeModel;
public ShelfScrimView(Context context, AttributeSet attrs) { public ShelfScrimView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
@@ -108,6 +111,7 @@ public class ShelfScrimView extends ScrimView<BaseQuickstepLauncher>
mEndAlpha = Color.alpha(mEndScrim); mEndAlpha = Color.alpha(mEndScrim);
mRadius = BOTTOM_CORNER_RADIUS_RATIO * Themes.getDialogCornerRadius(context); mRadius = BOTTOM_CORNER_RADIUS_RATIO * Themes.getDialogCornerRadius(context);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mOnboardingPrefs = mLauncher.getOnboardingPrefs();
// Just assume the easiest UI for now, until we have the proper layout information. // Just assume the easiest UI for now, until we have the proper layout information.
mDrawingFlatColor = true; mDrawingFlatColor = true;
@@ -140,9 +144,11 @@ public class ShelfScrimView extends ScrimView<BaseQuickstepLauncher>
// Show the shelf more quickly before reaching overview progress. // Show the shelf more quickly before reaching overview progress.
mBeforeMidProgressColorInterpolator = ACCEL_2; mBeforeMidProgressColorInterpolator = ACCEL_2;
mAfterMidProgressColorInterpolator = ACCEL; mAfterMidProgressColorInterpolator = ACCEL;
mIsTwoZoneSwipeModel = FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get();
} else { } else {
mBeforeMidProgressColorInterpolator = ACCEL; mBeforeMidProgressColorInterpolator = ACCEL;
mAfterMidProgressColorInterpolator = Interpolators.clampToProgress(ACCEL, 0.5f, 1f); mAfterMidProgressColorInterpolator = Interpolators.clampToProgress(ACCEL, 0.5f, 1f);
mIsTwoZoneSwipeModel = false;
} }
} }
@@ -236,9 +242,9 @@ public class ShelfScrimView extends ScrimView<BaseQuickstepLauncher>
@Override @Override
protected boolean shouldDragHandleBeVisible() { protected boolean shouldDragHandleBeVisible() {
boolean twoZoneSwipeModel = FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() boolean needsAllAppsEdu = mIsTwoZoneSwipeModel
&& SysUINavigationMode.removeShelfFromOverview(mLauncher); && !mOnboardingPrefs.hasReachedMaxCount(OnboardingPrefs.ALL_APPS_COUNT);
return twoZoneSwipeModel || super.shouldDragHandleBeVisible(); return needsAllAppsEdu || super.shouldDragHandleBeVisible();
} }
@Override @Override
@@ -48,9 +48,9 @@ import androidx.test.uiautomator.By;
import androidx.test.uiautomator.UiDevice; import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.Until; import androidx.test.uiautomator.Until;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.tapl.Background; import com.android.launcher3.tapl.Background;
import com.android.launcher3.testcomponent.ListViewService; import com.android.launcher3.testcomponent.ListViewService;
import com.android.launcher3.testcomponent.ListViewService.SimpleViewsFactory; import com.android.launcher3.testcomponent.ListViewService.SimpleViewsFactory;
+1 -1
View File
@@ -20,7 +20,7 @@
android:gravity="center"> android:gravity="center">
<TextView <TextView
style="@style/PrimaryMediumText" style="@style/PrimaryHeadline"
android:textColor="?attr/workProfileOverlayTextColor" android:textColor="?attr/workProfileOverlayTextColor"
android:id="@+id/work_apps_paused_title" android:id="@+id/work_apps_paused_title"
android:layout_width="wrap_content" android:layout_width="wrap_content"
+8
View File
@@ -118,6 +118,8 @@
<!-- numHotseatIcons defaults to numColumns, if not specified --> <!-- numHotseatIcons defaults to numColumns, if not specified -->
<attr name="numHotseatIcons" format="integer" /> <attr name="numHotseatIcons" format="integer" />
<attr name="dbFile" format="string" /> <attr name="dbFile" format="string" />
<!-- numAllAppsColumns defaults to numColumns, if not specified -->
<attr name="numAllAppsColumns" format="integer" />
<attr name="defaultLayoutId" format="reference" /> <attr name="defaultLayoutId" format="reference" />
<attr name="demoModeLayoutId" format="reference" /> <attr name="demoModeLayoutId" format="reference" />
</declare-styleable> </declare-styleable>
@@ -133,6 +135,12 @@
<attr name="iconTextSize" format="float" /> <attr name="iconTextSize" format="float" />
<!-- If true, this display option is used to determine the default grid --> <!-- If true, this display option is used to determine the default grid -->
<attr name="canBeDefault" format="boolean" /> <attr name="canBeDefault" format="boolean" />
<!-- The following values are only enabled if grid is supported. -->
<!-- allAppsIconSize defaults to iconSize, if not specified -->
<attr name="allAppsIconSize" format="float" />
<!-- allAppsIconTextSize defaults to iconTextSize, if not specified -->
<attr name="allAppsIconTextSize" format="float" />
</declare-styleable> </declare-styleable>
<declare-styleable name="CellLayout"> <declare-styleable name="CellLayout">
+2 -2
View File
@@ -131,8 +131,8 @@
<item name="dismiss_task_trans_x_damping_ratio" type="dimen" format="float">0.5</item> <item name="dismiss_task_trans_x_damping_ratio" type="dimen" format="float">0.5</item>
<item name="dismiss_task_trans_x_stiffness" type="dimen" format="float">1500</item> <item name="dismiss_task_trans_x_stiffness" type="dimen" format="float">1500</item>
<item name="horizontal_spring_damping_ratio" type="dimen" format="float">0.75</item> <item name="horizontal_spring_damping_ratio" type="dimen" format="float">0.8</item>
<item name="horizontal_spring_stiffness" type="dimen" format="float">200</item> <item name="horizontal_spring_stiffness" type="dimen" format="float">400</item>
<item name="swipe_up_rect_scale_damping_ratio" type="dimen" format="float">0.75</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_scale_stiffness" type="dimen" format="float">200</item>
+4
View File
@@ -343,6 +343,10 @@
<string name="work_apps_paused_title">Work profile is paused</string> <string name="work_apps_paused_title">Work profile is paused</string>
<!--- body shown when user opens work apps tab while work apps are paused --> <!--- body shown when user opens work apps tab while work apps are paused -->
<string name="work_apps_paused_body">Work apps can\t send you notifications, use your battery, or access your location</string> <string name="work_apps_paused_body">Work apps can\t send you notifications, use your battery, or access your location</string>
<!-- content description for paused work apps list -->
<string name="work_apps_paused_content_description">Work profile is paused. Work apps can\t send you notifications, use your battery, or access your location</string>
<!-- A tip shown pointing at work toggle --> <!-- A tip shown pointing at work toggle -->
<string name="work_switch_tip">Pause work apps and notifications</string> <string name="work_switch_tip">Pause work apps and notifications</string>
+3
View File
@@ -226,6 +226,9 @@
<style name="TextHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle" /> <style name="TextHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle" />
<style name="PrimaryMediumText" parent="@android:style/TextAppearance.DeviceDefault.Medium"/> <style name="PrimaryMediumText" parent="@android:style/TextAppearance.DeviceDefault.Medium"/>
<style name="PrimaryHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle">
<item name="android:textStyle">bold</item>
</style>
<style name="TextTitle" parent="@android:style/TextAppearance.DeviceDefault" /> <style name="TextTitle" parent="@android:style/TextAppearance.DeviceDefault" />
+2 -2
View File
@@ -21,7 +21,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := LauncherRoboTests LOCAL_MODULE := LauncherRoboTests
LOCAL_MODULE_CLASS := JAVA_LIBRARIES LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_SDK_VERSION := current LOCAL_SDK_VERSION := system_current
LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := \ LOCAL_STATIC_JAVA_LIBRARIES := \
androidx.test.runner \ androidx.test.runner \
@@ -47,7 +47,7 @@ include $(BUILD_STATIC_JAVA_LIBRARY)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := RunLauncherRoboTests LOCAL_MODULE := RunLauncherRoboTests
LOCAL_SDK_VERSION := current LOCAL_SDK_VERSION := system_current
LOCAL_JAVA_LIBRARIES := LauncherRoboTests LOCAL_JAVA_LIBRARIES := LauncherRoboTests
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
@@ -1 +1,17 @@
sdk=29 sdk=29
shadows= \
com.android.launcher3.shadows.LShadowAppPredictionManager \
com.android.launcher3.shadows.LShadowAppWidgetManager \
com.android.launcher3.shadows.LShadowBackupManager \
com.android.launcher3.shadows.LShadowBitmap \
com.android.launcher3.shadows.LShadowLauncherApps \
com.android.launcher3.shadows.LShadowTypeface \
com.android.launcher3.shadows.LShadowUserManager \
com.android.launcher3.shadows.LShadowWallpaperManager \
com.android.launcher3.shadows.ShadowDeviceFlag \
com.android.launcher3.shadows.ShadowLooperExecutor \
com.android.launcher3.shadows.ShadowMainThreadInitializedObject \
com.android.launcher3.shadows.ShadowOverrides \
com.android.launcher3.shadows.ShadowSyncRtSurfaceTransactionApplierCompat \
application=com.android.launcher3.util.LauncherTestApplication
@@ -1,6 +1,6 @@
# Model data used by CacheDataUpdatedTaskTest # Model data used by CacheDataUpdatedTaskTest
classMap s com.android.launcher3.WorkspaceItemInfo classMap s com.android.launcher3.model.data.WorkspaceItemInfo
# Items for the BgDataModel # Items for the BgDataModel
@@ -1,7 +1,7 @@
# Model data used by PackageInstallStateChangeTaskTest # Model data used by PackageInstallStateChangeTaskTest
classMap s com.android.launcher3.WorkspaceItemInfo classMap s com.android.launcher3.model.data.WorkspaceItemInfo
classMap w com.android.launcher3.LauncherAppWidgetInfo classMap w com.android.launcher3.model.data.LauncherAppWidgetInfo
# Items for the BgDataModel # Items for the BgDataModel
@@ -20,20 +20,20 @@ import static org.junit.Assert.assertEquals;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.UserHandle;
import com.android.launcher3.AppInfo; import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shadows.LShadowUserManager;
import com.android.launcher3.util.LauncherRoboTestRunner;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList; import java.util.ArrayList;
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
public final class FolderNameProviderTest { public final class FolderNameProviderTest {
private Context mContext; private Context mContext;
private WorkspaceItemInfo mItem1; private WorkspaceItemInfo mItem1;
@@ -45,13 +45,13 @@ public final class FolderNameProviderTest {
mItem1 = new WorkspaceItemInfo(new AppInfo( mItem1 = new WorkspaceItemInfo(new AppInfo(
new ComponentName("a.b.c", "a.b.c/a.b.c.d"), new ComponentName("a.b.c", "a.b.c/a.b.c.d"),
"title1", "title1",
LShadowUserManager.newUserHandle(10), UserHandle.of(10),
new Intent().setComponent(new ComponentName("a.b.c", "a.b.c/a.b.c.d")) new Intent().setComponent(new ComponentName("a.b.c", "a.b.c/a.b.c.d"))
)); ));
mItem2 = new WorkspaceItemInfo(new AppInfo( mItem2 = new WorkspaceItemInfo(new AppInfo(
new ComponentName("a.b.c", "a.b.c/a.b.c.d"), new ComponentName("a.b.c", "a.b.c/a.b.c.d"),
"title2", "title2",
LShadowUserManager.newUserHandle(10), UserHandle.of(10),
new Intent().setComponent(new ComponentName("a.b.c", "a.b.c/a.b.c.d")) new Intent().setComponent(new ComponentName("a.b.c", "a.b.c/a.b.c.d"))
)); ));
} }
@@ -3,12 +3,11 @@ package com.android.launcher3.logging;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import com.android.launcher3.util.LauncherRoboTestRunner;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows; import org.robolectric.Shadows;
import org.robolectric.util.Scheduler; import org.robolectric.util.Scheduler;
@@ -21,7 +20,7 @@ import java.util.Calendar;
/** /**
* Tests for {@link FileLog} * Tests for {@link FileLog}
*/ */
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class FileLogTest { public class FileLogTest {
private File mTempDir; private File mTempDir;
@@ -14,23 +14,23 @@ import android.graphics.Rect;
import android.util.Pair; import android.util.Pair;
import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.util.ContentWriter; import com.android.launcher3.util.ContentWriter;
import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSparseArrayMap; import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.LauncherModelHelper; import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.util.LauncherRoboTestRunner;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.LooperMode; import org.robolectric.annotation.LooperMode;
import org.robolectric.annotation.LooperMode.Mode; import org.robolectric.annotation.LooperMode.Mode;
@@ -41,7 +41,7 @@ import java.util.List;
/** /**
* Tests for {@link AddWorkspaceItemsTask} * Tests for {@link AddWorkspaceItemsTask}
*/ */
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
@LooperMode(Mode.PAUSED) @LooperMode(Mode.PAUSED)
public class AddWorkspaceItemsTaskTest { public class AddWorkspaceItemsTaskTest {
@@ -43,11 +43,11 @@ import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.shadows.LShadowBackupManager; import com.android.launcher3.shadows.LShadowBackupManager;
import com.android.launcher3.shadows.LShadowUserManager; import com.android.launcher3.shadows.LShadowUserManager;
import com.android.launcher3.util.LauncherModelHelper; import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.util.LauncherRoboTestRunner;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.LooperMode; import org.robolectric.annotation.LooperMode;
import org.robolectric.shadow.api.Shadow; import org.robolectric.shadow.api.Shadow;
@@ -55,7 +55,7 @@ import org.robolectric.shadow.api.Shadow;
/** /**
* Tests to verify backup and restore flow. * Tests to verify backup and restore flow.
*/ */
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
@LooperMode(LooperMode.Mode.PAUSED) @LooperMode(LooperMode.Mode.PAUSED)
public class BackupRestoreTest { public class BackupRestoreTest {
@@ -17,19 +17,19 @@ import android.os.UserManager;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.android.launcher3.AppInfo;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppState;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.IconCache;
import com.android.launcher3.icons.cache.CachingLogic; import com.android.launcher3.icons.cache.CachingLogic;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.util.LauncherModelHelper; import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.util.LauncherRoboTestRunner;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.LooperMode; import org.robolectric.annotation.LooperMode;
import org.robolectric.annotation.LooperMode.Mode; import org.robolectric.annotation.LooperMode.Mode;
@@ -40,7 +40,7 @@ import java.util.HashSet;
/** /**
* Tests for {@link CacheDataUpdatedTask} * Tests for {@link CacheDataUpdatedTask}
*/ */
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
@LooperMode(Mode.PAUSED) @LooperMode(Mode.PAUSED)
public class CacheDataUpdatedTaskTest { public class CacheDataUpdatedTaskTest {
@@ -36,11 +36,11 @@ import com.android.launcher3.LauncherProvider;
import com.android.launcher3.LauncherProvider.DatabaseHelper; import com.android.launcher3.LauncherProvider.DatabaseHelper;
import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.util.LauncherRoboTestRunner;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import java.io.File; import java.io.File;
@@ -48,7 +48,7 @@ import java.io.File;
/** /**
* Tests for {@link DbDowngradeHelper} * Tests for {@link DbDowngradeHelper}
*/ */
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class DbDowngradeHelperTest { public class DbDowngradeHelperTest {
private static final String SCHEMA_FILE = "test_schema.json"; private static final String SCHEMA_FILE = "test_schema.json";
@@ -28,17 +28,17 @@ import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageInstaller.SessionParams;
import com.android.launcher3.FolderInfo;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings;
import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.LauncherLayoutBuilder; import com.android.launcher3.util.LauncherLayoutBuilder;
import com.android.launcher3.util.LauncherModelHelper; import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.util.LauncherRoboTestRunner;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.LooperMode; import org.robolectric.annotation.LooperMode;
import org.robolectric.annotation.LooperMode.Mode; import org.robolectric.annotation.LooperMode.Mode;
@@ -46,7 +46,7 @@ import org.robolectric.annotation.LooperMode.Mode;
/** /**
* Tests for layout parser for remote layout * Tests for layout parser for remote layout
*/ */
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
@LooperMode(Mode.PAUSED) @LooperMode(Mode.PAUSED)
public class DefaultLayoutProviderTest { public class DefaultLayoutProviderTest {
@@ -23,17 +23,17 @@ import android.graphics.Point;
import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.LauncherSettings.Settings; import com.android.launcher3.LauncherSettings.Settings;
import com.android.launcher3.util.LauncherModelHelper; import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.util.LauncherRoboTestRunner;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
/** /**
* Unit tests for {@link GridBackupTable} * Unit tests for {@link GridBackupTable}
*/ */
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class GridBackupTableTest { public class GridBackupTableTest {
private static final int BACKUP_ITEM_COUNT = 12; private static final int BACKUP_ITEM_COUNT = 12;
@@ -20,11 +20,11 @@ import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.GridSizeMigrationTask.MultiStepMigrationTask; import com.android.launcher3.model.GridSizeMigrationTask.MultiStepMigrationTask;
import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.LauncherModelHelper; import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.util.LauncherRoboTestRunner;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import java.util.HashSet; import java.util.HashSet;
@@ -33,7 +33,7 @@ import java.util.LinkedList;
/** /**
* Unit tests for {@link GridSizeMigrationTask} * Unit tests for {@link GridSizeMigrationTask}
*/ */
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class GridSizeMigrationTaskTest { public class GridSizeMigrationTaskTest {
private LauncherModelHelper mModelHelper; private LauncherModelHelper mModelHelper;
@@ -39,17 +39,17 @@ import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings;
import com.android.launcher3.pm.UserCache; import com.android.launcher3.pm.UserCache;
import com.android.launcher3.util.LauncherModelHelper; import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.util.LauncherRoboTestRunner;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import java.util.HashSet; import java.util.HashSet;
/** Unit tests for {@link GridSizeMigrationTaskV2} */ /** Unit tests for {@link GridSizeMigrationTaskV2} */
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class GridSizeMigrationTaskV2Test { public class GridSizeMigrationTaskV2Test {
private LauncherModelHelper mModelHelper; private LauncherModelHelper mModelHelper;
@@ -50,17 +50,17 @@ import android.database.MatrixCursor;
import android.os.Process; import android.os.Process;
import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings;
import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.util.Executors; import com.android.launcher3.util.Executors;
import com.android.launcher3.util.LauncherRoboTestRunner;
import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PackageManagerHelper;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.LooperMode; import org.robolectric.annotation.LooperMode;
import org.robolectric.annotation.LooperMode.Mode; import org.robolectric.annotation.LooperMode.Mode;
@@ -68,7 +68,7 @@ import org.robolectric.annotation.LooperMode.Mode;
/** /**
* Tests for {@link LoaderCursor} * Tests for {@link LoaderCursor}
*/ */
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
@LooperMode(Mode.PAUSED) @LooperMode(Mode.PAUSED)
public class LoaderCursorTest { public class LoaderCursorTest {
@@ -127,7 +127,7 @@ public class LoaderCursorTest {
new Intent().setComponent(cn), false /* allowMissingTarget */, true)) new Intent().setComponent(cn), false /* allowMissingTarget */, true))
.get(); .get();
assertNotNull(info); assertNotNull(info);
assertTrue(PackageManagerHelper.isLauncherAppTarget(info.intent)); assertTrue(PackageManagerHelper.isLauncherAppTarget(info.getIntent()));
} }
@Test @Test
@@ -141,7 +141,7 @@ public class LoaderCursorTest {
new Intent().setComponent(cn), true /* allowMissingTarget */, true)) new Intent().setComponent(cn), true /* allowMissingTarget */, true))
.get(); .get();
assertNotNull(info); assertNotNull(info);
assertTrue(PackageManagerHelper.isLauncherAppTarget(info.intent)); assertTrue(PackageManagerHelper.isLauncherAppTarget(info.getIntent()));
} }
@Test @Test
@@ -26,20 +26,20 @@ import static org.robolectric.Shadows.shadowOf;
import android.os.Process; import android.os.Process;
import com.android.launcher3.AppInfo;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.PagedView; import com.android.launcher3.PagedView;
import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.Executors; import com.android.launcher3.util.Executors;
import com.android.launcher3.util.LauncherLayoutBuilder; import com.android.launcher3.util.LauncherLayoutBuilder;
import com.android.launcher3.util.LauncherModelHelper; import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.util.LauncherRoboTestRunner;
import com.android.launcher3.util.LooperExecutor; import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.ViewOnDrawExecutor; import com.android.launcher3.util.ViewOnDrawExecutor;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.LooperMode; import org.robolectric.annotation.LooperMode;
import org.robolectric.annotation.LooperMode.Mode; import org.robolectric.annotation.LooperMode.Mode;
@@ -55,7 +55,7 @@ import java.util.stream.Collectors;
/** /**
* Tests to verify multiple callbacks in Loader * Tests to verify multiple callbacks in Loader
*/ */
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
@LooperMode(Mode.PAUSED) @LooperMode(Mode.PAUSED)
public class ModelMultiCallbacksTest { public class ModelMultiCallbacksTest {
@@ -2,16 +2,16 @@ package com.android.launcher3.model;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import com.android.launcher3.ItemInfo; import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.util.LauncherModelHelper; import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.util.LauncherRoboTestRunner;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.LooperMode; import org.robolectric.annotation.LooperMode;
import org.robolectric.annotation.LooperMode.Mode; import org.robolectric.annotation.LooperMode.Mode;
@@ -21,7 +21,7 @@ import java.util.HashSet;
/** /**
* Tests for {@link PackageInstallStateChangedTask} * Tests for {@link PackageInstallStateChangedTask}
*/ */
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
@LooperMode(Mode.PAUSED) @LooperMode(Mode.PAUSED)
public class PackageInstallStateChangedTaskTest { public class PackageInstallStateChangedTaskTest {
@@ -27,10 +27,9 @@ import static org.mockito.Mockito.spy;
import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutInfo;
import com.android.launcher3.util.LauncherRoboTestRunner;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList; import java.util.ArrayList;
@@ -40,7 +39,7 @@ import java.util.List;
/** /**
* Tests the sorting and filtering of shortcuts in {@link PopupPopulator}. * Tests the sorting and filtering of shortcuts in {@link PopupPopulator}.
*/ */
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class PopupPopulatorTest { public class PopupPopulatorTest {
@Test @Test
@@ -23,16 +23,16 @@ import android.database.sqlite.SQLiteDatabase;
import com.android.launcher3.LauncherProvider.DatabaseHelper; import com.android.launcher3.LauncherProvider.DatabaseHelper;
import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.util.LauncherRoboTestRunner;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
/** /**
* Tests for {@link RestoreDbTask} * Tests for {@link RestoreDbTask}
*/ */
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class RestoreDbTaskTest { public class RestoreDbTaskTest {
@Test @Test
@@ -0,0 +1,38 @@
/*
* 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.
*/
package com.android.launcher3.shadows;
import static org.mockito.Mockito.mock;
import android.app.prediction.AppPredictionContext;
import android.app.prediction.AppPredictionManager;
import android.app.prediction.AppPredictor;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
/**
* Shadow for {@link AppPredictionManager} which create mock predictors
*/
@Implements(value = AppPredictionManager.class)
public class LShadowAppPredictionManager {
@Implementation
public AppPredictor createAppPredictionSession(AppPredictionContext predictionContext) {
return mock(AppPredictor.class);
}
}
@@ -16,7 +16,6 @@
package com.android.launcher3.shadows; package com.android.launcher3.shadows;
import android.os.Parcel;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import android.util.SparseBooleanArray; import android.util.SparseBooleanArray;
@@ -51,12 +50,4 @@ public class LShadowUserManager extends ShadowUserManager {
public void setUserLocked(UserHandle userHandle, boolean enabled) { public void setUserLocked(UserHandle userHandle, boolean enabled) {
mLockedUsers.put(userHandle.hashCode(), enabled); mLockedUsers.put(userHandle.hashCode(), enabled);
} }
// Create user handle from parcel since UserHandle.of() was only added in later APIs.
public static UserHandle newUserHandle(int uid) {
Parcel userParcel = Parcel.obtain();
userParcel.writeInt(uid);
userParcel.setDataPosition(0);
return new UserHandle(userParcel);
}
} }
@@ -0,0 +1,42 @@
/*
* 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.
*/
package com.android.launcher3.shadows;
import static org.robolectric.shadow.api.Shadow.invokeConstructor;
import static org.robolectric.util.ReflectionHelpers.ClassParameter.from;
import android.view.View;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.RealObject;
/**
* Shadow for SyncRtSurfaceTransactionApplierCompat to override default functionality
*/
@Implements(className = "com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat",
isInAndroidSdk = false)
public class ShadowSyncRtSurfaceTransactionApplierCompat {
@RealObject
private Object mRealObject;
@Implementation
protected void __constructor__(View view) {
invokeConstructor(mRealObject.getClass(), mRealObject, from(View.class, null));
}
}
@@ -14,23 +14,20 @@
* limitations under the License. * limitations under the License.
*/package com.android.launcher3.ui; */package com.android.launcher3.ui;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.makeMeasureSpec;
import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE; import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
import static com.android.launcher3.util.LauncherUIHelper.buildAndBindLauncher;
import static com.android.launcher3.util.LauncherUIHelper.doLayout;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotEquals;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.os.SystemClock; import android.os.SystemClock;
import android.provider.Settings; import android.provider.Settings;
import android.view.InputDevice; import android.view.InputDevice;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.MotionEvent.PointerProperties; import android.view.MotionEvent.PointerProperties;
import android.view.View;
import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.InvariantDeviceProfile;
@@ -44,24 +41,21 @@ import com.android.launcher3.shadows.ShadowOverrides;
import com.android.launcher3.util.LauncherLayoutBuilder; import com.android.launcher3.util.LauncherLayoutBuilder;
import com.android.launcher3.util.LauncherLayoutBuilder.FolderBuilder; import com.android.launcher3.util.LauncherLayoutBuilder.FolderBuilder;
import com.android.launcher3.util.LauncherModelHelper; import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.util.LauncherRoboTestRunner;
import com.android.launcher3.util.ViewOnDrawExecutor;
import com.android.launcher3.widget.WidgetsFullSheet; import com.android.launcher3.widget.WidgetsFullSheet;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.LooperMode; import org.robolectric.annotation.LooperMode;
import org.robolectric.annotation.LooperMode.Mode; import org.robolectric.annotation.LooperMode.Mode;
import org.robolectric.shadows.ShadowLooper; import org.robolectric.shadows.ShadowLooper;
import org.robolectric.util.ReflectionHelpers;
/** /**
* Tests scroll behavior at various Launcher UI components * Tests scroll behavior at various Launcher UI components
*/ */
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
@LooperMode(Mode.PAUSED) @LooperMode(Mode.PAUSED)
public class LauncherUIScrollTest { public class LauncherUIScrollTest {
@@ -166,23 +160,7 @@ public class LauncherUIScrollTest {
private Launcher loadLauncher() throws Exception { private Launcher loadLauncher() throws Exception {
mModelHelper.setupDefaultLayoutProvider(mLayoutBuilder).loadModelSync(); mModelHelper.setupDefaultLayoutProvider(mLayoutBuilder).loadModelSync();
return buildAndBindLauncher();
Launcher launcher = Robolectric.buildActivity(Launcher.class).setup().get();
doLayout(launcher);
ViewOnDrawExecutor executor = ReflectionHelpers.getField(launcher, "mPendingExecutor");
if (executor != null) {
executor.runAllTasks();
}
return launcher;
}
private static void doLayout(Activity activity) {
DeviceProfile dp = InvariantDeviceProfile.INSTANCE
.get(RuntimeEnvironment.application).portraitProfile;
View view = activity.getWindow().getDecorView();
view.measure(makeMeasureSpec(dp.widthPx, EXACTLY), makeMeasureSpec(dp.heightPx, EXACTLY));
view.layout(0, 0, dp.widthPx, dp.heightPx);
ShadowLooper.idleMainLooper();
} }
private static MotionEvent createScrollEvent(int scroll) { private static MotionEvent createScrollEvent(int scroll) {
@@ -1,16 +1,17 @@
package com.android.launcher3.util; package com.android.launcher3.util;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** /**
* Unit tests for {@link GridOccupancy} * Unit tests for {@link GridOccupancy}
*/ */
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class GridOccupancyTest { public class GridOccupancyTest {
@Test @Test
@@ -19,11 +19,12 @@ import static com.google.common.truth.Truth.assertThat;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** /**
* Robolectric unit tests for {@link IntArray} * Robolectric unit tests for {@link IntArray}
*/ */
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class IntArrayTest { public class IntArrayTest {
@Test @Test
@@ -17,17 +17,18 @@ package com.android.launcher3.util;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** /**
* Robolectric unit tests for {@link IntSet} * Robolectric unit tests for {@link IntSet}
*/ */
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class IntSetTest { public class IntSetTest {
@Test @Test
@@ -36,9 +36,7 @@ import android.net.Uri;
import android.os.Process; import android.os.Process;
import android.provider.Settings; import android.provider.Settings;
import com.android.launcher3.AppInfo;
import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherModel.ModelUpdateTask; import com.android.launcher3.LauncherModel.ModelUpdateTask;
@@ -47,6 +45,8 @@ import com.android.launcher3.LauncherSettings;
import com.android.launcher3.model.AllAppsList; import com.android.launcher3.model.AllAppsList;
import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.pm.UserCache; import com.android.launcher3.pm.UserCache;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
@@ -1,101 +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.util;
import static org.mockito.Mockito.mock;
import com.android.launcher3.shadows.LShadowAppWidgetManager;
import com.android.launcher3.shadows.LShadowBackupManager;
import com.android.launcher3.shadows.LShadowBitmap;
import com.android.launcher3.shadows.LShadowLauncherApps;
import com.android.launcher3.shadows.LShadowTypeface;
import com.android.launcher3.shadows.LShadowUserManager;
import com.android.launcher3.shadows.LShadowWallpaperManager;
import com.android.launcher3.shadows.ShadowDeviceFlag;
import com.android.launcher3.shadows.ShadowLooperExecutor;
import com.android.launcher3.shadows.ShadowMainThreadInitializedObject;
import com.android.launcher3.shadows.ShadowOverrides;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import org.junit.runners.model.InitializationError;
import org.robolectric.DefaultTestLifecycle;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.TestLifecycle;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLog;
import java.lang.reflect.Method;
import javax.annotation.Nonnull;
/**
* Test runner with Launcher specific configurations
*/
public class LauncherRoboTestRunner extends RobolectricTestRunner {
private static final Class<?>[] SHADOWS = new Class<?>[] {
LShadowAppWidgetManager.class,
LShadowUserManager.class,
LShadowLauncherApps.class,
LShadowBitmap.class,
LShadowBackupManager.class,
LShadowTypeface.class,
LShadowWallpaperManager.class,
ShadowLooperExecutor.class,
ShadowMainThreadInitializedObject.class,
ShadowDeviceFlag.class,
ShadowOverrides.class
};
public LauncherRoboTestRunner(Class<?> testClass) throws InitializationError {
super(testClass);
}
@Override
protected Config buildGlobalConfig() {
return new Config.Builder().setShadows(SHADOWS).build();
}
@Nonnull
@Override
protected Class<? extends TestLifecycle> getTestLifecycleClass() {
return LauncherTestLifecycle.class;
}
public static class LauncherTestLifecycle extends DefaultTestLifecycle {
@Override
public void beforeTest(Method method) {
super.beforeTest(method);
ShadowLog.stream = System.out;
// Disable plugins
PluginManagerWrapper.INSTANCE.initializeForTesting(mock(PluginManagerWrapper.class));
// Initialize mock wallpaper manager
LShadowWallpaperManager.initializeMock();
}
@Override
public void afterTest(Method method) {
super.afterTest(method);
ShadowLog.stream = null;
ShadowMainThreadInitializedObject.resetInitializedObjects();
ShadowOverrides.clearProvider();
}
}
}
@@ -0,0 +1,54 @@
/*
* 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.
*/
package com.android.launcher3.util;
import static org.mockito.Mockito.mock;
import android.app.Application;
import com.android.launcher3.shadows.LShadowWallpaperManager;
import com.android.launcher3.shadows.ShadowMainThreadInitializedObject;
import com.android.launcher3.shadows.ShadowOverrides;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import org.robolectric.TestLifecycleApplication;
import org.robolectric.shadows.ShadowLog;
import java.lang.reflect.Method;
public class LauncherTestApplication extends Application implements TestLifecycleApplication {
@Override
public void beforeTest(Method method) {
ShadowLog.stream = System.out;
// Disable plugins
PluginManagerWrapper.INSTANCE.initializeForTesting(mock(PluginManagerWrapper.class));
// Initialize mock wallpaper manager
LShadowWallpaperManager.initializeMock();
}
@Override
public void prepareTest(Object test) { }
@Override
public void afterTest(Method method) {
ShadowLog.stream = null;
ShadowMainThreadInitializedObject.resetInitializedObjects();
ShadowOverrides.clearProvider();
}
}
@@ -0,0 +1,102 @@
/*
* 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.
*/
package com.android.launcher3.util;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.makeMeasureSpec;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.graphics.Point;
import android.view.View;
import android.view.WindowManager;
import com.android.launcher3.Launcher;
import org.robolectric.Robolectric;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.shadows.ShadowLooper;
import org.robolectric.util.ReflectionHelpers;
import java.util.List;
/**
* Utility class to help manage Launcher UI and related objects for test.
*/
public class LauncherUIHelper {
/**
* Returns the class name for the Launcher activity as defined in the manifest
*/
public static String getLauncherClassName() {
Context context = RuntimeEnvironment.application;
Intent homeIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
.setPackage(context.getPackageName())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
List<ResolveInfo> launchers = context.getPackageManager()
.queryIntentActivities(homeIntent, 0);
if (launchers.size() != 1) {
return null;
}
return launchers.get(0).activityInfo.name;
}
/**
* Returns an activity controller for Launcher activity defined in the manifest
*/
public static <T extends Launcher> ActivityController<T> buildLauncher() {
try {
Class<T> tClass = (Class<T>) Class.forName(getLauncherClassName());
return Robolectric.buildActivity(tClass);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Creates and binds a Launcher activity defined in the manifest.
* Note that the model must be bound before calling this
*/
public static <T extends Launcher> T buildAndBindLauncher() {
ActivityController<T> controller = buildLauncher();
T launcher = controller.setup().get();
doLayout(launcher);
ViewOnDrawExecutor executor = ReflectionHelpers.getField(launcher, "mPendingExecutor");
if (executor != null) {
executor.runAllTasks();
}
return launcher;
}
/**
* Performs a measure and layout pass for the given activity
*/
public static void doLayout(Activity activity) {
Point size = new Point();
RuntimeEnvironment.application.getSystemService(WindowManager.class)
.getDefaultDisplay().getSize(size);
View view = activity.getWindow().getDecorView();
view.measure(makeMeasureSpec(size.x, EXACTLY), makeMeasureSpec(size.y, EXACTLY));
view.layout(0, 0, size.x, size.y);
ShadowLooper.idleMainLooper();
}
}
@@ -34,15 +34,15 @@ import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.WidgetPreviewLoader; import com.android.launcher3.WidgetPreviewLoader;
import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.model.WidgetItem; import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.util.LauncherRoboTestRunner; import com.android.launcher3.model.data.PackageItemInfo;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowPackageManager; import org.robolectric.shadows.ShadowPackageManager;
import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.ReflectionHelpers;
@@ -50,7 +50,7 @@ import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@RunWith(LauncherRoboTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class WidgetsListAdapterTest { public class WidgetsListAdapterTest {
@Mock private LayoutInflater mMockLayoutInflater; @Mock private LayoutInflater mMockLayoutInflater;
@@ -350,7 +350,7 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
mWidgetView.requestLayout(); mWidgetView.requestLayout();
} }
static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher, public static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher,
int spanX, int spanY) { int spanX, int spanY) {
getWidgetSizeRanges(launcher, spanX, spanY, sTmpRect); getWidgetSizeRanges(launcher, spanX, spanY, sTmpRect);
widgetView.updateAppWidgetSize(null, sTmpRect.left, sTmpRect.top, widgetView.updateAppWidgetSize(null, sTmpRect.left, sTmpRect.top,
@@ -17,6 +17,7 @@ import androidx.annotation.WorkerThread;
import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.model.LoaderTask; import com.android.launcher3.model.LoaderTask;
import com.android.launcher3.model.WidgetsModel; import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.pm.UserCache; import com.android.launcher3.pm.UserCache;
import com.android.launcher3.provider.RestoreDbTask; import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.util.ContentWriter; import com.android.launcher3.util.ContentWriter;
@@ -44,6 +44,8 @@ import com.android.launcher3.LauncherProvider.SqlArguments;
import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.icons.GraphicsUtils; import com.android.launcher3.icons.GraphicsUtils;
import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.qsb.QsbContainerView; import com.android.launcher3.qsb.QsbContainerView;
import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PackageManagerHelper;
@@ -39,6 +39,8 @@ import androidx.annotation.Nullable;
import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.model.AppLaunchTracker; import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.touch.ItemClickHandler;
@@ -53,7 +53,12 @@ import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.icons.DotRenderer; import com.android.launcher3.icons.DotRenderer;
import com.android.launcher3.icons.IconCache.IconLoadRequest; import com.android.launcher3.icons.IconCache.IconLoadRequest;
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver; import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
import com.android.launcher3.model.PackageItemInfo; import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.model.data.PromiseAppInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.IconLabelDotView; import com.android.launcher3.views.IconLabelDotView;
@@ -46,6 +46,7 @@ import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.Themes; import com.android.launcher3.util.Themes;
import com.android.launcher3.util.Thunk; import com.android.launcher3.util.Thunk;
+8 -2
View File
@@ -59,6 +59,7 @@ import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.folder.PreviewBackground; import com.android.launcher3.folder.PreviewBackground;
import com.android.launcher3.graphics.DragPreviewProvider; import com.android.launcher3.graphics.DragPreviewProvider;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.CellAndSpan; import com.android.launcher3.util.CellAndSpan;
import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.ParcelableSparseArray; import com.android.launcher3.util.ParcelableSparseArray;
@@ -959,8 +960,13 @@ public class CellLayout extends ViewGroup {
height = r.height(); height = r.height();
} }
if (v != null && v.getViewType() == DraggableView.DRAGGABLE_ICON) { // Center horizontaly
left += ((mCellWidth * spanX) - dragOutline.getWidth()) / 2; left += ((mCellWidth * spanX) - dragOutline.getWidth()) / 2;
if (v != null && v.getViewType() == DraggableView.DRAGGABLE_WIDGET) {
// Center vertically
top += ((mCellHeight * spanY) - dragOutline.getHeight()) / 2;
} else if (v != null && v.getViewType() == DraggableView.DRAGGABLE_ICON) {
int cHeight = getShortcutsAndWidgets().getCellContentHeight(); int cHeight = getShortcutsAndWidgets().getCellContentHeight();
int cellPaddingY = (int) Math.max(0, ((mCellHeight - cHeight) / 2f)); int cellPaddingY = (int) Math.max(0, ((mCellHeight - cHeight) / 2f));
top += cellPaddingY; top += cellPaddingY;
@@ -28,6 +28,10 @@ import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.logging.LoggerUtils; import com.android.launcher3.logging.LoggerUtils;
import com.android.launcher3.model.ModelWriter; import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.views.Snackbar; import com.android.launcher3.views.Snackbar;
+18 -28
View File
@@ -25,8 +25,6 @@ import android.graphics.Rect;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.view.Surface; import android.view.Surface;
import androidx.annotation.Nullable;
import com.android.launcher3.CellLayout.ContainerType; import com.android.launcher3.CellLayout.ContainerType;
import com.android.launcher3.graphics.IconShape; import com.android.launcher3.graphics.IconShape;
import com.android.launcher3.icons.DotRenderer; import com.android.launcher3.icons.DotRenderer;
@@ -36,8 +34,6 @@ import com.android.launcher3.util.DefaultDisplay;
public class DeviceProfile { public class DeviceProfile {
public final InvariantDeviceProfile inv; public final InvariantDeviceProfile inv;
// IDP with no grid override values.
@Nullable private final InvariantDeviceProfile originalIdp;
// Device properties // Device properties
public final boolean isTablet; public final boolean isTablet;
@@ -138,11 +134,10 @@ public class DeviceProfile {
public DotRenderer mDotRendererAllApps; public DotRenderer mDotRendererAllApps;
public DeviceProfile(Context context, InvariantDeviceProfile inv, public DeviceProfile(Context context, InvariantDeviceProfile inv,
InvariantDeviceProfile originalIDP, Point minSize, Point maxSize, Point minSize, Point maxSize,
int width, int height, boolean isLandscape, boolean isMultiWindowMode) { int width, int height, boolean isLandscape, boolean isMultiWindowMode) {
this.inv = inv; this.inv = inv;
this.originalIdp = inv;
this.isLandscape = isLandscape; this.isLandscape = isLandscape;
this.isMultiWindowMode = isMultiWindowMode; this.isMultiWindowMode = isMultiWindowMode;
@@ -234,19 +229,6 @@ public class DeviceProfile {
// Recalculate the available dimensions using the new hotseat size. // Recalculate the available dimensions using the new hotseat size.
updateAvailableDimensions(dm, res); updateAvailableDimensions(dm, res);
} }
if (originalIDP != null) {
// Grid size change should not affect All Apps UI, so we use the original profile
// measurements here.
DeviceProfile originalProfile = isLandscape
? originalIDP.landscapeProfile
: originalIDP.portraitProfile;
allAppsIconSizePx = originalProfile.iconSizePx;
allAppsIconTextSizePx = originalProfile.iconTextSizePx;
allAppsCellHeightPx = originalProfile.allAppsCellHeightPx;
allAppsIconDrawablePaddingPx = originalProfile.iconDrawablePaddingOriginalPx;
allAppsCellWidthPx = allAppsIconSizePx + 2 * allAppsIconDrawablePaddingPx;
}
updateWorkspacePadding(); updateWorkspacePadding();
// This is done last, after iconSizePx is calculated above. // This is done last, after iconSizePx is calculated above.
@@ -259,8 +241,8 @@ public class DeviceProfile {
public DeviceProfile copy(Context context) { public DeviceProfile copy(Context context) {
Point size = new Point(availableWidthPx, availableHeightPx); Point size = new Point(availableWidthPx, availableHeightPx);
return new DeviceProfile(context, inv, originalIdp, size, size, widthPx, heightPx, return new DeviceProfile(context, inv, size, size, widthPx, heightPx, isLandscape,
isLandscape, isMultiWindowMode); isMultiWindowMode);
} }
public DeviceProfile getMultiWindowProfile(Context context, Point mwSize) { public DeviceProfile getMultiWindowProfile(Context context, Point mwSize) {
@@ -271,8 +253,8 @@ public class DeviceProfile {
// In multi-window mode, we can have widthPx = availableWidthPx // In multi-window mode, we can have widthPx = availableWidthPx
// and heightPx = availableHeightPx because Launcher uses the InvariantDeviceProfiles' // and heightPx = availableHeightPx because Launcher uses the InvariantDeviceProfiles'
// widthPx and heightPx values where it's needed. // widthPx and heightPx values where it's needed.
DeviceProfile profile = new DeviceProfile(context, inv, null, mwSize, mwSize, DeviceProfile profile = new DeviceProfile(context, inv, mwSize, mwSize, mwSize.x, mwSize.y,
mwSize.x, mwSize.y, isLandscape, true); isLandscape, true);
// If there isn't enough vertical cell padding with the labels displayed, hide the labels. // If there isn't enough vertical cell padding with the labels displayed, hide the labels.
float workspaceCellPaddingY = profile.getCellSize().y - profile.iconSizePx float workspaceCellPaddingY = profile.getCellSize().y - profile.iconSizePx
@@ -356,11 +338,19 @@ public class DeviceProfile {
} }
cellWidthPx = iconSizePx + iconDrawablePaddingPx; cellWidthPx = iconSizePx + iconDrawablePaddingPx;
allAppsIconSizePx = iconSizePx; // All apps
allAppsIconTextSizePx = iconTextSizePx; if (allAppsHasDifferentNumColumns()) {
allAppsIconDrawablePaddingPx = iconDrawablePaddingPx; allAppsIconSizePx = ResourceUtils.pxFromDp(inv.allAppsIconSize, dm);
allAppsCellHeightPx = getCellSize().y; allAppsIconTextSizePx = Utilities.pxFromSp(inv.allAppsIconTextSize, dm);
allAppsCellWidthPx = allAppsIconSizePx + 2 * allAppsIconDrawablePaddingPx; allAppsCellHeightPx = getCellSize(inv.numAllAppsColumns, inv.numAllAppsColumns).y;
allAppsIconDrawablePaddingPx = iconDrawablePaddingOriginalPx;
} else {
allAppsIconSizePx = iconSizePx;
allAppsIconTextSizePx = iconTextSizePx;
allAppsIconDrawablePaddingPx = iconDrawablePaddingPx;
allAppsCellHeightPx = getCellSize().y;
}
allAppsCellWidthPx = allAppsIconSizePx + allAppsIconDrawablePaddingPx;
if (isVerticalBarLayout()) { if (isVerticalBarLayout()) {
// Always hide the Workspace text with vertical bar layout. // Always hide the Workspace text with vertical bar layout.
@@ -25,6 +25,7 @@ import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.folder.FolderNameProvider; import com.android.launcher3.folder.FolderNameProvider;
import com.android.launcher3.model.data.ItemInfo;
/** /**
* Interface defining an object that can receive a drag. * Interface defining an object that can receive a drag.
@@ -35,6 +35,7 @@ import android.util.Property;
import com.android.launcher3.graphics.PlaceHolderIconDrawable; import com.android.launcher3.graphics.PlaceHolderIconDrawable;
import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
public class FastBitmapDrawable extends Drawable { public class FastBitmapDrawable extends Drawable {
@@ -25,6 +25,7 @@ import android.view.ViewGroup;
import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderPagedView; import com.android.launcher3.folder.FolderPagedView;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.FocusLogic; import com.android.launcher3.util.FocusLogic;
import com.android.launcher3.util.Thunk; import com.android.launcher3.util.Thunk;
+1
View File
@@ -28,6 +28,7 @@ import android.view.ViewGroup;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider; import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
@@ -46,6 +46,10 @@ import androidx.annotation.WorkerThread;
import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.GraphicsUtils; import com.android.launcher3.icons.GraphicsUtils;
import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.UserCache; import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest; import com.android.launcher3.shortcuts.ShortcutRequest;
@@ -47,7 +47,6 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import com.android.launcher3.graphics.IconShape; import com.android.launcher3.graphics.IconShape;
import com.android.launcher3.graphics.LauncherPreviewRenderer;
import com.android.launcher3.util.ConfigMonitor; import com.android.launcher3.util.ConfigMonitor;
import com.android.launcher3.util.DefaultDisplay; import com.android.launcher3.util.DefaultDisplay;
import com.android.launcher3.util.DefaultDisplay.Info; import com.android.launcher3.util.DefaultDisplay.Info;
@@ -61,7 +60,6 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
public class InvariantDeviceProfile { public class InvariantDeviceProfile {
@@ -107,6 +105,8 @@ public class InvariantDeviceProfile {
public int iconBitmapSize; public int iconBitmapSize;
public int fillResIconDpi; public int fillResIconDpi;
public float iconTextSize; public float iconTextSize;
public float allAppsIconSize;
public float allAppsIconTextSize;
private SparseArray<TypedValue> mExtraAttrs; private SparseArray<TypedValue> mExtraAttrs;
@@ -149,6 +149,8 @@ public class InvariantDeviceProfile {
numHotseatIcons = p.numHotseatIcons; numHotseatIcons = p.numHotseatIcons;
numAllAppsColumns = p.numAllAppsColumns; numAllAppsColumns = p.numAllAppsColumns;
dbFile = p.dbFile; dbFile = p.dbFile;
allAppsIconSize = p.allAppsIconSize;
allAppsIconTextSize = p.allAppsIconTextSize;
defaultLayoutId = p.defaultLayoutId; defaultLayoutId = p.defaultLayoutId;
demoModeLayoutId = p.demoModeLayoutId; demoModeLayoutId = p.demoModeLayoutId;
mExtraAttrs = p.mExtraAttrs; mExtraAttrs = p.mExtraAttrs;
@@ -157,12 +159,9 @@ public class InvariantDeviceProfile {
@TargetApi(23) @TargetApi(23)
private InvariantDeviceProfile(Context context) { private InvariantDeviceProfile(Context context) {
if (context instanceof LauncherPreviewRenderer.PreviewContext) { String gridName = Utilities.getPrefs(context).getBoolean(GRID_OPTIONS_PREFERENCE_KEY, false)
throw new IllegalArgumentException( ? Utilities.getPrefs(context).getString(KEY_IDP_GRID_NAME, null)
"PreviewContext is passed into this IDP constructor"); : null;
}
String gridName = getCurrentGridName(context);
initGrid(context, gridName); initGrid(context, gridName);
mConfigMonitor = new ConfigMonitor(context, mConfigMonitor = new ConfigMonitor(context,
APPLY_CONFIG_AT_RUNTIME.get() ? this::onConfigChanged : this::killProcess); APPLY_CONFIG_AT_RUNTIME.get() ? this::onConfigChanged : this::killProcess);
@@ -179,7 +178,7 @@ public class InvariantDeviceProfile {
} }
} }
/** /**
* This constructor should NOT have any monitors by design. * This constructor should NOT have any monitors by design.
*/ */
public InvariantDeviceProfile(Context context, Display display) { public InvariantDeviceProfile(Context context, Display display) {
@@ -211,11 +210,55 @@ public class InvariantDeviceProfile {
Point smallestSize = new Point(displayInfo.smallestSize); Point smallestSize = new Point(displayInfo.smallestSize);
Point largestSize = new Point(displayInfo.largestSize); Point largestSize = new Point(displayInfo.largestSize);
ArrayList<DisplayOption> allOptions = getPredefinedDeviceProfiles(context, gridName);
// This guarantees that width < height // This guarantees that width < height
float minWidthDps = Utilities.dpiFromPx(Math.min(smallestSize.x, smallestSize.y), float minWidthDps = Utilities.dpiFromPx(Math.min(smallestSize.x, smallestSize.y),
displayInfo.metrics); displayInfo.metrics);
float minHeightDps = Utilities.dpiFromPx(Math.min(largestSize.x, largestSize.y), float minHeightDps = Utilities.dpiFromPx(Math.min(largestSize.x, largestSize.y),
displayInfo.metrics); displayInfo.metrics);
// Sort the profiles based on the closeness to the device size
Collections.sort(allOptions, (a, b) ->
Float.compare(dist(minWidthDps, minHeightDps, a.minWidthDps, a.minHeightDps),
dist(minWidthDps, minHeightDps, b.minWidthDps, b.minHeightDps)));
DisplayOption interpolatedDisplayOption =
invDistWeightedInterpolate(minWidthDps, minHeightDps, allOptions);
GridOption closestProfile = allOptions.get(0).grid;
numRows = closestProfile.numRows;
numColumns = closestProfile.numColumns;
numHotseatIcons = closestProfile.numHotseatIcons;
dbFile = closestProfile.dbFile;
defaultLayoutId = closestProfile.defaultLayoutId;
demoModeLayoutId = closestProfile.demoModeLayoutId;
numFolderRows = closestProfile.numFolderRows;
numFolderColumns = closestProfile.numFolderColumns;
numAllAppsColumns = closestProfile.numAllAppsColumns;
mExtraAttrs = closestProfile.extraAttrs;
if (!closestProfile.name.equals(gridName)) {
Utilities.getPrefs(context).edit()
.putString(KEY_IDP_GRID_NAME, closestProfile.name).apply();
}
iconSize = interpolatedDisplayOption.iconSize;
iconShapePath = getIconShapePath(context);
landscapeIconSize = interpolatedDisplayOption.landscapeIconSize;
iconBitmapSize = ResourceUtils.pxFromDp(iconSize, displayInfo.metrics);
iconTextSize = interpolatedDisplayOption.iconTextSize;
fillResIconDpi = getLauncherIconDensity(iconBitmapSize);
if (Utilities.getPrefs(context).getBoolean(GRID_OPTIONS_PREFERENCE_KEY, false)) {
allAppsIconSize = interpolatedDisplayOption.allAppsIconSize;
allAppsIconTextSize = interpolatedDisplayOption.allAppsIconTextSize;
} else {
allAppsIconSize = iconSize;
allAppsIconTextSize = iconTextSize;
}
// If the partner customization apk contains any grid overrides, apply them
// Supported overrides: numRows, numColumns, iconSize
applyPartnerDeviceProfileOverrides(context, displayInfo.metrics);
Point realSize = new Point(displayInfo.realSize); Point realSize = new Point(displayInfo.realSize);
// The real size never changes. smallSide and largeSide will remain the // The real size never changes. smallSide and largeSide will remain the
@@ -223,64 +266,10 @@ public class InvariantDeviceProfile {
int smallSide = Math.min(realSize.x, realSize.y); int smallSide = Math.min(realSize.x, realSize.y);
int largeSide = Math.max(realSize.x, realSize.y); int largeSide = Math.max(realSize.x, realSize.y);
// We want a list of all options as well as the list of filtered options. This allows us landscapeProfile = new DeviceProfile(context, this, smallestSize, largestSize,
// to have a consistent UI for areas that the grid size change should not affect largeSide, smallSide, true /* isLandscape */, false /* isMultiWindowMode */);
// ie. All Apps should be consistent between grid sizes. portraitProfile = new DeviceProfile(context, this, smallestSize, largestSize,
ArrayList<DisplayOption> allOptions = new ArrayList<>(); smallSide, largeSide, false /* isLandscape */, false /* isMultiWindowMode */);
ArrayList<DisplayOption> filteredOptions = new ArrayList<>();
getPredefinedDeviceProfiles(context, gridName, filteredOptions, allOptions);
if (allOptions.isEmpty() && filteredOptions.isEmpty()) {
throw new RuntimeException("No display option with canBeDefault=true");
}
// Sort the profiles based on the closeness to the device size
Comparator<DisplayOption> comparator = (a, b) -> Float.compare(dist(minWidthDps,
minHeightDps, a.minWidthDps, a.minHeightDps),
dist(minWidthDps, minHeightDps, b.minWidthDps, b.minHeightDps));
// Calculate the device profiles as if there is no grid override.
Collections.sort(allOptions, comparator);
DisplayOption interpolatedDisplayOption =
invDistWeightedInterpolate(minWidthDps, minHeightDps, allOptions);
initGridOption(context, allOptions, interpolatedDisplayOption, displayInfo.metrics);
// Create IDP with no grid override values.
InvariantDeviceProfile originalIDP = new InvariantDeviceProfile(this);
originalIDP.landscapeProfile = new DeviceProfile(context, this, null, smallestSize,
largestSize, largeSide, smallSide, true /* isLandscape */,
false /* isMultiWindowMode */);
originalIDP.portraitProfile = new DeviceProfile(context, this, null, smallestSize,
largestSize, smallSide, largeSide, false /* isLandscape */,
false /* isMultiWindowMode */);
if (filteredOptions.isEmpty()) {
filteredOptions = allOptions;
landscapeProfile = originalIDP.landscapeProfile;
portraitProfile = originalIDP.portraitProfile;
} else {
Collections.sort(filteredOptions, comparator);
interpolatedDisplayOption =
invDistWeightedInterpolate(minWidthDps, minHeightDps, filteredOptions);
initGridOption(context, filteredOptions, interpolatedDisplayOption,
displayInfo.metrics);
numAllAppsColumns = originalIDP.numAllAppsColumns;
landscapeProfile = new DeviceProfile(context, this, originalIDP, smallestSize,
largestSize, largeSide, smallSide, true /* isLandscape */,
false /* isMultiWindowMode */);
portraitProfile = new DeviceProfile(context, this, originalIDP, smallestSize,
largestSize, smallSide, largeSide, false /* isLandscape */,
false /* isMultiWindowMode */);
}
GridOption closestProfile = filteredOptions.get(0).grid;
if (!closestProfile.name.equals(gridName)) {
Utilities.getPrefs(context).edit()
.putString(KEY_IDP_GRID_NAME, closestProfile.name).apply();
}
// We need to ensure that there is enough extra space in the wallpaper // We need to ensure that there is enough extra space in the wallpaper
// for the intended parallax effects // for the intended parallax effects
@@ -298,34 +287,6 @@ public class InvariantDeviceProfile {
return closestProfile.name; return closestProfile.name;
} }
private void initGridOption(Context context, ArrayList<DisplayOption> options,
DisplayOption displayOption, DisplayMetrics metrics) {
GridOption closestProfile = options.get(0).grid;
numRows = closestProfile.numRows;
numColumns = closestProfile.numColumns;
numHotseatIcons = closestProfile.numHotseatIcons;
dbFile = closestProfile.dbFile;
defaultLayoutId = closestProfile.defaultLayoutId;
demoModeLayoutId = closestProfile.demoModeLayoutId;
numFolderRows = closestProfile.numFolderRows;
numFolderColumns = closestProfile.numFolderColumns;
numAllAppsColumns = numColumns;
mExtraAttrs = closestProfile.extraAttrs;
iconSize = displayOption.iconSize;
iconShapePath = getIconShapePath(context);
landscapeIconSize = displayOption.landscapeIconSize;
iconBitmapSize = ResourceUtils.pxFromDp(iconSize, metrics);
iconTextSize = displayOption.iconTextSize;
fillResIconDpi = getLauncherIconDensity(iconBitmapSize);
// If the partner customization apk contains any grid overrides, apply them
// Supported overrides: numRows, numColumns, iconSize
applyPartnerDeviceProfileOverrides(context, metrics);
}
@Nullable @Nullable
public TypedValue getAttrValue(int attr) { public TypedValue getAttrValue(int attr) {
return mExtraAttrs == null ? null : mExtraAttrs.get(attr); return mExtraAttrs == null ? null : mExtraAttrs.get(attr);
@@ -403,13 +364,7 @@ public class InvariantDeviceProfile {
} }
} }
/** static ArrayList<DisplayOption> getPredefinedDeviceProfiles(Context context, String gridName) {
* @param gridName The current grid name.
* @param filteredOptionsOut List filled with all the filtered options based on gridName.
* @param allOptionsOut List filled with all the options that can be the default option.
*/
static void getPredefinedDeviceProfiles(Context context, String gridName,
ArrayList<DisplayOption> filteredOptionsOut, ArrayList<DisplayOption> allOptionsOut) {
ArrayList<DisplayOption> profiles = new ArrayList<>(); ArrayList<DisplayOption> profiles = new ArrayList<>();
try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) { try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) {
final int depth = parser.getDepth(); final int depth = parser.getDepth();
@@ -436,19 +391,26 @@ public class InvariantDeviceProfile {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
ArrayList<DisplayOption> filteredProfiles = new ArrayList<>();
if (!TextUtils.isEmpty(gridName)) { if (!TextUtils.isEmpty(gridName)) {
for (DisplayOption option : profiles) { for (DisplayOption option : profiles) {
if (gridName.equals(option.grid.name)) { if (gridName.equals(option.grid.name)) {
filteredOptionsOut.add(option); filteredProfiles.add(option);
} }
} }
} }
if (filteredProfiles.isEmpty()) {
for (DisplayOption option : profiles) { // No grid found, use the default options
if (option.canBeDefault) { for (DisplayOption option : profiles) {
allOptionsOut.add(option); if (option.canBeDefault) {
filteredProfiles.add(option);
}
} }
} }
if (filteredProfiles.isEmpty()) {
throw new RuntimeException("No display option with canBeDefault=true");
}
return filteredProfiles;
} }
private int getLauncherIconDensity(int requiredSize) { private int getLauncherIconDensity(int requiredSize) {
@@ -493,7 +455,7 @@ public class InvariantDeviceProfile {
@VisibleForTesting @VisibleForTesting
static DisplayOption invDistWeightedInterpolate(float width, float height, static DisplayOption invDistWeightedInterpolate(float width, float height,
ArrayList<DisplayOption> points) { ArrayList<DisplayOption> points) {
float weights = 0; float weights = 0;
DisplayOption p = points.get(0); DisplayOption p = points.get(0);
@@ -573,6 +535,8 @@ public class InvariantDeviceProfile {
private final int numHotseatIcons; private final int numHotseatIcons;
private final String dbFile; private final String dbFile;
private final int numAllAppsColumns;
private final int defaultLayoutId; private final int defaultLayoutId;
private final int demoModeLayoutId; private final int demoModeLayoutId;
@@ -596,6 +560,8 @@ public class InvariantDeviceProfile {
R.styleable.GridDisplayOption_numFolderRows, numRows); R.styleable.GridDisplayOption_numFolderRows, numRows);
numFolderColumns = a.getInt( numFolderColumns = a.getInt(
R.styleable.GridDisplayOption_numFolderColumns, numColumns); R.styleable.GridDisplayOption_numFolderColumns, numColumns);
numAllAppsColumns = a.getInt(
R.styleable.GridDisplayOption_numAllAppsColumns, numColumns);
a.recycle(); a.recycle();
@@ -615,6 +581,8 @@ public class InvariantDeviceProfile {
private float iconSize; private float iconSize;
private float iconTextSize; private float iconTextSize;
private float landscapeIconSize; private float landscapeIconSize;
private float allAppsIconSize;
private float allAppsIconTextSize;
DisplayOption(GridOption grid, Context context, AttributeSet attrs) { DisplayOption(GridOption grid, Context context, AttributeSet attrs) {
this.grid = grid; this.grid = grid;
@@ -633,6 +601,10 @@ public class InvariantDeviceProfile {
iconSize); iconSize);
iconTextSize = a.getFloat(R.styleable.ProfileDisplayOption_iconTextSize, 0); iconTextSize = a.getFloat(R.styleable.ProfileDisplayOption_iconTextSize, 0);
allAppsIconSize = a.getFloat(R.styleable.ProfileDisplayOption_allAppsIconSize,
iconSize);
allAppsIconTextSize = a.getFloat(R.styleable.ProfileDisplayOption_allAppsIconTextSize,
iconTextSize);
a.recycle(); a.recycle();
} }
@@ -647,14 +619,18 @@ public class InvariantDeviceProfile {
private DisplayOption multiply(float w) { private DisplayOption multiply(float w) {
iconSize *= w; iconSize *= w;
landscapeIconSize *= w; landscapeIconSize *= w;
allAppsIconSize *= w;
iconTextSize *= w; iconTextSize *= w;
allAppsIconTextSize *= w;
return this; return this;
} }
private DisplayOption add(DisplayOption p) { private DisplayOption add(DisplayOption p) {
iconSize += p.iconSize; iconSize += p.iconSize;
landscapeIconSize += p.landscapeIconSize; landscapeIconSize += p.landscapeIconSize;
allAppsIconSize += p.allAppsIconSize;
iconTextSize += p.iconTextSize; iconTextSize += p.iconTextSize;
allAppsIconTextSize += p.allAppsIconTextSize;
return this; return this;
} }
} }
@@ -672,4 +648,4 @@ public class InvariantDeviceProfile {
onConfigChanged(context); onConfigChanged(context);
} }
} }
} }
+23 -1
View File
@@ -110,6 +110,12 @@ import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.model.AppLaunchTracker; import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.ModelWriter; import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.PromiseAppInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.notification.NotificationListener; import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.pm.PinRequestHelper; import com.android.launcher3.pm.PinRequestHelper;
import com.android.launcher3.pm.UserCache; import com.android.launcher3.pm.UserCache;
@@ -133,6 +139,7 @@ import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.MultiValueAlpha; import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty; import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.PendingRequestArgs; import com.android.launcher3.util.PendingRequestArgs;
@@ -294,6 +301,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
// We only want to get the SharedPreferences once since it does an FS stat each time we get // We only want to get the SharedPreferences once since it does an FS stat each time we get
// it from the context. // it from the context.
private SharedPreferences mSharedPrefs; private SharedPreferences mSharedPrefs;
private OnboardingPrefs mOnboardingPrefs;
// Activity result which needs to be processed after workspace has loaded. // Activity result which needs to be processed after workspace has loaded.
private ActivityResultInfo mPendingActivityResult; private ActivityResultInfo mPendingActivityResult;
@@ -361,6 +369,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
mAllAppsController = new AllAppsTransitionController(this); mAllAppsController = new AllAppsTransitionController(this);
mStateManager = new LauncherStateManager(this); mStateManager = new LauncherStateManager(this);
mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs, mStateManager);
mAppWidgetManager = new WidgetManagerHelper(this); mAppWidgetManager = new WidgetManagerHelper(this);
mAppWidgetHost = new LauncherAppWidgetHost(this, mAppWidgetHost = new LauncherAppWidgetHost(this,
appWidgetId -> getWorkspace().removeWidget(appWidgetId)); appWidgetId -> getWorkspace().removeWidget(appWidgetId));
@@ -452,6 +462,15 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
return new LauncherOverlayManager() { }; return new LauncherOverlayManager() { };
} }
protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs,
LauncherStateManager stateManager) {
return new OnboardingPrefs<>(this, sharedPrefs, stateManager);
}
public OnboardingPrefs getOnboardingPrefs() {
return mOnboardingPrefs;
}
@Override @Override
public void onPluginConnected(OverlayPlugin overlayManager, Context context) { public void onPluginConnected(OverlayPlugin overlayManager, Context context) {
switchOverlay(() -> overlayManager.createOverlayManager(this, this)); switchOverlay(() -> overlayManager.createOverlayManager(this, this));
@@ -1443,6 +1462,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
mLauncherCallbacks.onHomeIntent(internalStateHandled); mLauncherCallbacks.onHomeIntent(internalStateHandled);
} }
mOverlayManager.hideOverlay(isStarted() && !isForceInvisible()); mOverlayManager.hideOverlay(isStarted() && !isForceInvisible());
} else if (Intent.ACTION_ALL_APPS.equals(intent.getAction())) {
getStateManager().goToState(ALL_APPS, alreadyOnHome);
} }
TraceHelper.INSTANCE.endSection(traceToken); TraceHelper.INSTANCE.endSection(traceToken);
@@ -2557,9 +2578,10 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
writer.println(prefix + "\tmRotationHelper: " + mRotationHelper); writer.println(prefix + "\tmRotationHelper: " + mRotationHelper);
writer.println(prefix + "\tmAppWidgetHost.isListening: " + mAppWidgetHost.isListening()); writer.println(prefix + "\tmAppWidgetHost.isListening: " + mAppWidgetHost.isListening());
// Extra logging for b/116853349 // Extra logging for general debugging
mDragLayer.dump(prefix, writer); mDragLayer.dump(prefix, writer);
mStateManager.dump(prefix, writer); mStateManager.dump(prefix, writer);
mPopupDataProvider.dump(prefix, writer);
try { try {
FileLog.flushAll(writer); FileLog.flushAll(writer);
@@ -13,6 +13,7 @@ import android.os.UserHandle;
import com.android.launcher3.icons.ComponentWithLabelAndIcon; import com.android.launcher3.icons.ComponentWithLabelAndIcon;
import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
/** /**
* This class is a thin wrapper around the framework AppWidgetProviderInfo class. This class affords * This class is a thin wrapper around the framework AppWidgetProviderInfo class. This class affords

Some files were not shown because too many files have changed in this diff Show More