Merge "launcher: use scalable grid in 4x4" into sc-v2-dev
diff --git a/Android.bp b/Android.bp
index 43d28c9..c8d9186 100644
--- a/Android.bp
+++ b/Android.bp
@@ -33,6 +33,9 @@
android_library {
name: "launcher-aosp-tapl",
+ libs: [
+ "framework-statsd",
+ ],
static_libs: [
"androidx.annotation_annotation",
"androidx.test.runner",
@@ -192,6 +195,9 @@
resource_dirs: [
"quickstep/res",
],
+ libs: [
+ "framework-statsd",
+ ],
static_libs: [
"Launcher3ResLib",
"SystemUISharedLib",
@@ -261,6 +267,9 @@
resource_dirs: [
"quickstep/res",
],
+ libs: [
+ "framework-statsd",
+ ],
static_libs: [
"SystemUI-statsd",
"SystemUISharedLib",
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index 6d49d75..ca9f063 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -59,6 +59,7 @@
SettingsContainer settings_container = 9;
PredictedHotseatContainer predicted_hotseat_container = 10;
TaskSwitcherContainer task_switcher_container = 11;
+ TaskBarContainer task_bar_container = 12;
ExtendedContainers extended_containers = 20;
}
}
@@ -100,6 +101,16 @@
message TaskSwitcherContainer {
}
+// Container for taskbar.
+// Configured to show up on large screens(tablet-sized) such as foldables in expanded state, within
+// an app view(not in launcher screen).
+message TaskBarContainer {
+ optional int32 index = 1;
+
+ // Bit encoded value to capture pinned and predicted taskbar positions.
+ optional int32 cardinality = 2;
+}
+
enum Attribute {
UNKNOWN = 0;
DEFAULT_LAYOUT = 1; // icon automatically placed in workspace, folder, hotseat
@@ -230,6 +241,7 @@
oneof ParentContainer {
WorkspaceContainer workspace = 4;
HotseatContainer hotseat = 5;
+ TaskBarContainer taskbar = 6;
}
}
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 2534699..d24d752 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -90,6 +90,8 @@
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
import com.android.systemui.unfold.config.UnfoldTransitionConfig;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.List;
import java.util.stream.Stream;
@@ -122,6 +124,15 @@
private final ServiceConnection mTisBinderConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
+ if (!(iBinder instanceof TISBinder)) {
+ // Seems like there can be a race condition when user unlocks, which kills the TIS
+ // process and re-starts it. I guess in the meantime service can be connected to
+ // a killed TIS? Either way, unbind and try to re-connect in that case.
+ unbindService(mTisBinderConnection);
+ mHandler.postDelayed(mConnectionRunnable, BACKOFF_MILLIS);
+ return;
+ }
+
mTaskbarManager = ((TISBinder) iBinder).getTaskbarManager();
mTaskbarManager.setLauncher(BaseQuickstepLauncher.this);
@@ -619,4 +630,12 @@
recentsView.finishRecentsAnimation(/* toRecents= */ true, null);
}
}
+
+ @Override
+ public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ super.dump(prefix, fd, writer, args);
+ if (mDepthController != null) {
+ mDepthController.dump(prefix, writer);
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index 5769f0b..55a140d 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -25,7 +25,9 @@
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
import static com.android.launcher3.Utilities.getDevicePrefs;
import static com.android.launcher3.hybridhotseat.HotseatPredictionModel.convertDataModelToAppTargetBundle;
+import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import android.app.StatsManager;
import android.app.prediction.AppPredictionContext;
import android.app.prediction.AppPredictionManager;
import android.app.prediction.AppPredictor;
@@ -39,12 +41,14 @@
import android.content.pm.ShortcutInfo;
import android.os.UserHandle;
import android.util.Log;
+import android.util.StatsEvent;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
@@ -53,10 +57,10 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
-import com.android.launcher3.util.Executors;
import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.PersistedItemArray;
import com.android.quickstep.logging.StatsLogCompatManager;
+import com.android.systemui.shared.system.SysUiStatsLog;
import java.util.Collections;
import java.util.List;
@@ -85,6 +89,7 @@
private final InvariantDeviceProfile mIDP;
private final AppEventProducer mAppEventProducer;
+ private final StatsManager mStatsManager;
protected boolean mActive = false;
@@ -93,6 +98,7 @@
mIDP = InvariantDeviceProfile.INSTANCE.get(context);
StatsLogCompatManager.LOGS_CONSUMER.add(mAppEventProducer);
+ mStatsManager = context.getSystemService(StatsManager.class);
}
@Override
@@ -155,10 +161,60 @@
additionalSnapshotEvents(instanceId);
prefs.edit().putLong(LAST_SNAPSHOT_TIME_MILLIS, now).apply();
}
+
+ // Only register for launcher snapshot logging if this is the primary ModelDelegate
+ // instance, as there will be additional instances that may be destroyed at any time.
+ if (mIsPrimaryInstance) {
+ registerSnapshotLoggingCallback();
+ }
}
protected void additionalSnapshotEvents(InstanceId snapshotInstanceId){}
+ /**
+ * Registers a callback to log launcher workspace layout using Statsd pulled atom.
+ */
+ protected void registerSnapshotLoggingCallback() {
+ if (mStatsManager == null) {
+ Log.d(TAG, "Failed to get StatsManager");
+ }
+
+ try {
+ mStatsManager.setPullAtomCallback(
+ SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT,
+ null /* PullAtomMetadata */,
+ MODEL_EXECUTOR,
+ (i, eventList) -> {
+ InstanceId instanceId = new InstanceIdSequence().newInstanceId();
+ IntSparseArrayMap<ItemInfo> itemsIdMap;
+ synchronized (mDataModel) {
+ itemsIdMap = mDataModel.itemsIdMap.clone();
+ }
+
+ for (ItemInfo info : itemsIdMap) {
+ FolderInfo parent = info.container > 0
+ ? (FolderInfo) itemsIdMap.get(info.container) : null;
+ LauncherAtom.ItemInfo itemInfo = info.buildProto(parent);
+ Log.d(TAG, itemInfo.toString());
+ StatsEvent statsEvent = StatsLogCompatManager.buildStatsEvent(itemInfo,
+ instanceId);
+ eventList.add(statsEvent);
+ }
+ Log.d(TAG,
+ String.format(
+ "Successfully logged %d workspace items with instanceId=%d",
+ itemsIdMap.size(), instanceId.getId()));
+ additionalSnapshotEvents(instanceId);
+ return StatsManager.PULL_SUCCESS;
+ }
+ );
+ Log.d(TAG, "Successfully registered for launcher snapshot logging!");
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Failed to register launcher snapshot logging callback with StatsManager",
+ e);
+ }
+ }
+
@Override
public void validateData() {
super.validateData();
@@ -175,7 +231,9 @@
super.destroy();
mActive = false;
StatsLogCompatManager.LOGS_CONSUMER.remove(mAppEventProducer);
-
+ if (mIsPrimaryInstance) {
+ mStatsManager.clearPullAtomCallback(SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT);
+ }
destroyPredictors();
}
@@ -221,7 +279,7 @@
private void registerPredictor(PredictorState state, AppPredictor predictor) {
state.predictor = predictor;
state.predictor.registerPredictionUpdates(
- Executors.MODEL_EXECUTOR, t -> handleUpdate(state, t));
+ MODEL_EXECUTOR, t -> handleUpdate(state, t));
state.predictor.requestPredictionUpdate();
}
@@ -236,7 +294,7 @@
private void registerWidgetsPredictor(AppPredictor predictor) {
mWidgetsRecommendationState.predictor = predictor;
mWidgetsRecommendationState.predictor.registerPredictionUpdates(
- Executors.MODEL_EXECUTOR, targets -> {
+ MODEL_EXECUTOR, targets -> {
if (mWidgetsRecommendationState.setTargets(targets)) {
// No diff, skip
return;
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index 3e2fb63..9d70cfa 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -44,6 +44,8 @@
import com.android.systemui.shared.system.BlurUtils;
import com.android.systemui.shared.system.WallpaperManagerCompat;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.function.Consumer;
/**
@@ -138,6 +140,11 @@
*/
private float mDepth;
/**
+ * Last blur value, in pixels, that was applied.
+ * For debugging purposes.
+ */
+ private int mCurrentBlur;
+ /**
* If we're launching and app and should not be blurring the screen for performance reasons.
*/
private boolean mBlurDisabledForAppLaunch;
@@ -306,10 +313,10 @@
if (supportsBlur) {
boolean opaque = mLauncher.getScrimView().isFullyOpaque();
- int blur = !mCrossWindowBlursEnabled || mBlurDisabledForAppLaunch
+ mCurrentBlur = !mCrossWindowBlursEnabled || mBlurDisabledForAppLaunch
? 0 : (int) (depth * mMaxBlurRadius);
SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()
- .setBackgroundBlurRadius(mSurface, blur)
+ .setBackgroundBlurRadius(mSurface, mCurrentBlur)
.setOpaque(mSurface, opaque);
// Set early wake-up flags when we know we're executing an expensive operation, this way
@@ -348,4 +355,18 @@
mwAnimation.setAutoCancel(true);
mwAnimation.start();
}
+
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + this.getClass().getSimpleName());
+ writer.println(prefix + "\tmMaxBlurRadius=" + mMaxBlurRadius);
+ writer.println(prefix + "\tmCrossWindowBlursEnabled=" + mCrossWindowBlursEnabled);
+ writer.println(prefix + "\tmSurface=" + mSurface);
+ writer.println(prefix + "\tmOverlayScrollProgress=" + mOverlayScrollProgress);
+ writer.println(prefix + "\tmDepth=" + mDepth);
+ writer.println(prefix + "\tmCurrentBlur=" + mCurrentBlur);
+ writer.println(prefix + "\tmBlurDisabledForAppLaunch=" + mBlurDisabledForAppLaunch);
+ writer.println(prefix + "\tmInEarlyWakeUp=" + mInEarlyWakeUp);
+ writer.println(prefix + "\tmIgnoreStateChangesDuringMultiWindowAnimation="
+ + mIgnoreStateChangesDuringMultiWindowAnimation);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 764b0d3..68dfac7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -16,11 +16,15 @@
package com.android.launcher3.taskbar;
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_HIDE;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_SHOW;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
+import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.graphics.Rect;
import android.view.MotionEvent;
@@ -36,7 +40,11 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.logging.InstanceId;
+import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.model.data.ItemInfoWithIcon;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.util.OnboardingPrefs;
@@ -71,6 +79,16 @@
private final DeviceProfile.OnDeviceProfileChangeListener mOnDeviceProfileChangeListener =
this::onStashedInAppChanged;
+ private final StateManager.StateListener<LauncherState> mStateListener =
+ new StateManager.StateListener<LauncherState>() {
+ @Override
+ public void onStateTransitionComplete(LauncherState finalState) {
+ TaskbarStashController controller = mControllers.taskbarStashController;
+ controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
+ finalState.isTaskbarStashed());
+ }
+ };
+
// Initialized in init.
private TaskbarControllers mControllers;
private AnimatedFloat mTaskbarBackgroundAlpha;
@@ -113,6 +131,7 @@
onStashedInAppChanged(mLauncher.getDeviceProfile());
mLauncher.addOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
+ mLauncher.getStateManager().addStateListener(mStateListener);
}
@Override
@@ -122,13 +141,14 @@
mIconAlignmentForGestureState.finishAnimation();
mLauncher.removeOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
+ mLauncher.getStateManager().removeStateListener(mStateListener);
mLauncher.getHotseat().setIconsAlpha(1f);
mLauncher.setTaskbarUIController(null);
}
@Override
protected boolean isTaskbarTouchable() {
- return !isAnimatingToLauncher() && !mControllers.taskbarStashController.isStashed();
+ return !isAnimatingToLauncher();
}
private boolean isAnimatingToLauncher() {
@@ -179,24 +199,28 @@
*/
public Animator createAnimToLauncher(@NonNull LauncherState toState,
@NonNull RecentsAnimationCallbacks callbacks, long duration) {
+ AnimatorSet animatorSet = new AnimatorSet();
TaskbarStashController stashController = mControllers.taskbarStashController;
- ObjectAnimator animator = mIconAlignmentForGestureState
- .animateToValue(1)
- .setDuration(duration);
- animator.addListener(new AnimatorListenerAdapter() {
+ stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
+ toState.isTaskbarStashed());
+ if (toState.isTaskbarStashed()) {
+ animatorSet.play(stashController.applyStateWithoutStart(duration));
+ } else {
+ animatorSet.play(mIconAlignmentForGestureState
+ .animateToValue(1)
+ .setDuration(duration));
+ }
+ animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
- public void onAnimationEnd(Animator animation) {
+ public void onAnimationEnd(Animator animator) {
mTargetStateOverride = null;
animator.removeListener(this);
}
@Override
- public void onAnimationStart(Animator animation) {
+ public void onAnimationStart(Animator animator) {
mTargetStateOverride = toState;
mIsAnimatingToLauncherViaGesture = true;
- // TODO: FLAG_IN_APP might be sufficient for now, but in the future we do want to
- // add another flag for LauncherState as well. We will need to decide whether to
- // show hotseat or the task bar.
stashController.updateStateForFlag(FLAG_IN_APP, false);
stashController.applyState(duration);
}
@@ -210,7 +234,7 @@
callbacks.removeListener(listener);
});
- return animator;
+ return animatorSet;
}
private float getCurrentIconAlignmentRatio() {
@@ -262,6 +286,11 @@
@Override
protected void onStashedInAppChanged() {
onStashedInAppChanged(mLauncher.getDeviceProfile());
+ if (mControllers.taskbarStashController.isStashedInApp()) {
+ mContext.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_LONGPRESS_HIDE);
+ } else {
+ mContext.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_LONGPRESS_SHOW);
+ }
}
private void onStashedInAppChanged(DeviceProfile deviceProfile) {
@@ -306,6 +335,12 @@
mControllers.taskbarEduController.hideEdu();
}
+ @Override
+ public void onTaskbarIconLaunched(WorkspaceItemInfo item) {
+ InstanceId instanceId = new InstanceIdSequence().newInstanceId();
+ mLauncher.logAppLaunch(mContext.getStatsLogManager(), item, instanceId);
+ }
+
private final class TaskBarRecentsAnimationListener implements RecentsAnimationListener {
private final RecentsAnimationCallbacks mCallbacks;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 0d684a0..0b6f9c4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -19,6 +19,7 @@
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR;
@@ -52,6 +53,7 @@
import com.android.launcher3.R;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.taskbar.contextual.RotationButtonController;
@@ -162,6 +164,8 @@
mWindowLayoutParams.setFitInsetsTypes(0);
mWindowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ mWindowLayoutParams.privateFlags =
+ WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
WindowManagerWrapper wmWrapper = WindowManagerWrapper.getInstance();
wmWrapper.setProvidesInsetsTypes(
@@ -230,6 +234,60 @@
}
/**
+ * Change from hotseat/predicted hotseat to taskbar container.
+ */
+ @Override
+ public void applyOverwritesToLogItem(LauncherAtom.ItemInfo.Builder itemInfoBuilder) {
+ if (!itemInfoBuilder.hasContainerInfo()) {
+ return;
+ }
+ LauncherAtom.ContainerInfo oldContainer = itemInfoBuilder.getContainerInfo();
+
+ if (oldContainer.hasPredictedHotseatContainer()) {
+ LauncherAtom.PredictedHotseatContainer predictedHotseat =
+ oldContainer.getPredictedHotseatContainer();
+ LauncherAtom.TaskBarContainer.Builder taskbarBuilder =
+ LauncherAtom.TaskBarContainer.newBuilder();
+
+ if (predictedHotseat.hasIndex()) {
+ taskbarBuilder.setIndex(predictedHotseat.getIndex());
+ }
+ if (predictedHotseat.hasCardinality()) {
+ taskbarBuilder.setCardinality(predictedHotseat.getCardinality());
+ }
+
+ itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
+ .setTaskBarContainer(taskbarBuilder));
+ } else if (oldContainer.hasHotseat()) {
+ LauncherAtom.HotseatContainer hotseat = oldContainer.getHotseat();
+ LauncherAtom.TaskBarContainer.Builder taskbarBuilder =
+ LauncherAtom.TaskBarContainer.newBuilder();
+
+ if (hotseat.hasIndex()) {
+ taskbarBuilder.setIndex(hotseat.getIndex());
+ }
+
+ itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
+ .setTaskBarContainer(taskbarBuilder));
+ } else if (oldContainer.hasFolder() && oldContainer.getFolder().hasHotseat()) {
+ LauncherAtom.FolderContainer.Builder folderBuilder = oldContainer.getFolder()
+ .toBuilder();
+ LauncherAtom.HotseatContainer hotseat = folderBuilder.getHotseat();
+ LauncherAtom.TaskBarContainer.Builder taskbarBuilder =
+ LauncherAtom.TaskBarContainer.newBuilder();
+
+ if (hotseat.hasIndex()) {
+ taskbarBuilder.setIndex(hotseat.getIndex());
+ }
+
+ folderBuilder.setTaskbar(taskbarBuilder);
+ folderBuilder.clearHotseat();
+ itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
+ .setFolder(folderBuilder));
+ }
+ }
+
+ /**
* Sets a new data-source for this taskbar instance
*/
public void setUIController(@NonNull TaskbarUIController uiController) {
@@ -326,6 +384,7 @@
getDragLayer().post(() -> {
folder.animateOpen();
+ getStatsLogManager().logger().withItemInfo(folder.mInfo).log(LAUNCHER_FOLDER_OPEN);
folder.iterateOverItems((itemInfo, itemView) -> {
mControllers.taskbarViewController
@@ -363,6 +422,8 @@
getSystemService(LauncherApps.class).startMainActivity(
intent.getComponent(), info.user, intent.getSourceBounds(), null);
}
+
+ mControllers.uiController.onTaskbarIconLaunched(info);
} catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT)
.show();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index b89032e..1afbd17 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -34,6 +34,8 @@
import androidx.annotation.Nullable;
+import com.android.internal.logging.InstanceId;
+import com.android.internal.logging.InstanceIdSequence;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DragSource;
@@ -48,6 +50,7 @@
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.graphics.DragPreviewProvider;
import com.android.launcher3.icons.FastBitmapDrawable;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.systemui.shared.recents.model.Task;
@@ -284,10 +287,22 @@
}
if (clipDescription != null && intent != null) {
+ // Need to share the same InstanceId between launcher3 and WM Shell (internal).
+ InstanceId internalInstanceId = new InstanceIdSequence(
+ com.android.launcher3.logging.InstanceId.INSTANCE_ID_MAX).newInstanceId();
+ com.android.launcher3.logging.InstanceId launcherInstanceId =
+ new com.android.launcher3.logging.InstanceId(internalInstanceId.getId());
+
+ intent.putExtra(ClipDescription.EXTRA_LOGGING_INSTANCE_ID, internalInstanceId);
+
ClipData clipData = new ClipData(clipDescription, new ClipData.Item(intent));
if (btv.startDragAndDrop(clipData, shadowBuilder, null /* localState */,
View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_OPAQUE)) {
onSystemDragStarted();
+
+ mActivity.getStatsLogManager().logger().withItemInfo(mDragObject.dragInfo)
+ .withInstanceId(launcherInstanceId)
+ .log(StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DRAG_STARTED);
}
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index b7c5db2..10a5b89 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -135,8 +135,9 @@
} else if (!mControllers.uiController.isTaskbarTouchable()) {
// Let touches pass through us.
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
- } else if (mControllers.taskbarViewController.areIconsVisible()) {
- // Buttons are visible, take over the full taskbar area
+ } else if (mControllers.taskbarViewController.areIconsVisible()
+ || AbstractFloatingView.getOpenView(mActivity, TYPE_ALL) != null) {
+ // Taskbar has some touchable elements, take over the full taskbar area
insetsInfo.setTouchableInsets(mActivity.isTaskbarWindowFullscreen()
? TOUCHABLE_INSETS_FRAME : TOUCHABLE_INSETS_CONTENT);
} else {
@@ -155,7 +156,7 @@
* Called when a child is removed from TaskbarDragLayer.
*/
public void onDragLayerViewRemoved() {
- if (AbstractFloatingView.getOpenView(mActivity, TYPE_ALL) == null) {
+ if (AbstractFloatingView.getAnyView(mActivity, TYPE_ALL) == null) {
mActivity.setTaskbarWindowFullscreen(false);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 453bf1c..2e9d8bc 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -24,6 +24,7 @@
import android.content.ComponentCallbacks;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
@@ -41,6 +42,7 @@
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.SettingsCache;
+import com.android.launcher3.util.SimpleBroadcastReceiver;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.SystemUiProxy;
@@ -62,6 +64,7 @@
private final TaskbarNavButtonController mNavButtonController;
private final SettingsCache.OnChangeListener mUserSetupCompleteListener;
private final ComponentCallbacks mComponentCallbacks;
+ private final SimpleBroadcastReceiver mShutdownReceiver;
// The source for this provider is set when Launcher is available
private final ScopedUnfoldTransitionProgressProvider mUnfoldProgressProvider =
@@ -103,12 +106,14 @@
@Override
public void onLowMemory() { }
};
+ mShutdownReceiver = new SimpleBroadcastReceiver(i -> destroyExistingTaskbar());
mDisplayController.addChangeListener(this);
mSysUINavigationMode.addModeChangeListener(this);
SettingsCache.INSTANCE.get(mContext).register(USER_SETUP_COMPLETE_URI,
mUserSetupCompleteListener);
mContext.registerComponentCallbacks(mComponentCallbacks);
+ mShutdownReceiver.register(mContext, Intent.ACTION_SHUTDOWN);
recreateTaskbar();
}
@@ -231,6 +236,7 @@
SettingsCache.INSTANCE.get(mContext).unregister(USER_SETUP_COMPLETE_URI,
mUserSetupCompleteListener);
mContext.unregisterComponentCallbacks(mComponentCallbacks);
+ mContext.unregisterReceiver(mShutdownReceiver);
}
public @Nullable TaskbarActivityContext getCurrentActivityContext() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index fc277cc..a9ff03b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -41,6 +41,7 @@
public static final int FLAG_IN_APP = 1 << 0;
public static final int FLAG_STASHED_IN_APP = 1 << 1;
+ public static final int FLAG_IN_STASHED_LAUNCHER_STATE = 1 << 2;
/**
* How long to stash/unstash when manually invoked via long press.
@@ -83,9 +84,6 @@
private final int mStashedHeight;
private final int mUnstashedHeight;
- private final StatePropertyHolder mStatePropertyHolder = new StatePropertyHolder(
- flags -> (((flags & FLAG_IN_APP) != 0) && (flags & FLAG_STASHED_IN_APP) != 0));
-
// Initialized in init.
private TaskbarControllers mControllers;
// Taskbar background properties.
@@ -106,6 +104,18 @@
private @Nullable AnimatorSet mAnimator;
+ // Evaluate whether the handle should be stashed
+ private final StatePropertyHolder mStatePropertyHolder = new StatePropertyHolder(
+ flags -> {
+ if (!supportsStashing()) {
+ return false;
+ }
+ boolean inApp = (flags & FLAG_IN_APP) != 0;
+ boolean stashedInApp = (flags & FLAG_STASHED_IN_APP) != 0;
+ boolean stashedLauncherState = (flags & FLAG_IN_STASHED_LAUNCHER_STATE) != 0;
+ return (inApp && stashedInApp) || (!inApp && stashedLauncherState);
+ });
+
public TaskbarStashController(TaskbarActivityContext activity) {
mActivity = activity;
mPrefs = Utilities.getPrefs(mActivity);
@@ -331,7 +341,15 @@
}
public void applyState(long duration) {
- mStatePropertyHolder.setState(mState, duration);
+ mStatePropertyHolder.setState(mState, duration, true);
+ }
+
+ public Animator applyStateWithoutStart() {
+ return applyStateWithoutStart(TASKBAR_STASH_DURATION);
+ }
+
+ public Animator applyStateWithoutStart(long duration) {
+ return mStatePropertyHolder.setState(mState, duration, false);
}
/**
@@ -360,12 +378,16 @@
mStashCondition = stashCondition;
}
- public void setState(int flags, long duration) {
+ public Animator setState(int flags, long duration, boolean start) {
boolean isStashed = mStashCondition.test(flags);
if (mIsStashed != isStashed) {
mIsStashed = isStashed;
- createAnimToIsStashed(mIsStashed, duration).start();
+ Animator animator = createAnimToIsStashed(mIsStashed, duration);
+ if (start) {
+ animator.start();
+ }
}
+ return mAnimator;
}
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index c0312a0..d8360e0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -18,6 +18,7 @@
import android.graphics.Rect;
import com.android.launcher3.model.data.ItemInfoWithIcon;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
import java.util.stream.Stream;
@@ -43,4 +44,6 @@
public Stream<ItemInfoWithIcon> getAppIconsForEdu() {
return Stream.empty();
}
+
+ public void onTaskbarIconLaunched(WorkspaceItemInfo item) { }
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 2009cd7..3738dce 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -51,6 +51,7 @@
import com.android.launcher3.appprediction.PredictionRowView;
import com.android.launcher3.hybridhotseat.HotseatPredictionController;
import com.android.launcher3.logging.InstanceId;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.data.ItemInfo;
@@ -104,7 +105,8 @@
}
@Override
- protected void logAppLaunch(ItemInfo info, InstanceId instanceId) {
+ public void logAppLaunch(StatsLogManager statsLogManager, ItemInfo info,
+ InstanceId instanceId) {
// If the app launch is from any of the surfaces in AllApps then add the InstanceId from
// LiveSearchManager to recreate the AllApps session on the server side.
if (mAllAppsSessionLogId != null && ALL_APPS.equals(
@@ -112,8 +114,7 @@
instanceId = mAllAppsSessionLogId;
}
- StatsLogger logger = getStatsLogManager()
- .logger().withItemInfo(info).withInstanceId(instanceId);
+ StatsLogger logger = statsLogManager.logger().withItemInfo(info).withInstanceId(instanceId);
if (mAllAppsPredictions != null
&& (info.itemType == ITEM_TYPE_APPLICATION
diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java
deleted file mode 100644
index 0e12e30..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2018 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.plugins;
-
-import android.content.Context;
-
-import com.android.launcher3.Utilities;
-import com.android.systemui.shared.plugins.PluginInitializer;
-
-public class PluginInitializerImpl implements PluginInitializer {
- @Override
- public String[] getPrivilegedPlugins(Context context) {
- return new String[0];
- }
-
- @Override
- public void handleWtfs() {
- }
-
- public boolean isDebuggable() {
- return Utilities.IS_DEBUG_DEVICE;
- }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
index e12f42e..df0ac7c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
@@ -24,17 +24,19 @@
import android.content.Intent;
import android.content.pm.ResolveInfo;
+import com.android.launcher3.Utilities;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.shared.plugins.PluginInstanceManager;
+import com.android.systemui.shared.plugins.PluginActionManager;
+import com.android.systemui.shared.plugins.PluginInstance;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.shared.plugins.PluginManagerImpl;
import com.android.systemui.shared.plugins.PluginPrefs;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@@ -52,29 +54,36 @@
private PluginManagerWrapper(Context c) {
mContext = c;
- PluginInitializerImpl pluginInitializer = new PluginInitializerImpl();
mPluginEnabler = new PluginEnablerImpl(c);
- PluginInstanceManager.Factory instanceManagerFactory = new PluginInstanceManager.Factory(
- c, c.getPackageManager(), c.getMainExecutor(), MODEL_EXECUTOR, pluginInitializer,
+ List<String> privilegedPlugins = Collections.emptyList();
+ PluginInstance.Factory instanceFactory = new PluginInstance.Factory(
+ getClass().getClassLoader(), new PluginInstance.InstanceFactory<>(),
+ new PluginInstance.VersionChecker(), privilegedPlugins,
+ Utilities.IS_DEBUG_DEVICE);
+ PluginActionManager.Factory instanceManagerFactory = new PluginActionManager.Factory(
+ c, c.getPackageManager(), c.getMainExecutor(), MODEL_EXECUTOR,
c.getSystemService(NotificationManager.class), mPluginEnabler,
- Arrays.asList(pluginInitializer.getPrivilegedPlugins(c)));
+ privilegedPlugins, instanceFactory);
mPluginManager = new PluginManagerImpl(c, instanceManagerFactory,
- pluginInitializer.isDebuggable(),
+ Utilities.IS_DEBUG_DEVICE,
Optional.ofNullable(Thread.getDefaultUncaughtExceptionHandler()), mPluginEnabler,
- new PluginPrefs(c), Arrays.asList(pluginInitializer.getPrivilegedPlugins(c)));
+ new PluginPrefs(c), privilegedPlugins);
}
public PluginEnablerImpl getPluginEnabler() {
return mPluginEnabler;
}
- public void addPluginListener(PluginListener<? extends Plugin> listener, Class<?> pluginClass) {
+ /** */
+ public <T extends Plugin> void addPluginListener(
+ PluginListener<T> listener, Class<T> pluginClass) {
addPluginListener(listener, pluginClass, false);
}
- public void addPluginListener(PluginListener<? extends Plugin> listener, Class<?> pluginClass,
- boolean allowMultiple) {
+ /** */
+ public <T extends Plugin> void addPluginListener(
+ PluginListener<T> listener, Class<T> pluginClass, boolean allowMultiple) {
mPluginManager.addPluginListener(listener, pluginClass, allowMultiple);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 1302ac0..d396018 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -97,6 +97,11 @@
}
@Override
+ public boolean isTaskbarStashed() {
+ return true;
+ }
+
+ @Override
public int getWorkspaceScrimColor(Launcher launcher) {
return Themes.getAttrColor(launcher, R.attr.overviewScrimColor);
}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 1e841da..47c865f 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -65,7 +65,6 @@
import android.os.Build;
import android.os.IBinder;
import android.os.SystemClock;
-import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnApplyWindowInsetsListener;
@@ -88,7 +87,6 @@
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulActivity;
-import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.tracing.InputConsumerProto;
import com.android.launcher3.tracing.SwipeHandlerProto;
import com.android.launcher3.util.TraceHelper;
@@ -270,7 +268,7 @@
TaskAnimationManager taskAnimationManager, GestureState gestureState,
long touchTimeMs, boolean continuingLastGesture,
InputConsumerController inputConsumer) {
- super(context, deviceState, gestureState, new TransformParams());
+ super(context, deviceState, gestureState);
mActivityInterface = gestureState.getActivityInterface();
mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit);
mInputConsumerProxy =
@@ -883,9 +881,6 @@
*/
@UiThread
public void onGestureEnded(float endVelocity, PointF velocity, PointF downPos) {
- if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
- Log.d(TestProtocol.L3_SWIPE_TO_HOME, "3");
- }
float flingThreshold = mContext.getResources()
.getDimension(R.dimen.quickstep_fling_threshold_speed);
boolean isFling = mGestureStarted && !mIsMotionPaused
@@ -1048,9 +1043,6 @@
@UiThread
private void handleNormalGestureEnd(float endVelocity, boolean isFling, PointF velocity,
boolean isCancel) {
- if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
- Log.d(TestProtocol.L3_SWIPE_TO_HOME, "4");
- }
long duration = MAX_SWIPE_DURATION;
float currentShift = mCurrentShift.value;
final GestureEndTarget endTarget = calculateEndTarget(velocity, endVelocity,
@@ -1169,9 +1161,6 @@
@UiThread
private void animateToProgress(float start, float end, long duration, Interpolator interpolator,
GestureEndTarget target, PointF velocityPxPerMs) {
- if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
- Log.d(TestProtocol.L3_SWIPE_TO_HOME, "5");
- }
runOnRecentsAnimationStart(() -> animateToProgressInternal(start, end, duration,
interpolator, target, velocityPxPerMs));
}
@@ -1222,9 +1211,6 @@
}
}
- if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
- Log.d(TestProtocol.L3_SWIPE_TO_HOME, "7, end target=" + mGestureState.getEndTarget());
- }
if (mGestureState.getEndTarget() == HOME) {
getOrientationHandler().adjustFloatingIconStartVelocity(velocityPxPerMs);
final RemoteAnimationTargetCompat runningTaskTarget = mRecentsAnimationTargets != null
@@ -1239,9 +1225,6 @@
&& runningTaskTarget.allowEnterPip
&& runningTaskTarget.taskInfo.pictureInPictureParams != null
&& runningTaskTarget.taskInfo.pictureInPictureParams.isAutoEnterEnabled();
- if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
- Log.d(TestProtocol.L3_SWIPE_TO_HOME, "8, class=" + getClass().getSimpleName());
- }
HomeAnimationFactory homeAnimFactory =
createHomeAnimationFactory(cookies, duration, isTranslucent, appCanEnterPip,
runningTaskTarget);
@@ -1840,9 +1823,6 @@
* be run when it is next started.
*/
protected void runOnRecentsAnimationStart(Runnable action) {
- if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
- Log.d(TestProtocol.L3_SWIPE_TO_HOME, "6");
- }
if (mRecentsAnimationTargets == null) {
mRecentsAnimationStartCallbacks.add(action);
} else {
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index 80ae65e..c1b45e0 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -45,7 +45,6 @@
import android.os.Messenger;
import android.os.ParcelUuid;
import android.os.UserHandle;
-import android.util.Log;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
@@ -58,7 +57,6 @@
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.SpringAnimationBuilder;
-import com.android.launcher3.testing.TestProtocol;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsState;
import com.android.quickstep.util.AppCloseConfig;
@@ -141,10 +139,6 @@
mActiveAnimationFactory = new FallbackHomeAnimationFactory(duration);
ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
Intent intent = new Intent(mGestureState.getHomeIntent());
- if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
- Log.d(TestProtocol.L3_SWIPE_TO_HOME,
- "createHomeAnimationFactory: " + intent.toShortString(true, true, true, false));
- }
mActiveAnimationFactory.addGestureContract(intent);
try {
mContext.startActivity(intent, options.toBundle());
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 3c05a3e..e948221 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -20,14 +20,12 @@
import android.graphics.Rect;
import android.util.ArraySet;
-import android.util.Log;
import android.view.RemoteAnimationTarget;
import androidx.annotation.BinderThread;
import androidx.annotation.UiThread;
import com.android.launcher3.Utilities;
-import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.Preconditions;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
@@ -97,9 +95,6 @@
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
Rect homeContentInsets, Rect minimizedHomeBounds) {
- if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
- Log.d(TestProtocol.L3_SWIPE_TO_HOME, "RecentsAnimationCallbacks.onAnimationStart");
- }
// Convert appTargets to type RemoteAnimationTarget for all apps except Home app
RemoteAnimationTarget[] nonHomeApps = Arrays.stream(appTargets)
.filter(remoteAnimationTarget ->
@@ -121,10 +116,6 @@
mController::finishAnimationToApp);
} else {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
- if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
- Log.d(TestProtocol.L3_SWIPE_TO_HOME,
- "RecentsAnimationCallbacks.onAnimationStart callback");
- }
for (RecentsAnimationListener listener : getListeners()) {
listener.onRecentsAnimationStart(mController, targets);
}
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index 51a491e..d188018 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -80,7 +80,7 @@
protected boolean mIsSwipeForStagedSplit;
public SwipeUpAnimationLogic(Context context, RecentsAnimationDeviceState deviceState,
- GestureState gestureState, TransformParams transformParams) {
+ GestureState gestureState) {
mContext = context;
mDeviceState = deviceState;
mGestureState = gestureState;
@@ -89,13 +89,13 @@
LauncherSplitScreenListener.INSTANCE.getNoCreate()
.getRunningSplitTaskIds().length > 1;
- TaskViewSimulator primaryTVS = new TaskViewSimulator(context,
- gestureState.getActivityInterface());
- primaryTVS.getOrientationState().update(
- mDeviceState.getRotationTouchHelper().getCurrentActiveRotation(),
- mDeviceState.getRotationTouchHelper().getDisplayRotation());
mTargetGluer = new RemoteTargetGluer(mContext, mGestureState.getActivityInterface());
mRemoteTargetHandles = mTargetGluer.getRemoteTargetHandles();
+ runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTaskViewSimulator().getOrientationState().update(
+ mDeviceState.getRotationTouchHelper().getCurrentActiveRotation(),
+ mDeviceState.getRotationTouchHelper().getDisplayRotation()
+ ));
}
protected void initTransitionEndpoints(DeviceProfile dp) {
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index e6285f2..725c7c4 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -50,7 +50,6 @@
import androidx.annotation.UiThread;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.tracing.InputConsumerProto;
@@ -357,9 +356,6 @@
}
case ACTION_CANCEL:
case ACTION_UP: {
- if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
- Log.d(TestProtocol.L3_SWIPE_TO_HOME, "1");
- }
if (DEBUG_FAILED_QUICKSWITCH && !mPassedWindowMoveSlop) {
float displacementX = mLastPos.x - mDownPos.x;
float displacementY = mLastPos.y - mDownPos.y;
@@ -413,9 +409,6 @@
* the animation can still be running.
*/
private void finishTouchTracking(MotionEvent ev) {
- if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
- Log.d(TestProtocol.L3_SWIPE_TO_HOME, "2");
- }
Object traceToken = TraceHelper.INSTANCE.beginSection(UP_EVT,
FLAG_CHECK_FOR_RACE_CONDITIONS);
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index 1f75936..ce8047e 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -50,6 +50,7 @@
import com.android.quickstep.GestureState;
import com.android.quickstep.OverviewComponentObserver;
import com.android.quickstep.RecentsAnimationDeviceState;
+import com.android.quickstep.RemoteTargetGluer;
import com.android.quickstep.SwipeUpAnimationLogic;
import com.android.quickstep.SwipeUpAnimationLogic.RunningWindowAnim;
import com.android.quickstep.util.AppCloseConfig;
@@ -254,7 +255,9 @@
ViewSwipeUpAnimation(Context context, RecentsAnimationDeviceState deviceState,
GestureState gestureState) {
- super(context, deviceState, gestureState, new FakeTransformParams());
+ super(context, deviceState, gestureState);
+ mRemoteTargetHandles[0] = new RemoteTargetGluer.RemoteTargetHandle(
+ mRemoteTargetHandles[0].getTaskViewSimulator(), new FakeTransformParams());
}
void initDp(DeviceProfile dp) {
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index 6575996..676161e 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -31,9 +31,11 @@
import android.content.Context;
import android.util.Log;
+import android.util.StatsEvent;
import android.view.View;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import androidx.slice.SliceItem;
@@ -56,6 +58,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.LogConfig;
+import com.android.launcher3.views.ActivityContext;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.SysUiStatsLog;
@@ -97,7 +100,7 @@
@Override
protected StatsLogger createLogger() {
- return new StatsCompatLogger(mContext);
+ return new StatsCompatLogger(mContext, mActivityContext);
}
/**
@@ -135,13 +138,44 @@
}
/**
+ * Builds {@link StatsEvent} from {@link LauncherAtom.ItemInfo}. Used for pulled atom callback
+ * implementation.
+ */
+ public static StatsEvent buildStatsEvent(LauncherAtom.ItemInfo info,
+ @Nullable InstanceId instanceId) {
+ return SysUiStatsLog.buildStatsEvent(
+ SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT, // atom ID,
+ LAUNCHER_WORKSPACE_SNAPSHOT.getId(), // event_id = 1;
+ info.getAttribute().getNumber() * ATTRIBUTE_MULTIPLIER
+ + info.getItemCase().getNumber(), // item_id = 2;
+ instanceId == null ? 0 : instanceId.getId(), //instance_id = 3;
+ 0, //uid = 4 [(is_uid) = true];
+ getPackageName(info), // package_name = 5;
+ getComponentName(info), // component_name = 6;
+ getGridX(info, false), //grid_x = 7 [default = -1];
+ getGridY(info, false), //grid_y = 8 [default = -1];
+ getPageId(info), // page_id = 9 [default = -2];
+ getGridX(info, true), //grid_x_parent = 10 [default = -1];
+ getGridY(info, true), //grid_y_parent = 11 [default = -1];
+ getParentPageId(info), //page_id_parent = 12 [default = -2];
+ getHierarchy(info), // container_id = 13;
+ info.getIsWork(), // is_work_profile = 14;
+ info.getAttribute().getNumber(), // attribute_id = 15;
+ getCardinality(info), // cardinality = 16;
+ info.getWidget().getSpanX(), // span_x = 17 [default = 1];
+ info.getWidget().getSpanY() // span_y = 18 [default = 1];
+ );
+ }
+
+ /**
* Helps to construct and write statsd compatible log message.
*/
private static class StatsCompatLogger implements StatsLogger {
private static final ItemInfo DEFAULT_ITEM_INFO = new ItemInfo();
- private Context mContext;
+ private final Context mContext;
+ private final Optional<ActivityContext> mActivityContext;
private ItemInfo mItemInfo = DEFAULT_ITEM_INFO;
private InstanceId mInstanceId = DEFAULT_INSTANCE_ID;
private OptionalInt mRank = OptionalInt.empty();
@@ -154,8 +188,9 @@
private SliceItem mSliceItem;
private LauncherAtom.Slice mSlice;
- StatsCompatLogger(Context context) {
+ StatsCompatLogger(Context context, ActivityContext activityContext) {
mContext = context;
+ mActivityContext = Optional.ofNullable(activityContext);
}
@Override
@@ -307,6 +342,9 @@
mRank.ifPresent(itemInfoBuilder::setRank);
mContainerInfo.ifPresent(itemInfoBuilder::setContainerInfo);
+ mActivityContext.ifPresent(activityContext ->
+ activityContext.applyOverwritesToLogItem(itemInfoBuilder));
+
if (mFromState.isPresent() || mToState.isPresent() || mEditText.isPresent()) {
FolderIcon.Builder folderIconBuilder = itemInfoBuilder
.getFolderIcon()
@@ -375,6 +413,8 @@
switch (info.getContainerInfo().getContainerCase()) {
case PREDICTED_HOTSEAT_CONTAINER:
return info.getContainerInfo().getPredictedHotseatContainer().getCardinality();
+ case TASK_BAR_CONTAINER:
+ return info.getContainerInfo().getTaskBarContainer().getCardinality();
case SEARCH_RESULT_CONTAINER:
return info.getContainerInfo().getSearchResultContainer().getQueryLength();
case EXTENDED_CONTAINERS:
@@ -461,6 +501,8 @@
return info.getContainerInfo().getHotseat().getIndex();
case PREDICTED_HOTSEAT_CONTAINER:
return info.getContainerInfo().getPredictedHotseatContainer().getIndex();
+ case TASK_BAR_CONTAINER:
+ return info.getContainerInfo().getTaskBarContainer().getIndex();
default:
return info.getContainerInfo().getWorkspace().getPageIndex();
}
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index ccc587c..44396fa 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -197,7 +197,7 @@
launcher.getStateManager().createAtomicAnimation(BACKGROUND_APP, NORMAL, config).start();
// Stop scrolling so that it doesn't interfere with the translation offscreen.
- launcher.<RecentsView>getOverviewPanel().getScroller().forceFinished(true);
+ launcher.<RecentsView>getOverviewPanel().forceFinishScroller();
if (animateOverviewScrim) {
launcher.getWorkspace().getStateTransitionAnimation()
diff --git a/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java b/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java
index df94d0b..7ae6cb7 100644
--- a/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java
+++ b/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java
@@ -120,7 +120,7 @@
launcher.getStateManager().createAtomicAnimation(BACKGROUND_APP, NORMAL, config).start();
// Stop scrolling so that it doesn't interfere with the translation offscreen.
- launcher.<RecentsView>getOverviewPanel().getScroller().forceFinished(true);
+ launcher.<RecentsView>getOverviewPanel().forceFinishScroller();
if (animateOverviewScrim) {
launcher.getWorkspace().getStateTransitionAnimation()
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 8562719..16303f3 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -31,6 +31,7 @@
private Task mSecondaryTask;
private TaskThumbnailView mSnapshotView2;
private CancellableTask mThumbnailLoadRequest2;
+ private SplitConfigurationOptions.StagedSplitBounds mSplitBoundsConfig;
public GroupedTaskView(Context context) {
super(context);
@@ -57,7 +58,7 @@
mTaskIdContainer[1] = secondary.key.id;
mTaskIdAttributeContainer[1] = new TaskIdAttributeContainer(secondary, mSnapshotView2);
mSnapshotView2.bind(secondary);
- adjustThumbnailBoundsForSplit(splitBoundsConfig, orientedState);
+ mSplitBoundsConfig = splitBoundsConfig;
}
@Override
@@ -121,6 +122,21 @@
public void onRecycle() {
super.onRecycle();
mSnapshotView2.setThumbnail(mSecondaryTask, null);
+ mSplitBoundsConfig = null;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+ setMeasuredDimension(widthSize, heightSize);
+ if (mSplitBoundsConfig == null || mSnapshotView == null || mSnapshotView2 == null) {
+ return;
+ }
+ getPagedOrientationHandler().measureGroupedTaskViewThumbnailBounds(mSnapshotView,
+ mSnapshotView2, widthSize, heightSize, mSplitBoundsConfig,
+ mActivity.getDeviceProfile());
}
@Override
@@ -128,16 +144,4 @@
super.setOverlayEnabled(overlayEnabled);
mSnapshotView2.setOverlayEnabled(overlayEnabled);
}
-
- private void adjustThumbnailBoundsForSplit(
- SplitConfigurationOptions.StagedSplitBounds splitBoundsConfig,
- RecentsOrientedState orientedState) {
- if (splitBoundsConfig == null) {
- return;
- }
-
- orientedState.getOrientationHandler().setGroupedTaskViewThumbnailBounds(
- mSnapshotView, mSnapshotView2, this, splitBoundsConfig,
- mActivity.getDeviceProfile());
- }
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index dd470e8..5fa95f4 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -2059,10 +2059,10 @@
int runningIndex = getCurrentPage();
AnimatorSet as = new AnimatorSet();
for (int i = 0; i < getTaskViewCount(); i++) {
- if (runningIndex == i) {
+ View taskView = getTaskViewAt(i);
+ if (runningIndex == i && taskView.getAlpha() != 0) {
continue;
}
- View taskView = getTaskViewAt(i);
as.play(ObjectAnimator.ofFloat(taskView, View.ALPHA, fadeInChildren ? 0 : 1));
}
return as;
@@ -3150,7 +3150,7 @@
*/
private void updateFocusedSplitButtonVisibility() {
mActionsView.setSplitButtonVisible(mActivity.getDeviceProfile().isTablet &&
- !(getRunningTaskView() instanceof GroupedTaskView) &&
+ !(getFocusedTaskView() instanceof GroupedTaskView) &&
getTaskViewCount() > 1
);
}
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 45e7e69..cba4833 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -42,7 +42,6 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.RemoteException;
-import android.util.Log;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -56,7 +55,6 @@
import com.android.launcher3.tapl.OverviewTask;
import com.android.launcher3.tapl.TestHelpers;
import com.android.launcher3.testcomponent.TestCommandReceiver;
-import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.FailureWatcher;
import com.android.quickstep.views.RecentsView;
@@ -188,15 +186,9 @@
protected <T> T getFromRecents(Function<RecentsActivity, T> f) {
if (!TestHelpers.isInLauncherProcess()) return null;
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.FALLBACK_ACTIVITY_NO_SET, "getFromRecents");
- }
Object[] result = new Object[1];
Wait.atMost("Failed to get from recents", () -> MAIN_EXECUTOR.submit(() -> {
RecentsActivity activity = RecentsActivity.ACTIVITY_TRACKER.getCreatedActivity();
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.FALLBACK_ACTIVITY_NO_SET, "activity=" + activity);
- }
if (activity == null) {
return false;
}
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index e080537..e3cfb59 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -195,10 +195,24 @@
}
/**
- * Returns a view matching FloatingViewType
+ * Returns a view matching FloatingViewType and {@link #isOpen()} == true.
*/
public static <T extends AbstractFloatingView> T getOpenView(
ActivityContext activity, @FloatingViewType int type) {
+ return getView(activity, type, true /* mustBeOpen */);
+ }
+
+ /**
+ * Returns a view matching FloatingViewType, and {@link #isOpen()} may be false (if animating
+ * closed).
+ */
+ public static <T extends AbstractFloatingView> T getAnyView(
+ ActivityContext activity, @FloatingViewType int type) {
+ return getView(activity, type, false /* mustBeOpen */);
+ }
+
+ private static <T extends AbstractFloatingView> T getView(
+ ActivityContext activity, @FloatingViewType int type, boolean mustBeOpen) {
BaseDragLayer dragLayer = activity.getDragLayer();
if (dragLayer == null) return null;
// Iterate in reverse order. AbstractFloatingView is added later to the dragLayer,
@@ -207,7 +221,7 @@
View child = dragLayer.getChildAt(i);
if (child instanceof AbstractFloatingView) {
AbstractFloatingView view = (AbstractFloatingView) child;
- if (view.isOfType(type) && view.isOpen()) {
+ if (view.isOfType(type) && (!mustBeOpen || view.isOpen())) {
return (T) view;
}
}
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 2c76e52..7954011 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -55,6 +55,7 @@
import com.android.launcher3.allapps.search.SearchAdapterProvider;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.touch.ItemClickHandler;
@@ -224,7 +225,7 @@
}
if (item != null) {
InstanceId instanceId = new InstanceIdSequence().newInstanceId();
- logAppLaunch(item, instanceId);
+ logAppLaunch(getStatsLogManager(), item, instanceId);
}
return true;
} catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
@@ -234,8 +235,12 @@
return false;
}
- protected void logAppLaunch(ItemInfo info, InstanceId instanceId) {
- getStatsLogManager().logger().withItemInfo(info).withInstanceId(instanceId)
+ /**
+ * Creates and logs a new app launch event.
+ */
+ public void logAppLaunch(StatsLogManager statsLogManager, ItemInfo info,
+ InstanceId instanceId) {
+ statsLogManager.logger().withItemInfo(info).withInstanceId(instanceId)
.log(LAUNCHER_APP_LAUNCH_TAP);
}
diff --git a/src/com/android/launcher3/ExtendedEditText.java b/src/com/android/launcher3/ExtendedEditText.java
index 21bc479..92432a8 100644
--- a/src/com/android/launcher3/ExtendedEditText.java
+++ b/src/com/android/launcher3/ExtendedEditText.java
@@ -26,7 +26,6 @@
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.views.ActivityContext;
@@ -99,18 +98,6 @@
}
}
- /**
- * Sets whether EditText background should be visible
- * @param maxAlpha defines the maximum alpha the background should animates to
- */
- public void setBackgroundVisibility(boolean visible, float maxAlpha) {}
-
- /**
- * Returns whether a visible background is set on EditText
- */
- public boolean getBackgroundVisibility() {
- return getBackground() != null;
- }
public void showKeyboard() {
mShowImeAfterFirstLayout = !showSoftInput();
@@ -150,9 +137,6 @@
if (!TextUtils.isEmpty(getText())) {
setText("");
}
- if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
- return;
- }
if (isFocused()) {
View nextFocus = focusSearch(View.FOCUS_DOWN);
if (nextFocus != null) {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index ed9f044..85dd3b3 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -87,6 +87,7 @@
import android.os.Process;
import android.os.StrictMode;
import android.os.SystemClock;
+import android.os.Trace;
import android.text.TextUtils;
import android.text.method.TextKeyListener;
import android.util.Log;
@@ -280,6 +281,11 @@
private static final int THEME_CROSS_FADE_ANIMATION_DURATION = 375;
+ private static final String DISPLAY_WORKSPACE_TRACE_METHOD_NAME = "DisplayWorkspaceFirstFrame";
+ private static final String DISPLAY_ALL_APPS_TRACE_METHOD_NAME = "DisplayAllApps";
+ public static final int DISPLAY_WORKSPACE_TRACE_COOKIE = 0;
+ public static final int DISPLAY_ALL_APPS_TRACE_COOKIE = 1;
+
private Configuration mOldConfig;
@Thunk
@@ -366,7 +372,15 @@
private LauncherState mPrevLauncherState;
@Override
+ @TargetApi(Build.VERSION_CODES.S)
protected void onCreate(Bundle savedInstanceState) {
+ // Only use a hard-coded cookie since we only want to trace this once.
+ if (Utilities.ATLEAST_S) {
+ Trace.beginAsyncSection(
+ DISPLAY_WORKSPACE_TRACE_METHOD_NAME, DISPLAY_WORKSPACE_TRACE_COOKIE);
+ Trace.beginAsyncSection(DISPLAY_ALL_APPS_TRACE_METHOD_NAME,
+ DISPLAY_ALL_APPS_TRACE_COOKIE);
+ }
Object traceToken = TraceHelper.INSTANCE.beginSection(ON_CREATE_EVT,
TraceHelper.FLAG_UI_EVENT);
if (DEBUG_STRICT_MODE) {
@@ -2584,6 +2598,7 @@
}
@Override
+ @TargetApi(Build.VERSION_CODES.S)
public void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks) {
mSynchronouslyBoundPages = boundPages;
mPagesToBindSynchronously = new IntSet();
@@ -2606,6 +2621,10 @@
executor.onLoadAnimationCompleted();
}
executor.attachTo(this);
+ if (Utilities.ATLEAST_S) {
+ Trace.endAsyncSection(DISPLAY_WORKSPACE_TRACE_METHOD_NAME,
+ DISPLAY_WORKSPACE_TRACE_COOKIE);
+ }
}
/**
@@ -2669,9 +2688,14 @@
* Implementation of the method from LauncherModel.Callbacks.
*/
@Override
+ @TargetApi(Build.VERSION_CODES.S)
public void bindAllApplications(AppInfo[] apps, int flags) {
mAppsView.getAppsStore().setApps(apps, flags);
PopupContainerWithArrow.dismissInvalidPopup(this);
+ if (Utilities.ATLEAST_S) {
+ Trace.endAsyncSection(DISPLAY_ALL_APPS_TRACE_METHOD_NAME,
+ DISPLAY_ALL_APPS_TRACE_COOKIE);
+ }
}
/**
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 86217d7..10023b4 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -138,10 +138,11 @@
mContext = context;
mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(context);
- mIconProvider = new IconProvider(context, Themes.isThemedIconEnabled(context));
+ mIconProvider = new IconProvider(context, Themes.isThemedIconEnabled(context));
mIconCache = new IconCache(mContext, mInvariantDeviceProfile,
iconCacheFileName, mIconProvider);
- mModel = new LauncherModel(context, this, mIconCache, new AppFilter(mContext));
+ mModel = new LauncherModel(context, this, mIconCache, new AppFilter(mContext),
+ iconCacheFileName != null);
mOnTerminateCallback.add(mIconCache::close);
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 9ebec0a..f38f662 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -126,10 +126,12 @@
}
};
- LauncherModel(Context context, LauncherAppState app, IconCache iconCache, AppFilter appFilter) {
+ LauncherModel(Context context, LauncherAppState app, IconCache iconCache, AppFilter appFilter,
+ boolean isPrimaryInstance) {
mApp = app;
mBgAllAppsList = new AllAppsList(iconCache, appFilter);
- mModelDelegate = ModelDelegate.newInstance(context, app, mBgAllAppsList, mBgDataModel);
+ mModelDelegate = ModelDelegate.newInstance(context, app, mBgAllAppsList, mBgDataModel,
+ isPrimaryInstance);
}
public ModelDelegate getModelDelegate() {
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index d663480..03e4ee7 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -199,6 +199,7 @@
public static final int CONTAINER_WIDGETS_TRAY = -105;
public static final int CONTAINER_BOTTOM_WIDGETS_TRAY = -112;
public static final int CONTAINER_PIN_WIDGETS = -113;
+ public static final int CONTAINER_WALLPAPERS = -114;
// Represents search results view.
public static final int CONTAINER_SEARCH_RESULTS = -106;
public static final int CONTAINER_SHORTCUTS = -107;
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 7985ab5..15378e0 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -197,6 +197,10 @@
return (getVisibleElements(launcher) & elements) == elements;
}
+ public boolean isTaskbarStashed() {
+ return false;
+ }
+
/**
* Fraction shift in the vertical translation UI and related properties
*
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 108091c..a7198a8 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -254,7 +254,7 @@
}
mOrientationHandler.set(this, VIEW_SCROLL_TO, newPosition);
mScroller.startScroll(mScroller.getCurrX(), 0, newPosition - mScroller.getCurrX(), 0);
- forceFinishScroller(true);
+ forceFinishScroller();
}
/**
@@ -276,14 +276,16 @@
}
}
- private void forceFinishScroller(boolean resetNextPage) {
+ /**
+ * Immediately finishes any in-progress scroll, maintaining the current position. Also sets
+ * mNextPage = INVALID_PAGE and calls pageEndTransition().
+ */
+ public void forceFinishScroller() {
mScroller.forceFinished(true);
// We need to clean up the next page here to avoid computeScrollHelper from
// updating current page on the pass.
- if (resetNextPage) {
- mNextPage = INVALID_PAGE;
- pageEndTransition();
- }
+ mNextPage = INVALID_PAGE;
+ pageEndTransition();
}
private int validateNewPage(int newPage) {
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index e779ee8..ee5f7e4 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -59,7 +59,6 @@
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget.DragObject;
-import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.Insettable;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.R;
@@ -624,6 +623,9 @@
for (int i = 0; i < mAH.length; i++) {
mAH[i].padding.top = padding;
mAH[i].applyPadding();
+ if (mAH[i].recyclerView != null) {
+ mAH[i].recyclerView.scrollToTop();
+ }
}
mHeaderTop = mHeader.getTop();
}
@@ -639,6 +641,7 @@
public void onClearSearchResult() {
mIsSearching = false;
+ mHeader.setCollapsed(false);
rebindAdapters();
getActiveRecyclerView().scrollToTop();
}
@@ -814,14 +817,13 @@
invalidateHeader();
}
if (mSearchUiManager.getEditText() != null) {
- ExtendedEditText editText = mSearchUiManager.getEditText();
- boolean bgVisible = editText.getBackgroundVisibility();
+ boolean bgVisible = mSearchUiManager.getBackgroundVisibility();
if (scrolledOffset == 0 && !mIsSearching) {
bgVisible = true;
} else if (scrolledOffset > mHeaderThreshold) {
bgVisible = false;
}
- editText.setBackgroundVisibility(bgVisible, 1 - prog);
+ mSearchUiManager.setBackgroundVisibility(bgVisible, 1 - prog);
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index a0551f0..a6d8552 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -17,6 +17,7 @@
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT;
+import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
@@ -28,6 +29,7 @@
import android.animation.Animator.AnimatorListener;
import android.animation.ObjectAnimator;
import android.util.FloatProperty;
+import android.view.HapticFeedbackConstants;
import android.view.View;
import android.view.animation.Interpolator;
@@ -168,6 +170,11 @@
builder.add(anim);
setAlphas(toState, config, builder);
+
+ if (ALL_APPS.equals(toState) && mLauncher.isInState(NORMAL)) {
+ mLauncher.getAppsView().performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
+ HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+ }
}
public Animator createSpringAnimation(float... progressValues) {
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderRow.java b/src/com/android/launcher3/allapps/FloatingHeaderRow.java
index 9bf6043..6ff2132 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderRow.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderRow.java
@@ -47,6 +47,8 @@
/**
* Scrolls the content vertically.
+ * @param scroll scrolled distance in pixels for active recyclerview.
+ * @param isScrolledOut bool to determine if row is scrolled out of view
*/
void setVerticalScroll(int scroll, boolean isScrolledOut);
diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java
index 924a392..7478b53 100644
--- a/src/com/android/launcher3/allapps/SearchUiManager.java
+++ b/src/com/android/launcher3/allapps/SearchUiManager.java
@@ -49,6 +49,19 @@
ExtendedEditText getEditText();
/**
+ * Sets whether EditText background should be visible
+ * @param maxAlpha defines the maximum alpha the background should animates to
+ */
+ default void setBackgroundVisibility(boolean visible, float maxAlpha) {}
+
+ /**
+ * Returns whether a visible background is set on EditText
+ */
+ default boolean getBackgroundVisibility() {
+ return false;
+ }
+
+ /**
* sets highlight result's title
*/
default void setFocusedResultTitle(@Nullable CharSequence title) { }
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index f091262..382f7a7 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -147,6 +147,11 @@
public static final BooleanFlag ENABLE_THEMED_ICONS = getDebugFlag(
"ENABLE_THEMED_ICONS", true, "Enable themed icons on workspace");
+ public static final BooleanFlag ENABLE_BULK_WORKSPACE_ICON_LOADING = getDebugFlag(
+ "ENABLE_BULK_WORKSPACE_ICON_LOADING",
+ false,
+ "Enable loading workspace icons in bulk.");
+
// Keep as DeviceFlag for remote disable in emergency.
public static final BooleanFlag ENABLE_OVERVIEW_SELECTIONS = new DeviceFlag(
"ENABLE_OVERVIEW_SELECTIONS", true, "Show Select Mode button in Overview Actions");
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 1a468ae..60d6e83 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -19,6 +19,8 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static java.util.stream.Collectors.groupingBy;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -30,10 +32,15 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ShortcutInfo;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteException;
import android.graphics.drawable.Drawable;
import android.os.Process;
+import android.os.Trace;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
import androidx.annotation.NonNull;
@@ -47,6 +54,7 @@
import com.android.launcher3.icons.cache.CachingLogic;
import com.android.launcher3.icons.cache.HandlerRunnable;
import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.IconRequestInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -56,8 +64,13 @@
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.Preconditions;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
import java.util.function.Predicate;
import java.util.function.Supplier;
+import java.util.stream.Stream;
/**
* Cache of application icons. Icons can be made from any thread.
@@ -306,6 +319,87 @@
applyCacheEntry(entry, infoInOut);
}
+ /**
+ * Creates an sql cursor for a query of a set of ItemInfoWithIcon icons and titles.
+ *
+ * @param iconRequestInfos List of IconRequestInfos representing titles and icons to query.
+ * @param user UserHandle all the given iconRequestInfos share
+ * @param useLowResIcons whether we should exclude the icon column from the sql results.
+ */
+ private <T extends ItemInfoWithIcon> Cursor createBulkQueryCursor(
+ List<IconRequestInfo<T>> iconRequestInfos, UserHandle user, boolean useLowResIcons)
+ throws SQLiteException {
+ String[] queryParams = Stream.concat(
+ iconRequestInfos.stream()
+ .map(r -> r.itemInfo.getTargetComponent())
+ .filter(Objects::nonNull)
+ .distinct()
+ .map(ComponentName::flattenToString),
+ Stream.of(Long.toString(getSerialNumberForUser(user)))).toArray(String[]::new);
+ String componentNameQuery = TextUtils.join(
+ ",", Collections.nCopies(queryParams.length - 1, "?"));
+
+ return mIconDb.query(
+ useLowResIcons ? IconDB.COLUMNS_LOW_RES : IconDB.COLUMNS_HIGH_RES,
+ IconDB.COLUMN_COMPONENT
+ + " IN ( " + componentNameQuery + " )"
+ + " AND " + IconDB.COLUMN_USER + " = ?",
+ queryParams);
+ }
+
+ /**
+ * Load and fill icons requested in iconRequestInfos using a single bulk sql query.
+ */
+ public synchronized <T extends ItemInfoWithIcon> void getTitlesAndIconsInBulk(
+ List<IconRequestInfo<T>> iconRequestInfos) {
+ Map<Pair<UserHandle, Boolean>, List<IconRequestInfo<T>>> iconLoadSubsectionsMap =
+ iconRequestInfos.stream()
+ .collect(groupingBy(iconRequest ->
+ Pair.create(iconRequest.itemInfo.user, iconRequest.useLowResIcon)));
+
+ Trace.beginSection("loadIconsInBulk");
+ iconLoadSubsectionsMap.forEach((sectionKey, filteredList) -> {
+ Map<ComponentName, List<IconRequestInfo<T>>> duplicateIconRequestsMap =
+ filteredList.stream()
+ .collect(groupingBy(iconRequest ->
+ iconRequest.itemInfo.getTargetComponent()));
+
+ Trace.beginSection("loadIconSubsectionInBulk");
+ try (Cursor c = createBulkQueryCursor(
+ filteredList,
+ /* user = */ sectionKey.first,
+ /* useLowResIcons = */ sectionKey.second)) {
+ int componentNameColumnIndex = c.getColumnIndexOrThrow(IconDB.COLUMN_COMPONENT);
+ while (c.moveToNext()) {
+ ComponentName cn = ComponentName.unflattenFromString(
+ c.getString(componentNameColumnIndex));
+ List<IconRequestInfo<T>> duplicateIconRequests =
+ duplicateIconRequestsMap.get(cn);
+
+ if (cn != null) {
+ CacheEntry entry = cacheLocked(
+ cn,
+ /* user = */ sectionKey.first,
+ () -> duplicateIconRequests.get(0).launcherActivityInfo,
+ mLauncherActivityInfoCachingLogic,
+ c,
+ /* usePackageIcon= */ false,
+ /* useLowResIcons = */ sectionKey.second);
+
+ for (IconRequestInfo<T> iconRequest : duplicateIconRequests) {
+ applyCacheEntry(entry, iconRequest.itemInfo);
+ }
+ }
+ }
+ } catch (SQLiteException e) {
+ Log.d(TAG, "Error reading icon cache", e);
+ } finally {
+ Trace.endSection();
+ }
+ });
+ Trace.endSection();
+ }
+
/**
* Fill in {@param infoInOut} with the corresponding icon and label.
diff --git a/src/com/android/launcher3/logging/InstanceId.java b/src/com/android/launcher3/logging/InstanceId.java
index e720d75..3c4a644 100644
--- a/src/com/android/launcher3/logging/InstanceId.java
+++ b/src/com/android/launcher3/logging/InstanceId.java
@@ -36,10 +36,10 @@
*/
public final class InstanceId implements Parcelable {
// At most 20 bits: ~1m possibilities, ~0.5% probability of collision in 100 values
- static final int INSTANCE_ID_MAX = 1 << 20;
+ public static final int INSTANCE_ID_MAX = 1 << 20;
private final int mId;
- InstanceId(int id) {
+ public InstanceId(int id) {
mId = min(max(0, id), INSTANCE_ID_MAX);
}
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 5ed651f..d987212 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -33,6 +33,7 @@
import com.android.launcher3.logger.LauncherAtom.ToState;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.launcher3.views.ActivityContext;
/**
* Handles the user event logging in R+.
@@ -53,6 +54,9 @@
public static final int LAUNCHER_STATE_UNCHANGED = 5;
private InstanceId mInstanceId;
+
+ protected @Nullable ActivityContext mActivityContext = null;
+
/**
* Returns event enum based on the two state transition information when swipe
* gesture happens(to be removed during UserEventDispatcher cleanup).
@@ -281,6 +285,9 @@
@UiEvent(doc = "User tapped on the share button on overview")
LAUNCHER_OVERVIEW_ACTIONS_SHARE(582),
+ @UiEvent(doc = "User tapped on the split screen button on overview")
+ LAUNCHER_OVERVIEW_ACTIONS_SPLIT(895),
+
@UiEvent(doc = "User tapped on the close button in select mode")
LAUNCHER_SELECT_MODE_CLOSE(583),
@@ -505,7 +512,13 @@
LAUNCHER_TURN_OFF_WORK_APPS_TAP(839),
@UiEvent(doc = "Launcher item drop failed since there was not enough room on the screen.")
- LAUNCHER_ITEM_DROP_FAILED_INSUFFICIENT_SPACE(872);
+ LAUNCHER_ITEM_DROP_FAILED_INSUFFICIENT_SPACE(872),
+
+ @UiEvent(doc = "User long pressed on the taskbar background to hide the taskbar")
+ LAUNCHER_TASKBAR_LONGPRESS_HIDE(896),
+
+ @UiEvent(doc = "User long pressed on the taskbar gesture handle to show the taskbar")
+ LAUNCHER_TASKBAR_LONGPRESS_SHOW(897);
// ADD MORE
@@ -645,7 +658,7 @@
public StatsLogger logger() {
StatsLogger logger = createLogger();
if (mInstanceId != null) {
- return logger.withInstanceId(mInstanceId);
+ logger.withInstanceId(mInstanceId);
}
return logger;
}
@@ -668,7 +681,9 @@
* Creates a new instance of {@link StatsLogManager} based on provided context.
*/
public static StatsLogManager newInstance(Context context) {
- return Overrides.getObject(StatsLogManager.class,
+ StatsLogManager manager = Overrides.getObject(StatsLogManager.class,
context.getApplicationContext(), R.string.stats_log_manager_class);
+ manager.mActivityContext = ActivityContext.lookupContextNoThrow(context);
+ return manager;
}
}
diff --git a/src/com/android/launcher3/model/DeviceGridState.java b/src/com/android/launcher3/model/DeviceGridState.java
index 1076e88..0fc4c2d 100644
--- a/src/com/android/launcher3/model/DeviceGridState.java
+++ b/src/com/android/launcher3/model/DeviceGridState.java
@@ -25,11 +25,15 @@
import android.content.SharedPreferences;
import android.text.TextUtils;
+import androidx.annotation.IntDef;
+
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
import com.android.launcher3.util.IntSet;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Locale;
import java.util.Objects;
@@ -42,14 +46,23 @@
public static final String KEY_HOTSEAT_COUNT = "migration_src_hotseat_count";
public static final String KEY_DEVICE_TYPE = "migration_src_device_type";
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({TYPE_PHONE, TYPE_MULTI_DISPLAY, TYPE_TABLET})
+ public @interface DeviceType{}
public static final int TYPE_PHONE = 0;
public static final int TYPE_MULTI_DISPLAY = 1;
public static final int TYPE_TABLET = 2;
- public static final IntSet COMPATIBLE_TYPES = IntSet.wrap(TYPE_PHONE, TYPE_MULTI_DISPLAY);
+
+ private static final IntSet COMPATIBLE_TYPES = IntSet.wrap(TYPE_PHONE, TYPE_MULTI_DISPLAY);
+
+ public static boolean deviceTypeCompatible(@DeviceType int typeA, @DeviceType int typeB) {
+ return typeA == typeB
+ || (COMPATIBLE_TYPES.contains(typeA) && COMPATIBLE_TYPES.contains(typeB));
+ }
private final String mGridSizeString;
private final int mNumHotseat;
- private final int mDeviceType;
+ private final @DeviceType int mDeviceType;
public DeviceGridState(InvariantDeviceProfile idp) {
mGridSizeString = String.format(Locale.ENGLISH, "%d,%d", idp.numColumns, idp.numRows);
@@ -71,7 +84,7 @@
/**
* Returns the device type for the grid
*/
- public int getDeviceType() {
+ public @DeviceType int getDeviceType() {
return mDeviceType;
}
@@ -106,14 +119,23 @@
}
@Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- DeviceGridState that = (DeviceGridState) o;
- return mNumHotseat == that.mNumHotseat
- && (mDeviceType == that.mDeviceType
- || (COMPATIBLE_TYPES.contains(mDeviceType)
- && COMPATIBLE_TYPES.contains(that.mDeviceType)))
- && Objects.equals(mGridSizeString, that.mGridSizeString);
+ public String toString() {
+ return "DeviceGridState{"
+ + "mGridSizeString='" + mGridSizeString + '\''
+ + ", mNumHotseat=" + mNumHotseat
+ + ", mDeviceType=" + mDeviceType
+ + '}';
+ }
+
+ /**
+ * Returns true if the database from another DeviceGridState can be loaded into the current
+ * DeviceGridState without migration, or false otherwise.
+ */
+ public boolean isCompatible(DeviceGridState other) {
+ if (this == other) return true;
+ if (other == null) return false;
+ return mNumHotseat == other.mNumHotseat
+ && deviceTypeCompatible(mDeviceType, other.mDeviceType)
+ && Objects.equals(mGridSizeString, other.mGridSizeString);
}
}
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
index e7d0749..fc86cf8 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
@@ -103,7 +103,13 @@
* Check given a new IDP, if migration is necessary.
*/
public static boolean needsToMigrate(Context context, InvariantDeviceProfile idp) {
- return !new DeviceGridState(idp).equals(new DeviceGridState(context));
+ DeviceGridState idpGridState = new DeviceGridState(idp);
+ DeviceGridState contextGridState = new DeviceGridState(context);
+ boolean needsToMigrate = !idpGridState.isCompatible(contextGridState);
+ // TODO: Revert this change after b/200010396 is fixed
+ Log.d(TAG, "Migration is needed. idpGridState: " + idpGridState
+ + ", contextGridState: " + contextGridState);
+ return needsToMigrate;
}
/** See {@link #migrateGridIfNeeded(Context, InvariantDeviceProfile)} */
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 7e3bcee..8a5a9bf 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -16,13 +16,10 @@
package com.android.launcher3.model;
-import static android.graphics.BitmapFactory.decodeByteArray;
-
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
-import android.content.Intent.ShortcutIconResource;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
@@ -45,11 +42,10 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.IconRequestInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
@@ -184,32 +180,21 @@
* Loads the icon from the cursor and updates the {@param info} if the icon is an app resource.
*/
protected boolean loadIcon(WorkspaceItemInfo info) {
- try (LauncherIcons li = LauncherIcons.obtain(mContext)) {
- if (itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
- String packageName = getString(iconPackageIndex);
- String resourceName = getString(iconResourceIndex);
- if (!TextUtils.isEmpty(packageName) || !TextUtils.isEmpty(resourceName)) {
- info.iconResource = new ShortcutIconResource();
- info.iconResource.packageName = packageName;
- info.iconResource.resourceName = resourceName;
- BitmapInfo iconInfo = li.createIconBitmap(info.iconResource);
- if (iconInfo != null) {
- info.bitmap = iconInfo;
- return true;
- }
- }
- }
+ return createIconRequestInfo(info, false).loadWorkspaceIcon(mContext);
+ }
- // Failed to load from resource, try loading from DB.
- byte[] data = getBlob(iconIndex);
- try {
- info.bitmap = li.createIconBitmap(decodeByteArray(data, 0, data.length));
- return true;
- } catch (Exception e) {
- Log.e(TAG, "Failed to decode byte array for info " + info, e);
- return false;
- }
- }
+ public IconRequestInfo<WorkspaceItemInfo> createIconRequestInfo(
+ WorkspaceItemInfo wai, boolean useLowResIcon) {
+ String packageName = itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
+ ? getString(iconPackageIndex) : null;
+ String resourceName = itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
+ ? getString(iconResourceIndex) : null;
+ byte[] iconBlob = itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
+ || restoreFlag != 0
+ ? getBlob(iconIndex) : null;
+
+ return new IconRequestInfo<>(
+ wai, mActivityInfo, packageName, resourceName, iconBlob, useLowResIcon);
}
/**
@@ -262,6 +247,11 @@
*/
public WorkspaceItemInfo getAppShortcutInfo(
Intent intent, boolean allowMissingTarget, boolean useLowResIcon) {
+ return getAppShortcutInfo(intent, allowMissingTarget, useLowResIcon, true);
+ }
+
+ public WorkspaceItemInfo getAppShortcutInfo(
+ Intent intent, boolean allowMissingTarget, boolean useLowResIcon, boolean loadIcon) {
if (user == null) {
Log.d(TAG, "Null user found in getShortcutInfo");
return null;
@@ -288,9 +278,11 @@
info.user = user;
info.intent = newIntent;
- mIconCache.getTitleAndIcon(info, mActivityInfo, useLowResIcon);
- if (mIconCache.isDefaultIcon(info.bitmap, user)) {
- loadIcon(info);
+ if (loadIcon) {
+ mIconCache.getTitleAndIcon(info, mActivityInfo, useLowResIcon);
+ if (mIconCache.isDefaultIcon(info.bitmap, user)) {
+ loadIcon(info);
+ }
}
if (mActivityInfo != null) {
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index f4a0eb8..1249606 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -43,6 +43,7 @@
import android.graphics.Point;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
@@ -71,6 +72,7 @@
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.IconRequestInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -197,7 +199,12 @@
TimingLogger logger = new TimingLogger(TAG, "run");
try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
List<ShortcutInfo> allShortcuts = new ArrayList<>();
- loadWorkspace(allShortcuts);
+ Trace.beginSection("LoadWorkspace");
+ try {
+ loadWorkspace(allShortcuts);
+ } finally {
+ Trace.endSection();
+ }
logASplit(logger, "loadWorkspace");
// Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db.
@@ -225,7 +232,13 @@
verifyNotStopped();
// second step
- List<LauncherActivityInfo> allActivityList = loadAllApps();
+ Trace.beginSection("LoadAllApps");
+ List<LauncherActivityInfo> allActivityList;
+ try {
+ allActivityList = loadAllApps();
+ } finally {
+ Trace.endSection();
+ }
logASplit(logger, "loadAllApps");
verifyNotStopped();
@@ -408,6 +421,7 @@
LauncherAppWidgetProviderInfo widgetProviderInfo;
Intent intent;
String targetPkg;
+ List<IconRequestInfo<WorkspaceItemInfo>> iconRequestInfos = new ArrayList<>();
while (!mStopped && c.moveToNext()) {
try {
@@ -530,7 +544,10 @@
} else if (c.itemType ==
LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
info = c.getAppShortcutInfo(
- intent, allowMissingTarget, useLowResIcon);
+ intent,
+ allowMissingTarget,
+ useLowResIcon,
+ !FeatureFlags.ENABLE_BULK_WORKSPACE_ICON_LOADING.get());
} else if (c.itemType ==
LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
@@ -582,6 +599,8 @@
}
if (info != null) {
+ iconRequestInfos.add(c.createIconRequestInfo(info, useLowResIcon));
+
c.applyCommonProperties(info);
info.intent = intent;
@@ -799,6 +818,21 @@
Log.e(TAG, "Desktop items loading interrupted", e);
}
}
+ if (FeatureFlags.ENABLE_BULK_WORKSPACE_ICON_LOADING.get()) {
+ Trace.beginSection("LoadWorkspaceIconsInBulk");
+ try {
+ mIconCache.getTitlesAndIconsInBulk(iconRequestInfos);
+ for (IconRequestInfo<WorkspaceItemInfo> iconRequestInfo :
+ iconRequestInfos) {
+ WorkspaceItemInfo wai = iconRequestInfo.itemInfo;
+ if (mIconCache.isDefaultIcon(wai.bitmap, wai.user)) {
+ iconRequestInfo.loadWorkspaceIcon(mApp.getContext());
+ }
+ }
+ } finally {
+ Trace.endSection();
+ }
+ }
} finally {
IOUtils.closeSilently(c);
}
diff --git a/src/com/android/launcher3/model/ModelDelegate.java b/src/com/android/launcher3/model/ModelDelegate.java
index 13ec1ec..765141a 100644
--- a/src/com/android/launcher3/model/ModelDelegate.java
+++ b/src/com/android/launcher3/model/ModelDelegate.java
@@ -40,19 +40,21 @@
* Creates and initializes a new instance of the delegate
*/
public static ModelDelegate newInstance(
- Context context, LauncherAppState app, AllAppsList appsList, BgDataModel dataModel) {
+ Context context, LauncherAppState app, AllAppsList appsList, BgDataModel dataModel,
+ boolean isPrimaryInstance) {
ModelDelegate delegate = Overrides.getObject(
ModelDelegate.class, context, R.string.model_delegate_class);
-
delegate.mApp = app;
delegate.mAppsList = appsList;
delegate.mDataModel = dataModel;
+ delegate.mIsPrimaryInstance = isPrimaryInstance;
return delegate;
}
protected LauncherAppState mApp;
protected AllAppsList mAppsList;
protected BgDataModel mDataModel;
+ protected boolean mIsPrimaryInstance;
public ModelDelegate() { }
diff --git a/src/com/android/launcher3/model/data/IconRequestInfo.java b/src/com/android/launcher3/model/data/IconRequestInfo.java
new file mode 100644
index 0000000..2f566f6
--- /dev/null
+++ b/src/com/android/launcher3/model/data/IconRequestInfo.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2021 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.model.data;
+
+import static android.graphics.BitmapFactory.decodeByteArray;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.LauncherActivityInfo;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.LauncherIcons;
+
+/**
+ * Class representing one request for an icon to be queried in a sql database.
+ *
+ * @param <T> ItemInfoWithIcon subclass whose title and icon can be loaded and filled by an sql
+ * query.
+ */
+public class IconRequestInfo<T extends ItemInfoWithIcon> {
+
+ private static final String TAG = "IconRequestInfo";
+
+ @NonNull public final T itemInfo;
+ @Nullable public final LauncherActivityInfo launcherActivityInfo;
+ @Nullable public final String packageName;
+ @Nullable public final String resourceName;
+ @Nullable public final byte[] iconBlob;
+ public final boolean useLowResIcon;
+
+ public IconRequestInfo(
+ @NonNull T itemInfo,
+ @Nullable LauncherActivityInfo launcherActivityInfo,
+ @Nullable String packageName,
+ @Nullable String resourceName,
+ @Nullable byte[] iconBlob,
+ boolean useLowResIcon) {
+ this.itemInfo = itemInfo;
+ this.launcherActivityInfo = launcherActivityInfo;
+ this.packageName = packageName;
+ this.resourceName = resourceName;
+ this.iconBlob = iconBlob;
+ this.useLowResIcon = useLowResIcon;
+ }
+
+ /** Loads */
+ public boolean loadWorkspaceIcon(Context context) {
+ if (!(itemInfo instanceof WorkspaceItemInfo)) {
+ throw new IllegalStateException(
+ "loadWorkspaceIcon should only be use for a WorkspaceItemInfos: " + itemInfo);
+ }
+
+ try (LauncherIcons li = LauncherIcons.obtain(context)) {
+ WorkspaceItemInfo info = (WorkspaceItemInfo) itemInfo;
+ if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
+ if (!TextUtils.isEmpty(packageName) || !TextUtils.isEmpty(resourceName)) {
+ info.iconResource = new Intent.ShortcutIconResource();
+ info.iconResource.packageName = packageName;
+ info.iconResource.resourceName = resourceName;
+ BitmapInfo iconInfo = li.createIconBitmap(info.iconResource);
+ if (iconInfo != null) {
+ info.bitmap = iconInfo;
+ return true;
+ }
+ }
+ }
+
+ // Failed to load from resource, try loading from DB.
+ try {
+ if (iconBlob == null) {
+ return false;
+ }
+ info.bitmap = li.createIconBitmap(decodeByteArray(
+ iconBlob, 0, iconBlob.length));
+ return true;
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to decode byte array for info " + info, e);
+ return false;
+ }
+ }
+ }
+}
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 8d02a4a..d59429d 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -84,9 +84,10 @@
}
private static boolean performRestore(Context context, DatabaseHelper helper) {
- if (new DeviceGridState(LauncherAppState.getIDP(context)).getDeviceType()
- != Utilities.getPrefs(context).getInt(RESTORED_DEVICE_TYPE, TYPE_PHONE)) {
- // DO not restore if the device types are different
+ if (!DeviceGridState.deviceTypeCompatible(
+ new DeviceGridState(LauncherAppState.getIDP(context)).getDeviceType(),
+ Utilities.getPrefs(context).getInt(RESTORED_DEVICE_TYPE, TYPE_PHONE))) {
+ // DO NOT restore if the device types are incompatible.
return false;
}
SQLiteDatabase db = helper.getWritableDatabase();
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index 24d3fd4..b34af97 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -18,7 +18,6 @@
import static android.animation.ValueAnimator.areAnimatorsEnabled;
-import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.AnimatorPlaybackController.callListenerCommandRecursively;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_ALL_ANIMATIONS;
@@ -28,14 +27,12 @@
import android.animation.AnimatorSet;
import android.os.Handler;
import android.os.Looper;
-import android.util.Log;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
-import com.android.launcher3.testing.TestProtocol;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -256,9 +253,6 @@
if (listener != null) {
animation.addListener(listener);
}
- if (TestProtocol.sDebugTracing && state == NORMAL) {
- Log.d(TestProtocol.L3_SWIPE_TO_HOME, "goToStateAnimated: " + state);
- }
mUiHandler.post(new StartAnimRunnable(animation));
}
@@ -334,17 +328,11 @@
@Override
public void onAnimationStart(Animator animation) {
// Change the internal state only when the transition actually starts
- if (TestProtocol.sDebugTracing && state == NORMAL) {
- Log.d(TestProtocol.L3_SWIPE_TO_HOME, "onAnimationStart: " + state);
- }
onStateTransitionStart(state);
}
@Override
public void onAnimationSuccess(Animator animator) {
- if (TestProtocol.sDebugTracing && state == NORMAL) {
- Log.d(TestProtocol.L3_SWIPE_TO_HOME, "onAnimationEnd: " + state);
- }
onStateTransitionEnd(state);
}
};
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index ed52e20..3aecaa5 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -116,8 +116,6 @@
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
public static final String WORK_PROFILE_REMOVED = "b/159671700";
- public static final String FALLBACK_ACTIVITY_NO_SET = "b/181019015";
public static final String TASK_VIEW_ID_CRASH = "b/195430732";
- public static final String L3_SWIPE_TO_HOME = "b/192018189";
public static final String NO_DROP_TARGET = "b/195031154";
}
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index 895ca08..2ac6cea 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -408,22 +408,30 @@
}
@Override
- public void setGroupedTaskViewThumbnailBounds(View mSnapshotView, View mSnapshotView2,
- View taskParent, SplitConfigurationOptions.StagedSplitBounds splitBoundsConfig,
- DeviceProfile dp) {
+ public void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
+ int parentWidth, int parentHeight,
+ SplitConfigurationOptions.StagedSplitBounds splitBoundsConfig, DeviceProfile dp) {
int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
- int totalThumbnailHeight = taskParent.getHeight() - spaceAboveSnapshot;
- int totalThumbnailWidth = taskParent.getWidth();
+ int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
int dividerBar = splitBoundsConfig.visualDividerBounds.width();
- ViewGroup.LayoutParams primaryLp = mSnapshotView.getLayoutParams();
- ViewGroup.LayoutParams secondaryLp = mSnapshotView2.getLayoutParams();
+ int primarySnapshotHeight;
+ int primarySnapshotWidth;
+ int secondarySnapshotHeight;
+ int secondarySnapshotWidth;
- primaryLp.width = totalThumbnailWidth;
- primaryLp.height = (int) (totalThumbnailHeight * splitBoundsConfig.leftTaskPercent);
+ primarySnapshotWidth = parentWidth;
+ primarySnapshotHeight = (int) (totalThumbnailHeight * splitBoundsConfig.leftTaskPercent);
- secondaryLp.width = totalThumbnailWidth;
- secondaryLp.height = totalThumbnailHeight - primaryLp.height - dividerBar;
- mSnapshotView2.setTranslationY(primaryLp.height + spaceAboveSnapshot + dividerBar);
+ secondarySnapshotWidth = parentWidth;
+ secondarySnapshotHeight = totalThumbnailHeight - primarySnapshotHeight - dividerBar;
+ secondarySnapshot.setTranslationY(primarySnapshotHeight + spaceAboveSnapshot + dividerBar);
+ primarySnapshot.measure(
+ View.MeasureSpec.makeMeasureSpec(primarySnapshotWidth, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(primarySnapshotHeight, View.MeasureSpec.EXACTLY));
+ secondarySnapshot.measure(
+ View.MeasureSpec.makeMeasureSpec(secondarySnapshotWidth, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(secondarySnapshotHeight,
+ View.MeasureSpec.EXACTLY));
}
@Override
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index b34a81e..b119e2c 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -162,7 +162,8 @@
SplitConfigurationOptions.StagedSplitBounds splitInfo,
@SplitConfigurationOptions.StagePosition int desiredStagePosition);
- void setGroupedTaskViewThumbnailBounds(View mSnapshot1, View mSnapshot2, View taskParent,
+ void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
+ int parentWidth, int parentHeight,
SplitConfigurationOptions.StagedSplitBounds splitBoundsConfig, DeviceProfile dp);
// Overview TaskMenuView methods
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 064d808..99ad050 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -35,7 +35,6 @@
import android.view.Surface;
import android.view.VelocityTracker;
import android.view.View;
-import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.LinearLayout;
@@ -503,43 +502,56 @@
if (dp.isLandscape) {
splitOffset.x = splitInfo.leftTopBounds.width() +
splitInfo.visualDividerBounds.width();
+ splitOffset.y = 0;
} else {
splitOffset.y = splitInfo.leftTopBounds.height() +
splitInfo.visualDividerBounds.height();
+ splitOffset.x = 0;
}
}
}
@Override
- public void setGroupedTaskViewThumbnailBounds(View mSnapshotView, View mSnapshotView2,
- View taskParent, SplitConfigurationOptions.StagedSplitBounds splitBoundsConfig,
- DeviceProfile dp) {
+ public void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
+ int parentWidth, int parentHeight,
+ SplitConfigurationOptions.StagedSplitBounds splitBoundsConfig, DeviceProfile dp) {
int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
- int totalThumbnailHeight = taskParent.getHeight() - spaceAboveSnapshot;
- int totalThumbnailWidth = taskParent.getWidth();
- int dividerBar = (dp.isLandscape ?
- splitBoundsConfig.visualDividerBounds.width() :
- splitBoundsConfig.visualDividerBounds.height());
- ViewGroup.LayoutParams primaryLp = mSnapshotView.getLayoutParams();
- ViewGroup.LayoutParams secondaryLp = mSnapshotView2.getLayoutParams();
-
+ int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
+ int dividerBar = (splitBoundsConfig.appsStackedVertically ?
+ splitBoundsConfig.visualDividerBounds.height() :
+ splitBoundsConfig.visualDividerBounds.width());
+ int primarySnapshotHeight;
+ int primarySnapshotWidth;
+ int secondarySnapshotHeight;
+ int secondarySnapshotWidth;
+ float taskPercent = splitBoundsConfig.appsStackedVertically ?
+ splitBoundsConfig.topTaskPercent : splitBoundsConfig.leftTaskPercent;
if (dp.isLandscape) {
- primaryLp.height = totalThumbnailHeight;
- primaryLp.width = (int) (totalThumbnailWidth * splitBoundsConfig.leftTaskPercent);
+ primarySnapshotHeight = totalThumbnailHeight;
+ primarySnapshotWidth = (int) (parentWidth * taskPercent);
- secondaryLp.height = totalThumbnailHeight;
- secondaryLp.width = totalThumbnailWidth - primaryLp.width - dividerBar;
- mSnapshotView2.setTranslationX(primaryLp.width + dividerBar);
- mSnapshotView2.setTranslationY(spaceAboveSnapshot);
+ secondarySnapshotHeight = totalThumbnailHeight;
+ secondarySnapshotWidth = parentWidth - primarySnapshotWidth - dividerBar;
+ int translationX = primarySnapshotWidth + dividerBar;
+ secondarySnapshot.setTranslationX(translationX);
+ secondarySnapshot.setTranslationY(spaceAboveSnapshot);
} else {
- primaryLp.width = totalThumbnailWidth;
- primaryLp.height = (int) (totalThumbnailHeight * splitBoundsConfig.topTaskPercent);
+ primarySnapshotWidth = parentWidth;
+ primarySnapshotHeight = (int) (totalThumbnailHeight * taskPercent);
- secondaryLp.width = totalThumbnailWidth;
- secondaryLp.height = totalThumbnailHeight - primaryLp.height - dividerBar;
- mSnapshotView2.setTranslationY(primaryLp.height + spaceAboveSnapshot + dividerBar);
- mSnapshotView2.setTranslationX(0);
+ secondarySnapshotWidth = parentWidth;
+ secondarySnapshotHeight = totalThumbnailHeight - primarySnapshotHeight - dividerBar;
+ int translationY = primarySnapshotHeight + spaceAboveSnapshot + dividerBar;
+ secondarySnapshot.setTranslationY(translationY);
+ secondarySnapshot.setTranslationX(0);
}
+ primarySnapshot.measure(
+ View.MeasureSpec.makeMeasureSpec(primarySnapshotWidth, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(primarySnapshotHeight, View.MeasureSpec.EXACTLY));
+ secondarySnapshot.measure(
+ View.MeasureSpec.makeMeasureSpec(secondarySnapshotWidth, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(secondarySnapshotHeight,
+ View.MeasureSpec.EXACTLY));
}
@Override
diff --git a/src/com/android/launcher3/util/SplitConfigurationOptions.java b/src/com/android/launcher3/util/SplitConfigurationOptions.java
index 5093d85..0b083e3 100644
--- a/src/com/android/launcher3/util/SplitConfigurationOptions.java
+++ b/src/com/android/launcher3/util/SplitConfigurationOptions.java
@@ -93,7 +93,13 @@
// This class is orientation-agnostic, so we compute both for later use
public final float topTaskPercent;
public final float leftTaskPercent;
-
+ /**
+ * If {@code true}, that means at the time of creation of this object, the
+ * split-screened apps were vertically stacked. This is useful in scenarios like
+ * rotation where the bounds won't change, but this variable can indicate what orientation
+ * the bounds were originally in
+ */
+ public final boolean appsStackedVertically;
public StagedSplitBounds(Rect leftTopBounds, Rect rightBottomBounds) {
this.leftTopBounds = leftTopBounds;
@@ -103,10 +109,12 @@
// vertical apps, horizontal divider
this.visualDividerBounds = new Rect(leftTopBounds.left, leftTopBounds.bottom,
leftTopBounds.right, rightBottomBounds.top);
+ appsStackedVertically = true;
} else {
// horizontal apps, vertical divider
this.visualDividerBounds = new Rect(leftTopBounds.right, leftTopBounds.top,
rightBottomBounds.left, leftTopBounds.bottom);
+ appsStackedVertically = false;
}
leftTaskPercent = this.leftTopBounds.width() / (float) rightBottomBounds.right;
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index dc5fe06..ebcd379 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -27,6 +27,7 @@
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.ViewCache;
@@ -122,15 +123,33 @@
}
/**
- * Returns the ActivityContext associated with the given Context.
+ * Called just before logging the given item.
+ */
+ default void applyOverwritesToLogItem(LauncherAtom.ItemInfo.Builder itemInfoBuilder) { }
+
+ /**
+ * Returns the ActivityContext associated with the given Context, or throws an exception if
+ * the Context is not associated with any ActivityContext.
*/
static <T extends Context & ActivityContext> T lookupContext(Context context) {
+ T activityContext = lookupContextNoThrow(context);
+ if (activityContext == null) {
+ throw new IllegalArgumentException("Cannot find ActivityContext in parent tree");
+ }
+ return activityContext;
+ }
+
+ /**
+ * Returns the ActivityContext associated with the given Context, or null if
+ * the Context is not associated with any ActivityContext.
+ */
+ static <T extends Context & ActivityContext> T lookupContextNoThrow(Context context) {
if (context instanceof ActivityContext) {
return (T) context;
} else if (context instanceof ContextWrapper) {
- return lookupContext(((ContextWrapper) context).getBaseContext());
+ return lookupContextNoThrow(((ContextWrapper) context).getBaseContext());
} else {
- throw new IllegalArgumentException("Cannot find ActivityContext in parent tree");
+ return null;
}
}
}
diff --git a/src_plugins/com/android/systemui/plugins/OneSearch.java b/src_plugins/com/android/systemui/plugins/OneSearch.java
index 6d57c19..8bd0b75 100644
--- a/src_plugins/com/android/systemui/plugins/OneSearch.java
+++ b/src_plugins/com/android/systemui/plugins/OneSearch.java
@@ -16,8 +16,7 @@
package com.android.systemui.plugins;
-import android.graphics.Bitmap;
-import android.text.Spanned;
+import android.os.Parcelable;
import com.android.systemui.plugins.annotations.ProvidesInterface;
@@ -29,7 +28,7 @@
@ProvidesInterface(action = OneSearch.ACTION, version = OneSearch.VERSION)
public interface OneSearch extends Plugin {
String ACTION = "com.android.systemui.action.PLUGIN_ONE_SEARCH";
- int VERSION = 2;
+ int VERSION = 3;
/**
* Get the content provider warmed up.
@@ -37,23 +36,8 @@
void warmUp();
/**
- * Get the suggests for the query.
+ * Get the suggest search target list for the query.
* @param query The query to get the search suggests for.
*/
- ArrayList<Spanned> getSuggests(String query);
-
- /**
- * Get the image bitmap for the suggest.
- * @param suggest The suggest to get the image bitmap for.
- */
- Bitmap getImageBitmap(Spanned suggest);
-
- /**
- * Get the subtitle for the suggest.
- * @param suggest The suggest to get the subtitle for.
- */
- String getSubtitle(Spanned suggest);
-
- /** Clear any cached data or storage used in search. */
- void clear();
+ ArrayList<Parcelable> getSuggests(Parcelable query);
}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 1a6ce8c..cd0c7f2 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -153,8 +153,6 @@
public static String dumpHprofData() {
String result;
if (sDumpWasGenerated) {
- Log.d("b/195319692", "dump has already been generated by another test",
- new Exception());
result = "dump has already been generated by another test";
} else {
try {
@@ -169,7 +167,6 @@
"am dumpheap " + device.getLauncherPackageName() + " " + fileName);
}
sDumpWasGenerated = true;
- Log.d("b/195319692", "sDumpWasGenerated := true", new Exception());
result = "memory dump filename: " + fileName;
} catch (Throwable e) {
Log.e(TAG, "dumpHprofData failed", e);
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index f9a9997..65aaa24 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -2,6 +2,7 @@
import static androidx.test.InstrumentationRegistry.getInstrumentation;
+import android.content.Context;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor.AutoCloseInputStream;
import android.util.Log;
@@ -45,11 +46,30 @@
return new Statement() {
@Override
public void evaluate() throws Throwable {
+ boolean success = false;
try {
Log.d("b/196820244", "Before evaluate");
+ mDevice.executeShellCommand("cmd statusbar tracing start");
FailureWatcher.super.apply(base, description).evaluate();
Log.d("b/196820244", "After evaluate");
+ success = true;
} finally {
+ // Save artifact for Launcher Winscope trace.
+ mDevice.executeShellCommand("cmd statusbar tracing stop");
+ final Context nexusLauncherContext =
+ getInstrumentation().getTargetContext()
+ .createPackageContext("com.google.android.apps.nexuslauncher",
+ 0);
+ final File launcherTrace =
+ new File(nexusLauncherContext.getFilesDir(), "launcher_trace.pb");
+ if (success) {
+ mDevice.executeShellCommand("rm " + launcherTrace);
+ } else {
+ mDevice.executeShellCommand("mv " + launcherTrace + " "
+ + diagFile(description, "LauncherWinscope", "pb"));
+ }
+
+ // Detect touch events coming from physical screen.
if (mLauncher.hadNontestEvents()) {
throw new AssertionError(
"Launcher received events not sent by the test. This may mean "
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 98d081b..ea8a295 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1559,10 +1559,12 @@
}
float getWindowCornerRadius() {
+ // TODO(b/197326121): Check if the touch is overlapping with the corners by offsetting
+ final float tmpBuffer = 100f;
final Resources resources = getResources();
if (!supportsRoundedCornersOnWindows(resources)) {
Log.d(TAG, "No rounded corners");
- return 0f;
+ return tmpBuffer;
}
// Radius that should be used in case top or bottom aren't defined.
@@ -1581,7 +1583,7 @@
// Always use the smallest radius to make sure the rounded corners will
// completely cover the display.
Log.d(TAG, "Rounded corners top: " + topRadius + " bottom: " + bottomRadius);
- return Math.max(topRadius, bottomRadius);
+ return Math.max(topRadius, bottomRadius) + tmpBuffer;
}
private static boolean supportsRoundedCornersOnWindows(Resources resources) {