parents);
+ }
+
+ /**
+ * Recursively finds the parent of the given child which implements IconLogInfoProvider
+ */
+ public static LogContainerProvider getLaunchProviderRecursive(@Nullable View v) {
+ ViewParent parent;
+ if (v != null) {
+ parent = v.getParent();
+ } else {
+ return null;
+ }
+
+ // Optimization to only check up to 5 parents.
+ int count = MAXIMUM_VIEW_HIERARCHY_LEVEL;
+ while (parent != null && count-- > 0) {
+ if (parent instanceof LogContainerProvider) {
+ return (LogContainerProvider) parent;
+ } else {
+ parent = parent.getParent();
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
new file mode 100644
index 0000000000..a40cc263db
--- /dev/null
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2012 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.logging;
+
+import static com.android.launcher3.logging.LoggerUtils.newAction;
+import static com.android.launcher3.logging.LoggerUtils.newCommandAction;
+import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
+import static com.android.launcher3.logging.LoggerUtils.newDropTarget;
+import static com.android.launcher3.logging.LoggerUtils.newItemTarget;
+import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
+import static com.android.launcher3.logging.LoggerUtils.newTarget;
+import static com.android.launcher3.logging.LoggerUtils.newTouchAction;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.TipType;
+
+import static java.util.Optional.ofNullable;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.DropTarget;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.userevent.LauncherLogProto;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
+import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+import com.android.launcher3.util.InstantAppResolver;
+import com.android.launcher3.util.LogConfig;
+import com.android.launcher3.util.ResourceBasedOverride;
+
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
+import com.google.protobuf.nano.MessageNano;
+
+import java.util.ArrayList;
+import java.util.UUID;
+
+/**
+ * Manages the creation of {@link LauncherEvent}.
+ * To debug this class, execute following command before side loading a new apk.
+ *
+ * $ adb shell setprop log.tag.UserEvent VERBOSE
+ */
+public class UserEventDispatcher implements ResourceBasedOverride {
+
+ private static final String TAG = "UserEvent";
+ private static final boolean IS_VERBOSE = Utilities.isPropertyEnabled(LogConfig.USEREVENT);
+ private static final String UUID_STORAGE = "uuid";
+
+ /**
+ * A factory method for UserEventDispatcher
+ */
+ public static UserEventDispatcher newInstance(Context context) {
+ SharedPreferences sharedPrefs = Utilities.getDevicePrefs(context);
+ String uuidStr = sharedPrefs.getString(UUID_STORAGE, null);
+ if (uuidStr == null) {
+ uuidStr = UUID.randomUUID().toString();
+ sharedPrefs.edit().putString(UUID_STORAGE, uuidStr).apply();
+ }
+ UserEventDispatcher ued = Overrides.getObject(UserEventDispatcher.class,
+ context.getApplicationContext(), R.string.user_event_dispatcher_class);
+ ued.mUuidStr = uuidStr;
+ ued.mInstantAppResolver = InstantAppResolver.newInstance(context);
+ return ued;
+ }
+
+
+ /**
+ * Fills in the container data on the given event if the given view is not null.
+ *
+ * @return whether container data was added.
+ */
+ private boolean fillLogContainer(@Nullable View v, Target child,
+ @Nullable ArrayList targets) {
+ LogContainerProvider firstParent = StatsLogUtils.getLaunchProviderRecursive(v);
+ if (v == null || !(v.getTag() instanceof ItemInfo) || firstParent == null) {
+ return false;
+ }
+ final ItemInfo itemInfo = (ItemInfo) v.getTag();
+ firstParent.fillInLogContainerData(itemInfo, child, targets);
+ return true;
+ }
+
+ protected void onFillInLogContainerData(@NonNull ItemInfo itemInfo, @NonNull Target target,
+ @NonNull ArrayList targets) {
+ }
+
+ private boolean mSessionStarted;
+ private long mElapsedContainerMillis;
+ private long mElapsedSessionMillis;
+ private long mActionDurationMillis;
+ private String mUuidStr;
+ protected InstantAppResolver mInstantAppResolver;
+ private boolean mAppOrTaskLaunch;
+ private boolean mPreviousHomeGesture;
+
+ private void fillComponentInfo(Target target, ComponentName cn) {
+ if (cn != null) {
+ target.packageNameHash = (mUuidStr + cn.getPackageName()).hashCode();
+ target.componentHash = (mUuidStr + cn.flattenToString()).hashCode();
+ }
+ }
+
+ public void logActionCommand(int command, int srcContainerType, int dstContainerType) {
+ logActionCommand(command, newContainerTarget(srcContainerType),
+ dstContainerType >= 0 ? newContainerTarget(dstContainerType) : null);
+ }
+
+ public void logActionCommand(int command, int srcContainerType, int dstContainerType,
+ int pageIndex) {
+ Target srcTarget = newContainerTarget(srcContainerType);
+ srcTarget.pageIndex = pageIndex;
+ logActionCommand(command, srcTarget,
+ dstContainerType >= 0 ? newContainerTarget(dstContainerType) : null);
+ }
+
+ public void logActionCommand(int command, Target srcTarget, Target dstTarget) {
+ LauncherEvent event = newLauncherEvent(newCommandAction(command), srcTarget);
+ if (command == Action.Command.STOP) {
+ if (mAppOrTaskLaunch || !mSessionStarted) {
+ mSessionStarted = false;
+ return;
+ }
+ }
+
+ if (dstTarget != null) {
+ event.destTarget = new Target[1];
+ event.destTarget[0] = dstTarget;
+ event.action.isStateChange = true;
+ }
+ dispatchUserEvent(event, null);
+ }
+
+ public void logActionOnControl(int action, int controlType) {
+ logActionOnControl(action, controlType, null);
+ }
+
+ public void logActionOnControl(int action, int controlType, int parentContainerType) {
+ logActionOnControl(action, controlType, null, parentContainerType);
+ }
+
+ /**
+ * Logs control action with proper parent hierarchy
+ */
+ public void logActionOnControl(int actionType, int controlType,
+ @Nullable View controlInContainer, int... parentTypes) {
+ Target control = newTarget(Target.Type.CONTROL);
+ control.controlType = controlType;
+ Action action = newAction(actionType);
+
+ ArrayList targets = makeTargetsList(control);
+ if (controlInContainer != null) {
+ fillLogContainer(controlInContainer, control, targets);
+ }
+ for (int parentContainerType : parentTypes) {
+ if (parentContainerType < 0) continue;
+ targets.add(newContainerTarget(parentContainerType));
+ }
+ LauncherEvent event = newLauncherEvent(action, targets);
+ if (actionType == Action.Touch.DRAGDROP) {
+ event.actionDurationMillis = SystemClock.uptimeMillis() - mActionDurationMillis;
+ }
+ dispatchUserEvent(event, null);
+ }
+
+ public void logActionTapOutside(Target target) {
+ LauncherEvent event = newLauncherEvent(newTouchAction(Action.Type.TOUCH),
+ target);
+ event.action.isOutside = true;
+ dispatchUserEvent(event, null);
+ }
+
+ public void logActionBounceTip(int containerType) {
+ LauncherEvent event = newLauncherEvent(newAction(Action.Type.TIP),
+ newContainerTarget(containerType));
+ event.srcTarget[0].tipType = TipType.BOUNCE;
+ dispatchUserEvent(event, null);
+ }
+
+ public void logActionOnContainer(int action, int dir, int containerType) {
+ logActionOnContainer(action, dir, containerType, 0);
+ }
+
+ public void logActionOnContainer(int action, int dir, int containerType, int pageIndex) {
+ LauncherEvent event = newLauncherEvent(newTouchAction(action),
+ newContainerTarget(containerType));
+ event.action.dir = dir;
+ event.srcTarget[0].pageIndex = pageIndex;
+ dispatchUserEvent(event, null);
+ }
+
+ /**
+ * Used primarily for swipe up and down when state changes when swipe up happens from the
+ * navbar bezel, the {@param srcChildContainerType} is NAVBAR and
+ * {@param srcParentContainerType} is either one of the two
+ * (1) WORKSPACE: if the launcher is the foreground activity
+ * (2) APP: if another app was the foreground activity
+ */
+ public void logStateChangeAction(int action, int dir, int downX, int downY,
+ int srcChildTargetType, int srcParentContainerType, int dstContainerType,
+ int pageIndex) {
+ LauncherEvent event;
+ if (srcChildTargetType == ItemType.TASK) {
+ event = newLauncherEvent(newTouchAction(action),
+ newItemTarget(srcChildTargetType),
+ newContainerTarget(srcParentContainerType));
+ } else {
+ event = newLauncherEvent(newTouchAction(action),
+ newContainerTarget(srcChildTargetType),
+ newContainerTarget(srcParentContainerType));
+ }
+ event.destTarget = new Target[1];
+ event.destTarget[0] = newContainerTarget(dstContainerType);
+ event.action.dir = dir;
+ event.action.isStateChange = true;
+ event.srcTarget[0].pageIndex = pageIndex;
+ event.srcTarget[0].spanX = downX;
+ event.srcTarget[0].spanY = downY;
+ dispatchUserEvent(event, null);
+ }
+
+ public void logActionOnItem(int action, int dir, int itemType) {
+ logActionOnItem(action, dir, itemType, null, null);
+ }
+
+ /**
+ * Creates new {@link LauncherEvent} of ITEM target type with input arguments and dispatches it.
+ *
+ * @param touchAction ENUM value of {@link LauncherLogProto.Action.Touch} Action
+ * @param dir ENUM value of {@link LauncherLogProto.Action.Direction} Action
+ * @param itemType ENUM value of {@link LauncherLogProto.ItemType}
+ * @param gridX Nullable X coordinate of item's position on the workspace grid
+ * @param gridY Nullable Y coordinate of item's position on the workspace grid
+ */
+ public void logActionOnItem(int touchAction, int dir, int itemType,
+ @Nullable Integer gridX, @Nullable Integer gridY) {
+ Target itemTarget = newTarget(Target.Type.ITEM);
+ itemTarget.itemType = itemType;
+ ofNullable(gridX).ifPresent(value -> itemTarget.gridX = value);
+ ofNullable(gridY).ifPresent(value -> itemTarget.gridY = value);
+ LauncherEvent event = newLauncherEvent(newTouchAction(touchAction), itemTarget);
+ event.action.dir = dir;
+ dispatchUserEvent(event, null);
+ }
+
+ /**
+ * Logs proto lite version of LauncherEvent object to clearcut.
+ */
+ public void logLauncherEvent(
+ com.android.launcher3.userevent.LauncherLogProto.LauncherEvent launcherEvent) {
+
+ if (mPreviousHomeGesture) {
+ mPreviousHomeGesture = false;
+ }
+ mAppOrTaskLaunch = false;
+ launcherEvent.toBuilder()
+ .setElapsedContainerMillis(SystemClock.uptimeMillis() - mElapsedContainerMillis)
+ .setElapsedSessionMillis(
+ SystemClock.uptimeMillis() - mElapsedSessionMillis).build();
+ try {
+ dispatchUserEvent(LauncherEvent.parseFrom(launcherEvent.toByteArray()), null);
+ } catch (InvalidProtocolBufferNanoException e) {
+ throw new RuntimeException("Cannot convert LauncherEvent from Lite to Nano version.");
+ }
+ }
+
+ public void logDeepShortcutsOpen(View icon) {
+ ItemInfo info = (ItemInfo) icon.getTag();
+ Target child = newItemTarget(info, mInstantAppResolver);
+ ArrayList targets = makeTargetsList(child);
+ fillLogContainer(icon, child, targets);
+ dispatchUserEvent(newLauncherEvent(newTouchAction(Action.Touch.TAP), targets), null);
+ }
+
+ public void logDragNDrop(DropTarget.DragObject dragObj, View dropTargetAsView) {
+ Target srcChild = newItemTarget(dragObj.originalDragInfo, mInstantAppResolver);
+ ArrayList srcTargets = makeTargetsList(srcChild);
+
+
+ Target destChild = newItemTarget(dragObj.originalDragInfo, mInstantAppResolver);
+ ArrayList destTargets = makeTargetsList(destChild);
+
+ //dragObj.dragSource.fillInLogContainerData(dragObj.originalDragInfo, srcChild, srcTargets);
+ if (dropTargetAsView instanceof LogContainerProvider) {
+ ((LogContainerProvider) dropTargetAsView).fillInLogContainerData(dragObj.dragInfo,
+ destChild, destTargets);
+ }
+ else {
+ destTargets.add(newDropTarget(dropTargetAsView));
+ }
+ LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.DRAGDROP), srcTargets);
+ Target[] destTargetsArray = new Target[destTargets.size()];
+ destTargets.toArray(destTargetsArray);
+ event.destTarget = destTargetsArray;
+
+ event.actionDurationMillis = SystemClock.uptimeMillis() - mActionDurationMillis;
+ dispatchUserEvent(event, null);
+ }
+
+ public final void startSession() {
+ mSessionStarted = true;
+ mElapsedSessionMillis = SystemClock.uptimeMillis();
+ mElapsedContainerMillis = SystemClock.uptimeMillis();
+ }
+
+ public final void setPreviousHomeGesture(boolean homeGesture) {
+ mPreviousHomeGesture = homeGesture;
+ }
+
+ public final boolean isPreviousHomeGesture() {
+ return mPreviousHomeGesture;
+ }
+
+ public final void resetActionDurationMillis() {
+ mActionDurationMillis = SystemClock.uptimeMillis();
+ }
+
+ public void dispatchUserEvent(LauncherEvent ev, Intent intent) {
+ if (mPreviousHomeGesture) {
+ mPreviousHomeGesture = false;
+ }
+ mAppOrTaskLaunch = false;
+ ev.elapsedContainerMillis = SystemClock.uptimeMillis() - mElapsedContainerMillis;
+ ev.elapsedSessionMillis = SystemClock.uptimeMillis() - mElapsedSessionMillis;
+ if (!IS_VERBOSE) {
+ return;
+ }
+ LauncherLogProto.LauncherEvent liteLauncherEvent;
+ try {
+ liteLauncherEvent =
+ LauncherLogProto.LauncherEvent.parseFrom(MessageNano.toByteArray(ev));
+ } catch (InvalidProtocolBufferException e) {
+ throw new RuntimeException("Cannot parse LauncherEvent from Nano to Lite version");
+ }
+ Log.d(TAG, liteLauncherEvent.toString());
+ }
+
+ /**
+ * Constructs an ArrayList with targets
+ */
+ public static ArrayList makeTargetsList(Target... targets) {
+ ArrayList result = new ArrayList<>();
+ for (Target target : targets) {
+ result.add(target);
+ }
+ return result;
+ }
+}
diff --git a/src/com/android/launcher3/model/data/FolderInfo.java b/src/com/android/launcher3/model/data/FolderInfo.java
index 06a2c92dab..41ccbd7054 100644
--- a/src/com/android/launcher3/model/data/FolderInfo.java
+++ b/src/com/android/launcher3/model/data/FolderInfo.java
@@ -20,9 +20,15 @@ import static android.text.TextUtils.isEmpty;
import static androidx.core.util.Preconditions.checkNotNull;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
import static com.android.launcher3.logger.LauncherAtom.Attribute.EMPTY_LABEL;
import static com.android.launcher3.logger.LauncherAtom.Attribute.MANUAL_LABEL;
import static com.android.launcher3.logger.LauncherAtom.Attribute.SUGGESTED_LABEL;
+import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_CUSTOM;
+import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_EMPTY;
+import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_FOLDER_LABEL_STATE_UNSPECIFIED;
+import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_SUGGESTED;
import android.os.Process;
@@ -37,6 +43,10 @@ import com.android.launcher3.logger.LauncherAtom.Attribute;
import com.android.launcher3.logger.LauncherAtom.FromState;
import com.android.launcher3.logger.LauncherAtom.ToState;
import com.android.launcher3.model.ModelWriter;
+import com.android.launcher3.userevent.LauncherLogProto;
+import com.android.launcher3.userevent.LauncherLogProto.Target;
+import com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState;
+import com.android.launcher3.userevent.LauncherLogProto.Target.ToFolderLabelState;
import com.android.launcher3.util.ContentWriter;
import java.util.ArrayList;
@@ -349,4 +359,113 @@ public class FolderInfo extends ItemInfo {
}
return LauncherAtom.ToState.TO_STATE_UNSPECIFIED;
}
+
+ /**
+ * Returns {@link LauncherLogProto.LauncherEvent} to log current folder label info.
+ *
+ * @deprecated This method is used only for validation purpose and soon will be removed.
+ */
+ @Deprecated
+ public LauncherLogProto.LauncherEvent getFolderLabelStateLauncherEvent(FromState fromState,
+ ToState toState) {
+ return LauncherLogProto.LauncherEvent.newBuilder()
+ .setAction(LauncherLogProto.Action
+ .newBuilder()
+ .setType(LauncherLogProto.Action.Type.SOFT_KEYBOARD))
+ .addSrcTarget(Target
+ .newBuilder()
+ .setType(Target.Type.ITEM)
+ .setItemType(LauncherLogProto.ItemType.EDITTEXT)
+ .setFromFolderLabelState(convertFolderLabelState(fromState))
+ .setToFolderLabelState(convertFolderLabelState(toState)))
+ .addSrcTarget(Target.newBuilder()
+ .setType(Target.Type.CONTAINER)
+ .setContainerType(LauncherLogProto.ContainerType.FOLDER)
+ .setPageIndex(screenId)
+ .setGridX(cellX)
+ .setGridY(cellY)
+ .setCardinality(contents.size()))
+ .addSrcTarget(newParentContainerTarget())
+ .build();
+ }
+
+ /**
+ * @deprecated This method is used only for validation purpose and soon will be removed.
+ */
+ @Deprecated
+ private Target.Builder newParentContainerTarget() {
+ Target.Builder builder = Target.newBuilder().setType(Target.Type.CONTAINER);
+ switch (container) {
+ case CONTAINER_HOTSEAT:
+ return builder.setContainerType(LauncherLogProto.ContainerType.HOTSEAT);
+ case CONTAINER_DESKTOP:
+ return builder.setContainerType(LauncherLogProto.ContainerType.WORKSPACE);
+ default:
+ throw new AssertionError(String
+ .format("Expected container to be either %s or %s but found %s.",
+ CONTAINER_HOTSEAT,
+ CONTAINER_DESKTOP,
+ container));
+ }
+ }
+
+ /**
+ * @deprecated This method is used only for validation purpose and soon will be removed.
+ */
+ @Deprecated
+ private static FromFolderLabelState convertFolderLabelState(FromState fromState) {
+ switch (fromState) {
+ case FROM_EMPTY:
+ return FROM_EMPTY;
+ case FROM_SUGGESTED:
+ return FROM_SUGGESTED;
+ case FROM_CUSTOM:
+ return FROM_CUSTOM;
+ default:
+ return FROM_FOLDER_LABEL_STATE_UNSPECIFIED;
+ }
+ }
+
+ /**
+ * @deprecated This method is used only for validation purpose and soon will be removed.
+ */
+ @Deprecated
+ private static ToFolderLabelState convertFolderLabelState(ToState toState) {
+ switch (toState) {
+ case UNCHANGED:
+ return ToFolderLabelState.UNCHANGED;
+ case TO_SUGGESTION0:
+ return ToFolderLabelState.TO_SUGGESTION0_WITH_VALID_PRIMARY;
+ case TO_SUGGESTION1_WITH_VALID_PRIMARY:
+ return ToFolderLabelState.TO_SUGGESTION1_WITH_VALID_PRIMARY;
+ case TO_SUGGESTION1_WITH_EMPTY_PRIMARY:
+ return ToFolderLabelState.TO_SUGGESTION1_WITH_EMPTY_PRIMARY;
+ case TO_SUGGESTION2_WITH_VALID_PRIMARY:
+ return ToFolderLabelState.TO_SUGGESTION2_WITH_VALID_PRIMARY;
+ case TO_SUGGESTION2_WITH_EMPTY_PRIMARY:
+ return ToFolderLabelState.TO_SUGGESTION2_WITH_EMPTY_PRIMARY;
+ case TO_SUGGESTION3_WITH_VALID_PRIMARY:
+ return ToFolderLabelState.TO_SUGGESTION3_WITH_VALID_PRIMARY;
+ case TO_SUGGESTION3_WITH_EMPTY_PRIMARY:
+ return ToFolderLabelState.TO_SUGGESTION3_WITH_EMPTY_PRIMARY;
+ case TO_EMPTY_WITH_VALID_PRIMARY:
+ return ToFolderLabelState.TO_EMPTY_WITH_VALID_PRIMARY;
+ case TO_EMPTY_WITH_VALID_SUGGESTIONS_AND_EMPTY_PRIMARY:
+ return ToFolderLabelState.TO_EMPTY_WITH_VALID_SUGGESTIONS_AND_EMPTY_PRIMARY;
+ case TO_EMPTY_WITH_EMPTY_SUGGESTIONS:
+ return ToFolderLabelState.TO_EMPTY_WITH_EMPTY_SUGGESTIONS;
+ case TO_EMPTY_WITH_SUGGESTIONS_DISABLED:
+ return ToFolderLabelState.TO_EMPTY_WITH_SUGGESTIONS_DISABLED;
+ case TO_CUSTOM_WITH_VALID_PRIMARY:
+ return ToFolderLabelState.TO_CUSTOM_WITH_VALID_PRIMARY;
+ case TO_CUSTOM_WITH_VALID_SUGGESTIONS_AND_EMPTY_PRIMARY:
+ return ToFolderLabelState.TO_CUSTOM_WITH_VALID_SUGGESTIONS_AND_EMPTY_PRIMARY;
+ case TO_CUSTOM_WITH_EMPTY_SUGGESTIONS:
+ return ToFolderLabelState.TO_CUSTOM_WITH_EMPTY_SUGGESTIONS;
+ case TO_CUSTOM_WITH_SUGGESTIONS_DISABLED:
+ return ToFolderLabelState.TO_CUSTOM_WITH_SUGGESTIONS_DISABLED;
+ default:
+ return ToFolderLabelState.TO_FOLDER_LABEL_STATE_UNSPECIFIED;
+ }
+ }
}
diff --git a/src/com/android/launcher3/model/data/RemoteActionItemInfo.java b/src/com/android/launcher3/model/data/RemoteActionItemInfo.java
deleted file mode 100644
index 81f7f3a0a2..0000000000
--- a/src/com/android/launcher3/model/data/RemoteActionItemInfo.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.model.data;
-
-import android.app.RemoteAction;
-import android.os.Process;
-
-/**
- * Represents a launchable {@link RemoteAction}
- */
-public class RemoteActionItemInfo extends ItemInfoWithIcon {
-
- private final RemoteAction mRemoteAction;
- private final String mToken;
- private final boolean mShouldStart;
-
- public RemoteActionItemInfo(RemoteAction remoteAction, String token, boolean shouldStart) {
- mShouldStart = shouldStart;
- mToken = token;
- mRemoteAction = remoteAction;
- title = remoteAction.getTitle();
- user = Process.myUserHandle();
- }
-
- public RemoteActionItemInfo(RemoteActionItemInfo info) {
- super(info);
- this.mShouldStart = info.mShouldStart;
- this.mRemoteAction = info.mRemoteAction;
- this.mToken = info.mToken;
- }
-
- @Override
- public ItemInfoWithIcon clone() {
- return new RemoteActionItemInfo(this);
- }
-
- public RemoteAction getRemoteAction() {
- return mRemoteAction;
- }
-
- public String getToken() {
- return mToken;
- }
-
- /**
- * Getter method for mShouldStart
- */
- public boolean shouldStartInLauncher() {
- return mShouldStart;
- }
-}
diff --git a/src/com/android/launcher3/notification/NotificationMainView.java b/src/com/android/launcher3/notification/NotificationMainView.java
index 9b065233b9..32f060ba85 100644
--- a/src/com/android/launcher3/notification/NotificationMainView.java
+++ b/src/com/android/launcher3/notification/NotificationMainView.java
@@ -17,7 +17,6 @@
package com.android.launcher3.notification;
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DISMISSED;
import android.animation.Animator;
import android.animation.ObjectAnimator;
@@ -42,6 +41,7 @@ import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.touch.BaseSwipeDetector;
import com.android.launcher3.touch.OverScroll;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.Themes;
/**
@@ -168,7 +168,10 @@ public class NotificationMainView extends FrameLayout implements SingleAxisSwipe
Launcher launcher = Launcher.getLauncher(getContext());
launcher.getPopupDataProvider().cancelNotification(
mNotificationInfo.notificationKey);
- launcher.getStatsLogManager().logger().log(LAUNCHER_NOTIFICATION_DISMISSED);
+ launcher.getUserEventDispatcher().logActionOnItem(
+ LauncherLogProto.Action.Touch.SWIPE,
+ LauncherLogProto.Action.Direction.RIGHT, // Assume all swipes are right for logging.
+ LauncherLogProto.ItemType.NOTIFICATION);
}
// SingleAxisSwipeDetector.Listener's
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index fa25114d49..753a6dd85e 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -17,7 +17,6 @@
package com.android.launcher3.pm;
import static com.android.launcher3.Utilities.getPrefs;
-import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -32,7 +31,6 @@ import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
-import androidx.annotation.WorkerThread;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.SessionCommitReceiver;
@@ -41,10 +39,10 @@ import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.ItemInstallQueue;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
+import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.util.Preconditions;
import java.util.ArrayList;
import java.util.HashMap;
@@ -67,27 +65,27 @@ public class InstallSessionHelper {
private final LauncherApps mLauncherApps;
private final Context mAppContext;
+ private final IntSet mPromiseIconIds;
private final PackageInstaller mInstaller;
private final HashMap mSessionVerifiedMap = new HashMap<>();
- private IntSet mPromiseIconIds;
-
public InstallSessionHelper(Context context) {
mInstaller = context.getPackageManager().getPackageInstaller();
mAppContext = context.getApplicationContext();
mLauncherApps = context.getSystemService(LauncherApps.class);
+
+ mPromiseIconIds = IntSet.wrap(IntArray.fromConcatString(
+ getPrefs(context).getString(PROMISE_ICON_IDS, "")));
+
+ cleanUpPromiseIconIds();
}
- @WorkerThread
- private IntSet getPromiseIconIds() {
- Preconditions.assertWorkerThread();
- if (mPromiseIconIds != null) {
- return mPromiseIconIds;
- }
- mPromiseIconIds = IntSet.wrap(IntArray.fromConcatString(
- getPrefs(mAppContext).getString(PROMISE_ICON_IDS, "")));
+ public static UserHandle getUserHandle(SessionInfo info) {
+ return Utilities.ATLEAST_Q ? info.getUser() : Process.myUserHandle();
+ }
+ protected void cleanUpPromiseIconIds() {
IntArray existingIds = new IntArray();
for (SessionInfo info : getActiveSessions().values()) {
existingIds.add(info.getSessionId());
@@ -102,7 +100,6 @@ public class InstallSessionHelper {
for (int i = idsToRemove.size() - 1; i >= 0; --i) {
mPromiseIconIds.getArray().removeValue(idsToRemove.get(i));
}
- return mPromiseIconIds;
}
public HashMap getActiveSessions() {
@@ -129,7 +126,7 @@ public class InstallSessionHelper {
private void updatePromiseIconPrefs() {
getPrefs(mAppContext).edit()
- .putString(PROMISE_ICON_IDS, getPromiseIconIds().getArray().toConcatString())
+ .putString(PROMISE_ICON_IDS, mPromiseIconIds.getArray().toConcatString())
.apply();
}
@@ -187,15 +184,13 @@ public class InstallSessionHelper {
return info.getInstallReason() == PackageManager.INSTALL_REASON_DEVICE_RESTORE;
}
- @WorkerThread
public boolean promiseIconAddedForId(int sessionId) {
- return getPromiseIconIds().contains(sessionId);
+ return mPromiseIconIds.contains(sessionId);
}
- @WorkerThread
public void removePromiseIconId(int sessionId) {
- if (promiseIconAddedForId(sessionId)) {
- getPromiseIconIds().getArray().removeValue(sessionId);
+ if (mPromiseIconIds.contains(sessionId)) {
+ mPromiseIconIds.getArray().removeValue(sessionId);
updatePromiseIconPrefs();
}
}
@@ -208,7 +203,6 @@ public class InstallSessionHelper {
* - The app is not already installed
* - A promise icon for the session has not already been created
*/
- @WorkerThread
void tryQueuePromiseAppIcon(PackageInstaller.SessionInfo sessionInfo) {
if (FeatureFlags.PROMISE_APPS_NEW_INSTALLS.get()
&& SessionCommitReceiver.isEnabled(mAppContext)
@@ -216,24 +210,25 @@ public class InstallSessionHelper {
&& sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER
&& sessionInfo.getAppIcon() != null
&& !TextUtils.isEmpty(sessionInfo.getAppLabel())
- && !promiseIconAddedForId(sessionInfo.getSessionId())
+ && !mPromiseIconIds.contains(sessionInfo.getSessionId())
&& new PackageManagerHelper(mAppContext).getApplicationInfo(
sessionInfo.getAppPackageName(), getUserHandle(sessionInfo), 0) == null) {
ItemInstallQueue.INSTANCE.get(mAppContext)
.queueItem(sessionInfo.getAppPackageName(), getUserHandle(sessionInfo));
- getPromiseIconIds().add(sessionInfo.getSessionId());
+ mPromiseIconIds.add(sessionInfo.getSessionId());
updatePromiseIconPrefs();
}
}
- public InstallSessionTracker registerInstallTracker(InstallSessionTracker.Callback callback) {
+ public InstallSessionTracker registerInstallTracker(
+ InstallSessionTracker.Callback callback, LooperExecutor executor) {
InstallSessionTracker tracker = new InstallSessionTracker(this, callback);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
- mInstaller.registerSessionCallback(tracker, MODEL_EXECUTOR.getHandler());
+ mInstaller.registerSessionCallback(tracker, executor.getHandler());
} else {
- mLauncherApps.registerPackageInstallerSessionCallback(MODEL_EXECUTOR, tracker);
+ mLauncherApps.registerPackageInstallerSessionCallback(executor, tracker);
}
return tracker;
}
@@ -245,8 +240,4 @@ public class InstallSessionHelper {
mLauncherApps.unregisterPackageInstallerSessionCallback(tracker);
}
}
-
- public static UserHandle getUserHandle(SessionInfo info) {
- return Utilities.ATLEAST_Q ? info.getUser() : Process.myUserHandle();
- }
}
diff --git a/src/com/android/launcher3/pm/InstallSessionTracker.java b/src/com/android/launcher3/pm/InstallSessionTracker.java
index b0b907ab19..eb3ca7366b 100644
--- a/src/com/android/launcher3/pm/InstallSessionTracker.java
+++ b/src/com/android/launcher3/pm/InstallSessionTracker.java
@@ -24,11 +24,8 @@ import android.content.pm.PackageInstaller.SessionInfo;
import android.os.UserHandle;
import android.util.SparseArray;
-import androidx.annotation.WorkerThread;
-
import com.android.launcher3.util.PackageUserKey;
-@WorkerThread
public class InstallSessionTracker extends PackageInstaller.SessionCallback {
// Lazily initialized
diff --git a/src/com/android/launcher3/pm/UserCache.java b/src/com/android/launcher3/pm/UserCache.java
index 5ade22be5e..2d7d6b092a 100644
--- a/src/com/android/launcher3/pm/UserCache.java
+++ b/src/com/android/launcher3/pm/UserCache.java
@@ -60,9 +60,6 @@ public class UserCache {
private void onUsersChanged(Intent intent) {
enableAndResetCache();
mUserChangeListeners.forEach(Runnable::run);
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.WORK_PROFILE_REMOVED, "profile changed", new Exception());
- }
}
/**
@@ -107,6 +104,9 @@ public class UserCache {
mUsers = null;
mUserToSerialMap = null;
}
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.WORK_PROFILE_REMOVED, "Work profile removed", new Exception());
+ }
}
}
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 90285c470b..d5b32fccd1 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -151,52 +151,32 @@ public abstract class ArrowPopup extends Abstrac
* @param viewsToFlip number of views from the top to to flip in case of reverse order
*/
protected void reorderAndShow(int viewsToFlip) {
- setupForDisplay();
- boolean reverseOrder = mIsAboveIcon;
- if (reverseOrder) {
- reverseOrder(viewsToFlip);
- }
- onInflationComplete(reverseOrder);
- addArrow();
- animateOpen();
- }
-
- /**
- * Shows the popup at the desired location.
- */
- protected void show() {
- setupForDisplay();
- onInflationComplete(false);
- addArrow();
- animateOpen();
- }
-
- private void setupForDisplay() {
setVisibility(View.INVISIBLE);
mIsOpen = true;
getPopupContainer().addView(this);
orientAboutObject();
- }
- private void reverseOrder(int viewsToFlip) {
- int count = getChildCount();
- ArrayList allViews = new ArrayList<>(count);
- for (int i = 0; i < count; i++) {
- if (i == viewsToFlip) {
- Collections.reverse(allViews);
+ boolean reverseOrder = mIsAboveIcon;
+ if (reverseOrder) {
+ int count = getChildCount();
+ ArrayList allViews = new ArrayList<>(count);
+ for (int i = 0; i < count; i++) {
+ if (i == viewsToFlip) {
+ Collections.reverse(allViews);
+ }
+ allViews.add(getChildAt(i));
+ }
+ Collections.reverse(allViews);
+ removeAllViews();
+ for (int i = 0; i < count; i++) {
+ addView(allViews.get(i));
}
- allViews.add(getChildAt(i));
- }
- Collections.reverse(allViews);
- removeAllViews();
- for (int i = 0; i < count; i++) {
- addView(allViews.get(i));
- }
- orientAboutObject();
- }
+ orientAboutObject();
+ }
+ onInflationComplete(reverseOrder);
- private void addArrow() {
+ // Add the arrow.
final Resources res = getResources();
final int arrowCenterOffset = res.getDimensionPixelSize(isAlignedWithStart()
? R.dimen.popup_arrow_horizontal_center_start
@@ -234,6 +214,8 @@ public abstract class ArrowPopup extends Abstrac
mArrow.setPivotX(arrowLp.width / 2);
mArrow.setPivotY(mIsAboveIcon ? arrowLp.height : 0);
+
+ animateOpen();
}
protected boolean isAlignedWithStart() {
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 6d92b8b627..26b32b8195 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -19,8 +19,10 @@ package com.android.launcher3.popup;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
+import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.animation.AnimatorSet;
@@ -158,7 +160,8 @@ public class PopupContainerWithArrow extends Arr
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
BaseDragLayer dl = getPopupContainer();
if (!dl.isEventOverView(this, ev)) {
- // TODO: add WW log if want to log if tap closed deep shortcut container.
+ mLauncher.getUserEventDispatcher().logActionTapOutside(
+ newContainerTarget(ContainerType.DEEPSHORTCUTS));
close(true);
// We let touches on the original icon go through so that users can launch
@@ -432,9 +435,7 @@ public class PopupContainerWithArrow extends Arr
// Make sure we keep the original icon hidden while it is being dragged.
mOriginalIcon.setVisibility(INVISIBLE);
} else {
- // TODO: add WW logging if want to add logging for long press on popup
- // container.
- // mLauncher.getUserEventDispatcher().logDeepShortcutsOpen(mOriginalIcon);
+ mLauncher.getUserEventDispatcher().logDeepShortcutsOpen(mOriginalIcon);
if (!mIsAboveIcon) {
// Show the icon but keep the text hidden.
mOriginalIcon.setVisibility(VISIBLE);
diff --git a/src/com/android/launcher3/popup/RemoteActionShortcut.java b/src/com/android/launcher3/popup/RemoteActionShortcut.java
index 7c393ad1e2..61829c002b 100644
--- a/src/com/android/launcher3/popup/RemoteActionShortcut.java
+++ b/src/com/android/launcher3/popup/RemoteActionShortcut.java
@@ -37,6 +37,7 @@ import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
@TargetApi(Build.VERSION_CODES.Q)
public class RemoteActionShortcut extends SystemShortcut {
@@ -106,6 +107,9 @@ public class RemoteActionShortcut extends SystemShortcut {
Toast.LENGTH_SHORT)
.show();
}
+
+ mTarget.getUserEventDispatcher().logActionOnControl(LauncherLogProto.Action.Touch.TAP,
+ LauncherLogProto.ControlType.REMOTE_ACTION_SHORTCUT, view);
}
@Override
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index 577fe4afaa..81302ac1f7 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -21,6 +21,8 @@ import com.android.launcher3.R;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.launcher3.util.InstantAppResolver;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
@@ -115,6 +117,8 @@ public abstract class SystemShortcut extends Ite
(WidgetsBottomSheet) mTarget.getLayoutInflater().inflate(
R.layout.widgets_bottom_sheet, mTarget.getDragLayer(), false);
widgetsBottomSheet.populateAndShow(mItemInfo);
+ mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
+ ControlType.WIDGETS_BUTTON, view);
mTarget.getStatsLogManager().logger().withItemInfo(mItemInfo)
.log(LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP);
}
@@ -135,6 +139,8 @@ public abstract class SystemShortcut extends Ite
Rect sourceBounds = mTarget.getViewBounds(view);
new PackageManagerHelper(mTarget).startDetailsActivityForInfo(
mItemInfo, sourceBounds, ActivityOptions.makeBasic().toBundle());
+ mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
+ ControlType.APPINFO_TARGET, view);
mTarget.getStatsLogManager().logger().withItemInfo(mItemInfo)
.log(LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP);
}
diff --git a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
index f4b059d8d8..4baecb7c56 100644
--- a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
+++ b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
@@ -306,15 +306,6 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat {
return true;
});
sandboxCategory.addPreference(launchAssistantTutorialPreference);
- Preference launchSandboxModeTutorialPreference = new Preference(context);
- launchSandboxModeTutorialPreference.setKey("launchSandboxMode");
- launchSandboxModeTutorialPreference.setTitle("Launch Sandbox Mode");
- launchSandboxModeTutorialPreference.setSummary("Practice navigation gestures");
- launchSandboxModeTutorialPreference.setOnPreferenceClickListener(preference -> {
- startActivity(launchSandboxIntent.putExtra("tutorial_type", "SANDBOX_MODE"));
- return true;
- });
- sandboxCategory.addPreference(launchSandboxModeTutorialPreference);
}
private String toName(String action) {
diff --git a/src/com/android/launcher3/states/HintState.java b/src/com/android/launcher3/states/HintState.java
index fd1d965982..b8a184fcfc 100644
--- a/src/com/android/launcher3/states/HintState.java
+++ b/src/com/android/launcher3/states/HintState.java
@@ -15,12 +15,11 @@
*/
package com.android.launcher3.states;
-import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
-
import android.content.Context;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
/**
* Scale down workspace/hotseat to hint at going to either overview (on pause) or first home screen.
@@ -31,7 +30,7 @@ public class HintState extends LauncherState {
| FLAG_HAS_SYS_UI_SCRIM;
public HintState(int id) {
- super(id, LAUNCHER_STATE_HOME, STATE_FLAGS);
+ super(id, ContainerType.DEFAULT_CONTAINERTYPE, STATE_FLAGS);
}
@Override
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index 45172b56ef..2a4f887503 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -15,8 +15,6 @@
*/
package com.android.launcher3.states;
-import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
-
import android.content.Context;
import android.graphics.Rect;
@@ -24,6 +22,7 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Workspace;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
/**
* Definition for spring loaded state used during drag and drop.
@@ -36,7 +35,7 @@ public class SpringLoadedState extends LauncherState {
| FLAG_HIDE_BACK_BUTTON;
public SpringLoadedState(int id) {
- super(id, LAUNCHER_STATE_HOME, STATE_FLAGS);
+ super(id, ContainerType.WORKSPACE, STATE_FLAGS);
}
@Override
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 9fd53e2563..8ee5a6e533 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -21,9 +21,6 @@ import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS;
-import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_ALLAPPS;
-import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
-import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_UNKNOWN_SWIPEDOWN;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_UNKNOWN_SWIPEUP;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
@@ -55,6 +52,9 @@ import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
import com.android.launcher3.testing.TestProtocol;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.FlingBlockCheck;
import com.android.launcher3.util.TouchController;
@@ -190,6 +190,11 @@ public abstract class AbstractStateChangeTouchController
protected abstract float initCurrentAnimation(@AnimationFlags int animComponents);
+ /**
+ * Returns the container that the touch started from when leaving NORMAL state.
+ */
+ protected abstract int getLogContainerTypeForNormalState(MotionEvent ev);
+
private boolean reinitCurrentAnimation(boolean reachedToState, boolean isDragTowardPositive) {
LauncherState newFromState = mFromState == null ? mLauncher.getStateManager().getState()
: reachedToState ? mToState : mFromState;
@@ -302,11 +307,11 @@ public abstract class AbstractStateChangeTouchController
public boolean onDrag(float displacement, MotionEvent ev) {
if (!mIsLogContainerSet) {
if (mStartState == ALL_APPS) {
- mStartContainerType = LAUNCHER_STATE_ALLAPPS;
+ mStartContainerType = ContainerType.ALLAPPS;
} else if (mStartState == NORMAL) {
- mStartContainerType = LAUNCHER_STATE_HOME;
+ mStartContainerType = getLogContainerTypeForNormalState(ev);
} else if (mStartState == OVERVIEW) {
- mStartContainerType = LAUNCHER_STATE_OVERVIEW;
+ mStartContainerType = ContainerType.TASKSWITCHER;
}
mIsLogContainerSet = true;
}
@@ -396,6 +401,7 @@ public abstract class AbstractStateChangeTouchController
@Override
public void onDragEnd(float velocity) {
boolean fling = mDetector.isFling(velocity);
+ final int logAction = fling ? Touch.FLING : Touch.SWIPE;
boolean blockedFling = fling && mFlingBlockCheck.isBlocked();
if (blockedFling) {
@@ -452,7 +458,7 @@ public abstract class AbstractStateChangeTouchController
}
}
- mCurrentAnimation.setEndAction(() -> onSwipeInteractionCompleted(targetState));
+ mCurrentAnimation.setEndAction(() -> onSwipeInteractionCompleted(targetState, logAction));
ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
anim.setFloatValues(startProgress, endProgress);
maybeUpdateAtomicAnim(mFromState, targetState, targetState == mToState ? 1f : 0f);
@@ -516,7 +522,11 @@ public abstract class AbstractStateChangeTouchController
.setInterpolator(scrollInterpolatorForVelocity(velocity));
}
- protected void onSwipeInteractionCompleted(LauncherState targetState) {
+ protected int getDirectionForLog() {
+ return mToState.ordinal > mFromState.ordinal ? Direction.UP : Direction.DOWN;
+ }
+
+ protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
if (mAtomicComponentsController != null) {
mAtomicComponentsController.getAnimationPlayer().end();
mAtomicComponentsController = null;
@@ -525,18 +535,18 @@ public abstract class AbstractStateChangeTouchController
boolean shouldGoToTargetState = true;
if (mPendingAnimation != null) {
boolean reachedTarget = mToState == targetState;
- mPendingAnimation.finish(reachedTarget);
+ mPendingAnimation.finish(reachedTarget, logAction);
mPendingAnimation = null;
shouldGoToTargetState = !reachedTarget;
}
if (shouldGoToTargetState) {
- goToTargetState(targetState);
+ goToTargetState(targetState, logAction);
}
}
- protected void goToTargetState(LauncherState targetState) {
+ protected void goToTargetState(LauncherState targetState, int logAction) {
if (targetState != mStartState) {
- logReachedState(targetState);
+ logReachedState(logAction, targetState);
}
if (!mLauncher.isInState(targetState)) {
// If we're already in the target state, don't jump to it at the end of the animation in
@@ -546,18 +556,24 @@ public abstract class AbstractStateChangeTouchController
mLauncher.getDragLayer().getScrim().createSysuiMultiplierAnim(1f).setDuration(0).start();
}
- private void logReachedState(LauncherState targetState) {
+ private void logReachedState(int logAction, LauncherState targetState) {
// Transition complete. log the action
+ mLauncher.getUserEventDispatcher().logStateChangeAction(logAction,
+ getDirectionForLog(), mDetector.getDownX(), mDetector.getDownY(),
+ mStartContainerType /* e.g., hotseat */,
+ mStartState.containerType /* e.g., workspace */,
+ targetState.containerType,
+ mLauncher.getWorkspace().getCurrentPage());
mLauncher.getStatsLogManager().logger()
- .withSrcState(mStartState.statsLogOrdinal)
- .withDstState(targetState.statsLogOrdinal)
+ .withSrcState(StatsLogManager.containerTypeToAtomState(mStartState.containerType))
+ .withDstState(StatsLogManager.containerTypeToAtomState(targetState.containerType))
.withContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
.setWorkspace(
LauncherAtom.WorkspaceContainer.newBuilder()
.setPageIndex(mLauncher.getWorkspace().getCurrentPage()))
.build())
- .log(StatsLogManager.getLauncherAtomEvent(mStartState.statsLogOrdinal,
- targetState.statsLogOrdinal, mToState.ordinal > mFromState.ordinal
+ .log(StatsLogManager.getLauncherAtomEvent(mStartState.containerType,
+ targetState.containerType, mToState.ordinal > mFromState.ordinal
? LAUNCHER_UNKNOWN_SWIPEUP
: LAUNCHER_UNKNOWN_SWIPEDOWN));
}
diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java
index f9dcf2d2e9..4a202b65d8 100644
--- a/src/com/android/launcher3/touch/AllAppsSwipeController.java
+++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java
@@ -24,6 +24,7 @@ import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
/**
* TouchController to switch between NORMAL and ALL_APPS state.
@@ -68,6 +69,12 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController {
return fromState;
}
+ @Override
+ protected int getLogContainerTypeForNormalState(MotionEvent ev) {
+ return mLauncher.getDragLayer().isEventOverView(mLauncher.getHotseat(), mTouchDownEvent)
+ ? ContainerType.HOTSEAT : ContainerType.WORKSPACE;
+ }
+
@Override
protected float initCurrentAnimation(@AnimationFlags int animComponents) {
float range = getShiftRange();
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index d56391da3d..61d6f7d804 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -25,9 +25,7 @@ import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_SA
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
import android.app.AlertDialog;
-import android.app.PendingIntent;
import android.content.Intent;
-import android.content.IntentSender;
import android.content.pm.LauncherApps;
import android.content.pm.PackageInstaller.SessionInfo;
import android.os.Process;
@@ -51,7 +49,6 @@ import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.PromiseAppInfo;
-import com.android.launcher3.model.data.RemoteActionItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.testing.TestLogging;
@@ -239,27 +236,6 @@ public class ItemClickHandler {
startAppShortcutOrInfoActivity(v, shortcut, launcher);
}
- /**
- * Event handler for a {@link android.app.RemoteAction} click
- *
- */
- public static void onClickRemoteAction(Launcher launcher,
- RemoteActionItemInfo remoteActionInfo) {
- try {
- PendingIntent pendingIntent = remoteActionInfo.getRemoteAction().getActionIntent();
- if (remoteActionInfo.shouldStartInLauncher()) {
- launcher.startIntentSenderForResult(pendingIntent.getIntentSender(), 0, null, 0, 0,
- 0);
- } else {
- pendingIntent.send();
- }
- } catch (PendingIntent.CanceledException | IntentSender.SendIntentException e) {
- Toast.makeText(launcher,
- launcher.getResources().getText(R.string.shortcut_not_available),
- Toast.LENGTH_SHORT).show();
- }
- }
-
private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN, "start: startAppShortcutOrInfoActivity");
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index 17f02be5b4..fb02f79c49 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -72,6 +72,7 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
out.halfPageSize = view.getNormalChildHeight() / 2;
out.halfScreenSize = view.getMeasuredHeight() / 2;
out.screenCenter = insets.top + view.getPaddingTop() + out.scroll + out.halfPageSize;
+ out.pageParentScale = view.getScaleY();
}
@Override
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index 114b75acec..354d78d0ac 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -112,6 +112,7 @@ public interface PagedOrientationHandler {
public int halfPageSize;
public int screenCenter;
public int halfScreenSize;
+ public float pageParentScale;
}
class ChildBounds {
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 5f5b2d1feb..06479e6b6a 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -70,6 +70,7 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
out.halfPageSize = view.getNormalChildWidth() / 2;
out.halfScreenSize = view.getMeasuredWidth() / 2;
out.screenCenter = insets.left + view.getPaddingLeft() + out.scroll + out.halfPageSize;
+ out.pageParentScale = view.getScaleX();
}
@Override
diff --git a/src/com/android/launcher3/util/Executors.java b/src/com/android/launcher3/util/Executors.java
index a85ae458ed..0a32734fca 100644
--- a/src/com/android/launcher3/util/Executors.java
+++ b/src/com/android/launcher3/util/Executors.java
@@ -20,10 +20,8 @@ import android.os.Looper;
import android.os.Process;
import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* Various different executors used in Launcher
@@ -85,29 +83,4 @@ public class Executors {
*/
public static final LooperExecutor MODEL_EXECUTOR =
new LooperExecutor(createAndStartNewLooper("launcher-loader"));
-
- /**
- * A simple ThreadFactory to set the thread name and priority when used with executors.
- */
- public static class SimpleThreadFactory implements ThreadFactory {
-
- private final int mPriority;
- private final String mNamePrefix;
-
- private final AtomicInteger mCount = new AtomicInteger(0);
-
- public SimpleThreadFactory(String namePrefix, int priority) {
- mNamePrefix = namePrefix;
- mPriority = priority;
- }
-
- @Override
- public Thread newThread(Runnable runnable) {
- Thread t = new Thread(() -> {
- Process.setThreadPriority(mPriority);
- runnable.run();
- }, mNamePrefix + mCount.incrementAndGet());
- return t;
- }
- }
}
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index d9a14e9e3f..52a82f8e93 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.views;
+import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
import static com.android.launcher3.Utilities.getBadge;
import static com.android.launcher3.Utilities.getFullDrawable;
import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
@@ -22,6 +23,9 @@ import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
@@ -70,6 +74,7 @@ public class FloatingIconView extends FrameLayout implements
private static @Nullable IconLoadResult sIconLoadResult;
public static final float SHAPE_PROGRESS_DURATION = 0.10f;
+ private static final int FADE_DURATION_MS = 200;
private static final RectF sTmpRectF = new RectF();
private static final Object[] sTmpObjArray = new Object[1];
@@ -84,9 +89,6 @@ public class FloatingIconView extends FrameLayout implements
private IconLoadResult mIconLoadResult;
- // Draw the drawable of the BubbleTextView behind ClipIconView to reveal the built in shadow.
- private View mBtvDrawable;
-
private ClipIconView mClipIconView;
private @Nullable Drawable mBadge;
@@ -96,6 +98,7 @@ public class FloatingIconView extends FrameLayout implements
private final Rect mFinalDrawableBounds = new Rect();
+ private AnimatorSet mFadeAnimatorSet;
private ListenerView mListenerView;
private Runnable mFastFinishRunnable;
@@ -113,8 +116,6 @@ public class FloatingIconView extends FrameLayout implements
mIsRtl = Utilities.isRtl(getResources());
mListenerView = new ListenerView(context, attrs);
mClipIconView = new ClipIconView(context, attrs);
- mBtvDrawable = new ImageView(context, attrs);
- addView(mBtvDrawable);
addView(mClipIconView);
setWillNotDraw(false);
}
@@ -175,7 +176,6 @@ public class FloatingIconView extends FrameLayout implements
setLayoutParams(lp);
mClipIconView.setLayoutParams(new FrameLayout.LayoutParams(lp.width, lp.height));
- mBtvDrawable.setLayoutParams(new FrameLayout.LayoutParams(lp.width, lp.height));
}
private void updatePosition(RectF pos, InsettableFrameLayout.LayoutParams lp) {
@@ -292,8 +292,6 @@ public class FloatingIconView extends FrameLayout implements
drawable = drawable == null ? null : drawable.getConstantState().newDrawable();
int iconOffset = getOffsetForIconBounds(l, drawable, pos);
synchronized (iconLoadResult) {
- iconLoadResult.btvDrawable = btvIcon == null || drawable == btvIcon
- ? null : btvIcon.getConstantState().newDrawable();
iconLoadResult.drawable = drawable;
iconLoadResult.badge = badge;
iconLoadResult.iconOffset = iconOffset;
@@ -313,8 +311,7 @@ public class FloatingIconView extends FrameLayout implements
* @param iconOffset The amount of offset needed to match this view with the original view.
*/
@UiThread
- private void setIcon(@Nullable Drawable drawable, @Nullable Drawable badge,
- @Nullable Drawable btvIcon, int iconOffset) {
+ private void setIcon(@Nullable Drawable drawable, @Nullable Drawable badge, int iconOffset) {
final InsettableFrameLayout.LayoutParams lp =
(InsettableFrameLayout.LayoutParams) getLayoutParams();
mBadge = badge;
@@ -345,10 +342,6 @@ public class FloatingIconView extends FrameLayout implements
mBadge.setBounds(0, 0, clipViewOgWidth, clipViewOgHeight);
}
}
-
- if (!mIsOpening && btvIcon != null) {
- mBtvDrawable.setBackground(btvIcon);
- }
invalidate();
}
@@ -367,7 +360,7 @@ public class FloatingIconView extends FrameLayout implements
synchronized (mIconLoadResult) {
if (mIconLoadResult.isIconLoaded) {
setIcon(mIconLoadResult.drawable, mIconLoadResult.badge,
- mIconLoadResult.btvDrawable, mIconLoadResult.iconOffset);
+ mIconLoadResult.iconOffset);
setIconAndDotVisible(originalView, false);
} else {
mIconLoadResult.onIconLoaded = () -> {
@@ -376,7 +369,7 @@ public class FloatingIconView extends FrameLayout implements
}
setIcon(mIconLoadResult.drawable, mIconLoadResult.badge,
- mIconLoadResult.btvDrawable, mIconLoadResult.iconOffset);
+ mIconLoadResult.iconOffset);
setVisibility(VISIBLE);
setIconAndDotVisible(originalView, false);
@@ -441,6 +434,10 @@ public class FloatingIconView extends FrameLayout implements
mEndRunnable.run();
mEndRunnable = null;
}
+ if (mFadeAnimatorSet != null) {
+ mFadeAnimatorSet.end();
+ mFadeAnimatorSet = null;
+ }
}
@Override
@@ -549,16 +546,8 @@ public class FloatingIconView extends FrameLayout implements
setIconAndDotVisible(originalView, true);
view.finish(dragLayer);
} else {
- originalView.setVisibility(VISIBLE);
- if (originalView instanceof IconLabelDotView) {
- setIconAndDotVisible(originalView, true);
- }
- if (originalView instanceof BubbleTextView) {
- BubbleTextView btv = (BubbleTextView) originalView;
- btv.setIconVisible(true);
- btv.setForceHideDot(true);
- }
- view.finish(dragLayer);
+ view.mFadeAnimatorSet = view.createFadeAnimation(originalView, dragLayer);
+ view.mFadeAnimatorSet.start();
}
} else {
view.finish(dragLayer);
@@ -575,6 +564,47 @@ public class FloatingIconView extends FrameLayout implements
return view;
}
+ private AnimatorSet createFadeAnimation(View originalView, DragLayer dragLayer) {
+ AnimatorSet fade = new AnimatorSet();
+ fade.setDuration(FADE_DURATION_MS);
+ fade.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ originalView.setVisibility(VISIBLE);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ finish(dragLayer);
+ }
+ });
+
+ if (originalView instanceof IconLabelDotView) {
+ fade.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ setIconAndDotVisible(originalView, true);
+ }
+ });
+ }
+
+ if (originalView instanceof BubbleTextView) {
+ BubbleTextView btv = (BubbleTextView) originalView;
+ fade.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ btv.setIconVisible(true);
+ btv.setForceHideDot(true);
+ }
+ });
+ fade.play(ObjectAnimator.ofInt(btv.getIcon(), DRAWABLE_ALPHA, 0, 255));
+ } else if (!(originalView instanceof FolderIcon)) {
+ fade.play(ObjectAnimator.ofFloat(originalView, ALPHA, 0f, 1f));
+ }
+
+ return fade;
+ }
+
private void finish(DragLayer dragLayer) {
((ViewGroup) dragLayer.getParent()).removeView(this);
dragLayer.removeView(mListenerView);
@@ -598,7 +628,11 @@ public class FloatingIconView extends FrameLayout implements
mLoadIconSignal = null;
mEndRunnable = null;
mFinalDrawableBounds.setEmpty();
+ if (mFadeAnimatorSet != null) {
+ mFadeAnimatorSet.cancel();
+ }
mPositionOut = null;
+ mFadeAnimatorSet = null;
mListenerView.setListener(null);
mOriginalIcon = null;
mOnTargetChangeRunnable = null;
@@ -606,13 +640,11 @@ public class FloatingIconView extends FrameLayout implements
sTmpObjArray[0] = null;
mIconLoadResult = null;
mClipIconView.recycle();
- mBtvDrawable.setBackground(null);
mFastFinishRunnable = null;
}
private static class IconLoadResult {
final ItemInfo itemInfo;
- Drawable btvDrawable;
Drawable drawable;
Drawable badge;
int iconOffset;
diff --git a/src/com/android/launcher3/views/HeroSearchResultView.java b/src/com/android/launcher3/views/HeroSearchResultView.java
index dd322d921a..a8e1c6b30c 100644
--- a/src/com/android/launcher3/views/HeroSearchResultView.java
+++ b/src/com/android/launcher3/views/HeroSearchResultView.java
@@ -16,16 +16,12 @@
package com.android.launcher3.views;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ShortcutInfo;
import android.graphics.Point;
import android.os.Bundle;
import android.util.AttributeSet;
-import android.util.Pair;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
@@ -35,10 +31,9 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
-import com.android.launcher3.allapps.search.AllAppsSearchBarController.PayloadResultHandler;
+import com.android.launcher3.allapps.search.AllAppsSearchBarController;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.graphics.DragPreviewProvider;
@@ -58,10 +53,9 @@ import java.util.List;
* A view representing a high confidence app search result that includes shortcuts
*/
public class HeroSearchResultView extends LinearLayout implements DragSource,
- PayloadResultHandler>> {
+ AllAppsSearchBarController.PayloadResultHandler> {
public static final int MAX_SHORTCUTS_COUNT = 2;
- private final Object[] mTargetInfo = createTargetInfo();
BubbleTextView mBubbleTextView;
View mIconView;
BubbleTextView[] mDeepShortcutTextViews = new BubbleTextView[2];
@@ -108,7 +102,7 @@ public class HeroSearchResultView extends LinearLayout implements DragSource,
grid.allAppsIconSizePx));
bubbleTextView.setOnClickListener(view -> {
WorkspaceItemInfo itemInfo = (WorkspaceItemInfo) bubbleTextView.getTag();
- SearchTargetEvent event = getSearchTargetEvent(
+ SearchTargetEvent event = new SearchTargetEvent(
SearchTarget.ItemType.APP_HERO,
SearchTargetEvent.CHILD_SELECT);
event.bundle = getAppBundle(itemInfo);
@@ -125,36 +119,21 @@ public class HeroSearchResultView extends LinearLayout implements DragSource,
* Apply {@link ItemInfo} for appIcon and shortcut Icons
*/
@Override
- public void applyAdapterInfo(
- AdapterItemWithPayload>> adapterItem) {
+ public void applyAdapterInfo(AdapterItemWithPayload> adapterItem) {
mBubbleTextView.applyFromApplicationInfo(adapterItem.appInfo);
mIconView.setBackground(mBubbleTextView.getIcon());
mIconView.setTag(adapterItem.appInfo);
- List> shortcutDetails = adapterItem.getPayload();
- LauncherAppState appState = LauncherAppState.getInstance(getContext());
+ List shorcutInfos = adapterItem.getPayload();
for (int i = 0; i < mDeepShortcutTextViews.length; i++) {
- BubbleTextView shortcutView = mDeepShortcutTextViews[i];
- mDeepShortcutTextViews[i].setVisibility(shortcutDetails.size() > i ? VISIBLE : GONE);
- if (i < shortcutDetails.size()) {
- Pair p = shortcutDetails.get(i);
- //apply ItemInfo and prepare view
- shortcutView.applyFromWorkspaceItem((WorkspaceItemInfo) p.second);
- MODEL_EXECUTOR.execute(() -> {
- // load unbadged shortcut in background and update view when icon ready
- appState.getIconCache().getUnbadgedShortcutIcon(p.second, p.first);
- MAIN_EXECUTOR.post(() -> shortcutView.reapplyItemInfo(p.second));
- });
+ mDeepShortcutTextViews[i].setVisibility(shorcutInfos.size() > i ? VISIBLE : GONE);
+ if (i < shorcutInfos.size()) {
+ mDeepShortcutTextViews[i].applyFromItemInfoWithIcon(shorcutInfos.get(i));
}
}
mPlugin = adapterItem.getPlugin();
adapterItem.setSelectionHandler(this::handleSelection);
}
- @Override
- public Object[] getTargetInfo() {
- return mTargetInfo;
- }
-
@Override
public void onDropCompleted(View target, DropTarget.DragObject d, boolean success) {
mBubbleTextView.setVisibility(VISIBLE);
@@ -190,7 +169,7 @@ public class HeroSearchResultView extends LinearLayout implements DragSource,
mLauncher.getWorkspace().beginDragShared(mContainer.mBubbleTextView,
draggableView, mContainer, itemInfo, previewProvider, new DragOptions());
- SearchTargetEvent event = mContainer.getSearchTargetEvent(
+ SearchTargetEvent event = new SearchTargetEvent(
SearchTarget.ItemType.APP_HERO, SearchTargetEvent.LONG_PRESS);
event.bundle = getAppBundle(itemInfo);
if (mContainer.mPlugin != null) {
@@ -207,7 +186,7 @@ public class HeroSearchResultView extends LinearLayout implements DragSource,
Launcher launcher = Launcher.getLauncher(getContext());
launcher.startActivitySafely(this, itemInfo.getIntent(), itemInfo);
- SearchTargetEvent event = getSearchTargetEvent(
+ SearchTargetEvent event = new SearchTargetEvent(
SearchTarget.ItemType.APP_HERO, eventType);
event.bundle = getAppBundle(itemInfo);
if (mPlugin != null) {
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 80f0981af5..3ec20d57a1 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -16,7 +16,6 @@
package com.android.launcher3.views;
import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_FLAVOR;
-import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_LAUNCH_SOURCE;
import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_OFFSET;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS;
@@ -133,7 +132,7 @@ public class OptionsPopupView extends ArrowPopup
view.setOnLongClickListener(popup);
popup.mItemMap.put(view, item);
}
- popup.show();
+ popup.reorderAndShow(popup.getChildCount());
}
@VisibleForTesting
@@ -212,8 +211,7 @@ public class OptionsPopupView extends ArrowPopup
Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
.putExtra(EXTRA_WALLPAPER_OFFSET,
- launcher.getWorkspace().getWallpaperOffsetForCenterPage())
- .putExtra(EXTRA_WALLPAPER_LAUNCH_SOURCE, "app_launched_launcher");
+ launcher.getWorkspace().getWallpaperOffsetForCenterPage());
if (!Utilities.existsStyleWallpapers(launcher)) {
intent.putExtra(EXTRA_WALLPAPER_FLAVOR, "wallpaper_only");
} else {
diff --git a/src/com/android/launcher3/views/SearchResultIconRow.java b/src/com/android/launcher3/views/SearchResultIconRow.java
deleted file mode 100644
index 313ae5e611..0000000000
--- a/src/com/android/launcher3/views/SearchResultIconRow.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.views;
-
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
-import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-
-import android.app.RemoteAction;
-import android.content.Context;
-import android.content.pm.ShortcutInfo;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.Bundle;
-import android.util.AttributeSet;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
-import com.android.launcher3.allapps.search.AllAppsSearchBarController;
-import com.android.launcher3.icons.LauncherIcons;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.ItemInfoWithIcon;
-import com.android.launcher3.model.data.RemoteActionItemInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.touch.ItemClickHandler;
-import com.android.systemui.plugins.AllAppsSearchPlugin;
-import com.android.systemui.plugins.shared.SearchTarget;
-import com.android.systemui.plugins.shared.SearchTarget.ItemType;
-import com.android.systemui.plugins.shared.SearchTargetEvent;
-
-/**
- * A view representing a stand alone shortcut search result
- */
-public class SearchResultIconRow extends DoubleShadowBubbleTextView implements
- AllAppsSearchBarController.PayloadResultHandler {
-
- private final Object[] mTargetInfo = createTargetInfo();
- private ShortcutInfo mShortcutInfo;
- private AllAppsSearchPlugin mPlugin;
- private AdapterItemWithPayload mAdapterItem;
-
-
- public SearchResultIconRow(@NonNull Context context) {
- super(context);
- }
-
- public SearchResultIconRow(@NonNull Context context,
- @Nullable AttributeSet attrs) {
- super(context, attrs);
- }
-
- public SearchResultIconRow(@NonNull Context context, @Nullable AttributeSet attrs,
- int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- @Override
- public void applyAdapterInfo(AdapterItemWithPayload adapterItemWithPayload) {
- if (mAdapterItem != null) {
- mAdapterItem.setSelectionHandler(null);
- }
- mAdapterItem = adapterItemWithPayload;
- SearchTarget payload = adapterItemWithPayload.getPayload();
- mPlugin = adapterItemWithPayload.getPlugin();
-
- if (payload.mRemoteAction != null) {
- prepareUsingRemoteAction(payload.mRemoteAction,
- payload.bundle.getString(SearchTarget.REMOTE_ACTION_TOKEN),
- payload.bundle.getBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START));
- } else {
- prepareUsingShortcutInfo(payload.shortcuts.get(0));
- }
- setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT));
- adapterItemWithPayload.setSelectionHandler(this::handleSelection);
- }
-
- private void prepareUsingShortcutInfo(ShortcutInfo shortcutInfo) {
- mShortcutInfo = shortcutInfo;
- WorkspaceItemInfo workspaceItemInfo = new WorkspaceItemInfo(mShortcutInfo, getContext());
- applyFromWorkspaceItem(workspaceItemInfo);
- LauncherAppState launcherAppState = LauncherAppState.getInstance(getContext());
- MODEL_EXECUTOR.execute(() -> {
- launcherAppState.getIconCache().getShortcutIcon(workspaceItemInfo, mShortcutInfo);
- reapplyItemInfoAsync(workspaceItemInfo);
- });
- }
-
- private void prepareUsingRemoteAction(RemoteAction remoteAction, String token, boolean start) {
- RemoteActionItemInfo itemInfo = new RemoteActionItemInfo(remoteAction, token, start);
-
- applyFromRemoteActionInfo(itemInfo);
- UI_HELPER_EXECUTOR.post(() -> {
- // If the Drawable from the remote action is not AdaptiveBitmap, styling will not work.
- try (LauncherIcons li = LauncherIcons.obtain(getContext())) {
- Drawable d = itemInfo.getRemoteAction().getIcon().loadDrawable(getContext());
- itemInfo.bitmap = li.createBadgedIconBitmap(d, itemInfo.user,
- Build.VERSION.SDK_INT);
- reapplyItemInfoAsync(itemInfo);
- }
- });
-
- }
-
- void reapplyItemInfoAsync(ItemInfoWithIcon itemInfoWithIcon) {
- MAIN_EXECUTOR.post(() -> reapplyItemInfo(itemInfoWithIcon));
- }
-
- @Override
- public Object[] getTargetInfo() {
- return mTargetInfo;
- }
-
- private void handleSelection(int eventType) {
- ItemInfo itemInfo = (ItemInfo) getTag();
- Launcher launcher = Launcher.getLauncher(getContext());
- final SearchTargetEvent searchTargetEvent;
- if (itemInfo instanceof WorkspaceItemInfo) {
- ItemClickHandler.onClickAppShortcut(this, (WorkspaceItemInfo) itemInfo, launcher);
- searchTargetEvent = getSearchTargetEvent(SearchTarget.ItemType.SHORTCUT,
- eventType);
- searchTargetEvent.shortcut = mShortcutInfo;
- } else {
- RemoteActionItemInfo remoteItemInfo = (RemoteActionItemInfo) itemInfo;
- ItemClickHandler.onClickRemoteAction(launcher, remoteItemInfo);
- searchTargetEvent = getSearchTargetEvent(ItemType.ACTION,
- eventType);
- searchTargetEvent.bundle = new Bundle();
- searchTargetEvent.remoteAction = remoteItemInfo.getRemoteAction();
- searchTargetEvent.bundle.putBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START,
- remoteItemInfo.shouldStartInLauncher());
- searchTargetEvent.bundle.putString(SearchTarget.REMOTE_ACTION_TOKEN,
- remoteItemInfo.getToken());
- }
- if (mPlugin != null) {
- mPlugin.notifySearchTargetEvent(searchTargetEvent);
- }
- }
-}
diff --git a/src/com/android/launcher3/views/SearchResultPeopleView.java b/src/com/android/launcher3/views/SearchResultPeopleView.java
index 0c9a22f672..6e45e88b32 100644
--- a/src/com/android/launcher3/views/SearchResultPeopleView.java
+++ b/src/com/android/launcher3/views/SearchResultPeopleView.java
@@ -15,6 +15,9 @@
*/
package com.android.launcher3.views;
+import static android.content.Intent.URI_ALLOW_UNSAFE;
+import static android.content.Intent.URI_ANDROID_APP_SCHEME;
+
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -25,6 +28,7 @@ import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.View;
@@ -46,6 +50,7 @@ import com.android.systemui.plugins.AllAppsSearchPlugin;
import com.android.systemui.plugins.shared.SearchTarget;
import com.android.systemui.plugins.shared.SearchTargetEvent;
+import java.net.URISyntaxException;
import java.util.ArrayList;
/**
@@ -61,8 +66,8 @@ public class SearchResultPeopleView extends LinearLayout implements
private TextView mTitleView;
private ImageButton[] mProviderButtons = new ImageButton[3];
private AllAppsSearchPlugin mPlugin;
- private Intent mIntent;
- private final Object[] mTargetInfo = createTargetInfo();
+ private Uri mContactUri;
+
public SearchResultPeopleView(Context context) {
this(context, null, 0);
@@ -104,7 +109,7 @@ public class SearchResultPeopleView extends LinearLayout implements
Bundle payload = adapterItemWithPayload.getPayload();
mPlugin = adapterItemWithPayload.getPlugin();
mTitleView.setText(payload.getString("title"));
- mIntent = payload.getParcelable("intent");
+ mContactUri = payload.getParcelable("contact_uri");
Bitmap icon = payload.getParcelable("icon");
if (icon != null) {
RoundedBitmapDrawable d = RoundedBitmapDrawableFactory.create(getResources(), icon);
@@ -120,20 +125,25 @@ public class SearchResultPeopleView extends LinearLayout implements
for (int i = 0; i < mProviderButtons.length; i++) {
ImageButton button = mProviderButtons[i];
if (providers != null && i < providers.size()) {
- Bundle provider = providers.get(i);
- Intent intent = provider.getParcelable("intent");
- setupProviderButton(button, provider, intent, adapterItemWithPayload);
- String pkg = provider.getString("package_name");
- UI_HELPER_EXECUTOR.post(() -> {
- try {
- ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(
- pkg, 0);
- Drawable appIcon = applicationInfo.loadIcon(mPackageManager);
- MAIN_EXECUTOR.post(() -> button.setImageDrawable(appIcon));
- } catch (PackageManager.NameNotFoundException ignored) {
- }
+ try {
+ Bundle provider = providers.get(i);
+ Intent intent = Intent.parseUri(provider.getString("intent_uri_str"),
+ URI_ANDROID_APP_SCHEME | URI_ALLOW_UNSAFE);
+ setupProviderButton(button, provider, intent);
+ String pkg = provider.getString("package_name");
+ UI_HELPER_EXECUTOR.post(() -> {
+ try {
+ ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(
+ pkg, 0);
+ Drawable appIcon = applicationInfo.loadIcon(mPackageManager);
+ MAIN_EXECUTOR.post(()-> button.setImageDrawable(appIcon));
+ } catch (PackageManager.NameNotFoundException ignored) {
+ }
- });
+ });
+ } catch (URISyntaxException ex) {
+ button.setVisibility(GONE);
+ }
} else {
button.setVisibility(GONE);
}
@@ -141,21 +151,15 @@ public class SearchResultPeopleView extends LinearLayout implements
adapterItemWithPayload.setSelectionHandler(this::handleSelection);
}
- @Override
- public Object[] getTargetInfo() {
- return mTargetInfo;
- }
-
- private void setupProviderButton(ImageButton button, Bundle provider, Intent intent,
- AllAppsGridAdapter.AdapterItem adapterItem) {
+ private void setupProviderButton(ImageButton button, Bundle provider, Intent intent) {
Launcher launcher = Launcher.getLauncher(getContext());
button.setOnClickListener(b -> {
launcher.startActivitySafely(b, intent, null);
- SearchTargetEvent searchTargetEvent = getSearchTargetEvent(
+ SearchTargetEvent searchTargetEvent = new SearchTargetEvent(
SearchTarget.ItemType.PEOPLE,
SearchTargetEvent.CHILD_SELECT);
searchTargetEvent.bundle = new Bundle();
- searchTargetEvent.bundle.putParcelable("intent", mIntent);
+ searchTargetEvent.bundle.putParcelable("contact_uri", mContactUri);
searchTargetEvent.bundle.putBundle("provider", provider);
if (mPlugin != null) {
mPlugin.notifySearchTargetEvent(searchTargetEvent);
@@ -165,13 +169,14 @@ public class SearchResultPeopleView extends LinearLayout implements
private void handleSelection(int eventType) {
- if (mIntent != null) {
+ if (mContactUri != null) {
Launcher launcher = Launcher.getLauncher(getContext());
- launcher.startActivitySafely(this, mIntent, null);
- SearchTargetEvent searchTargetEvent = getSearchTargetEvent(SearchTarget.ItemType.PEOPLE,
- eventType);
+ launcher.startActivitySafely(this, new Intent(Intent.ACTION_VIEW, mContactUri).setFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK), null);
+ SearchTargetEvent searchTargetEvent = new SearchTargetEvent(
+ SearchTarget.ItemType.PEOPLE, eventType);
searchTargetEvent.bundle = new Bundle();
- searchTargetEvent.bundle.putParcelable("intent", mIntent);
+ searchTargetEvent.bundle.putParcelable("contact_uri", mContactUri);
if (mPlugin != null) {
mPlugin.notifySearchTargetEvent(searchTargetEvent);
}
diff --git a/src/com/android/launcher3/views/SearchResultPlayItem.java b/src/com/android/launcher3/views/SearchResultPlayItem.java
index ff3ecc8bc3..8624609f80 100644
--- a/src/com/android/launcher3/views/SearchResultPlayItem.java
+++ b/src/com/android/launcher3/views/SearchResultPlayItem.java
@@ -58,8 +58,6 @@ public class SearchResultPlayItem extends LinearLayout implements
private String mPackageName;
private boolean mIsInstantGame;
private AllAppsSearchPlugin mPlugin;
- private final Object[] mTargetInfo = createTargetInfo();
-
public SearchResultPlayItem(Context context) {
this(context, null, 0);
@@ -127,11 +125,6 @@ public class SearchResultPlayItem extends LinearLayout implements
});
}
- @Override
- public Object[] getTargetInfo() {
- return mTargetInfo;
- }
-
private void showIfNecessary(TextView textView, @Nullable String string) {
if (string == null || string.isEmpty()) {
textView.setVisibility(GONE);
@@ -167,7 +160,7 @@ public class SearchResultPlayItem extends LinearLayout implements
}
private void logSearchEvent(int eventType) {
- SearchTargetEvent searchTargetEvent = getSearchTargetEvent(
+ SearchTargetEvent searchTargetEvent = new SearchTargetEvent(
SearchTarget.ItemType.PLAY_RESULTS, eventType);
searchTargetEvent.bundle = new Bundle();
searchTargetEvent.bundle.putString("package_name", mPackageName);
diff --git a/src/com/android/launcher3/views/SearchResultShortcut.java b/src/com/android/launcher3/views/SearchResultShortcut.java
new file mode 100644
index 0000000000..307cf34c7d
--- /dev/null
+++ b/src/com/android/launcher3/views/SearchResultShortcut.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.views;
+
+import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+
+import android.content.Context;
+import android.content.pm.ShortcutInfo;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.R;
+import com.android.launcher3.allapps.AllAppsGridAdapter;
+import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.touch.ItemClickHandler;
+import com.android.systemui.plugins.AllAppsSearchPlugin;
+import com.android.systemui.plugins.shared.SearchTarget;
+import com.android.systemui.plugins.shared.SearchTargetEvent;
+
+/**
+ * A view representing a stand alone shortcut search result
+ */
+public class SearchResultShortcut extends FrameLayout implements
+ AllAppsSearchBarController.PayloadResultHandler {
+
+ private BubbleTextView mBubbleTextView;
+ private View mIconView;
+ private ShortcutInfo mShortcutInfo;
+ private AllAppsSearchPlugin mPlugin;
+
+ public SearchResultShortcut(@NonNull Context context) {
+ super(context);
+ }
+
+ public SearchResultShortcut(@NonNull Context context,
+ @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public SearchResultShortcut(@NonNull Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ Launcher launcher = Launcher.getLauncher(getContext());
+ DeviceProfile grid = launcher.getDeviceProfile();
+ mIconView = findViewById(R.id.icon);
+ ViewGroup.LayoutParams iconParams = mIconView.getLayoutParams();
+ iconParams.height = grid.allAppsIconSizePx;
+ iconParams.width = grid.allAppsIconSizePx;
+ mBubbleTextView = findViewById(R.id.bubble_text);
+ setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT));
+ }
+
+ @Override
+ public void applyAdapterInfo(
+ AllAppsGridAdapter.AdapterItemWithPayload adapterItemWithPayload) {
+ SearchTarget payload = adapterItemWithPayload.getPayload();
+ mPlugin = adapterItemWithPayload.getPlugin();
+ mShortcutInfo = payload.shortcuts.get(0);
+ WorkspaceItemInfo workspaceItemInfo = new WorkspaceItemInfo(mShortcutInfo, getContext());
+ mBubbleTextView.applyFromWorkspaceItem(workspaceItemInfo);
+ mIconView.setBackground(mBubbleTextView.getIcon());
+ LauncherAppState launcherAppState = LauncherAppState.getInstance(getContext());
+ MODEL_EXECUTOR.execute(() -> {
+ launcherAppState.getIconCache().getShortcutIcon(workspaceItemInfo, mShortcutInfo);
+ mBubbleTextView.applyFromWorkspaceItem(workspaceItemInfo);
+ mIconView.setBackground(mBubbleTextView.getIcon());
+ });
+ adapterItemWithPayload.setSelectionHandler(this::handleSelection);
+ }
+
+ private void handleSelection(int eventType) {
+ WorkspaceItemInfo itemInfo = (WorkspaceItemInfo) mBubbleTextView.getTag();
+ ItemClickHandler.onClickAppShortcut(this, itemInfo, Launcher.getLauncher(getContext()));
+
+ SearchTargetEvent searchTargetEvent = new SearchTargetEvent(
+ SearchTarget.ItemType.SHORTCUT, eventType);
+ searchTargetEvent.shortcut = mShortcutInfo;
+ if (mPlugin != null) {
+ mPlugin.notifySearchTargetEvent(searchTargetEvent);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/views/SearchResultSuggestRow.java b/src/com/android/launcher3/views/SearchResultSuggestRow.java
deleted file mode 100644
index b5abbcc724..0000000000
--- a/src/com/android/launcher3/views/SearchResultSuggestRow.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.views;
-
-import static com.android.systemui.plugins.shared.SearchTarget.ItemType.SUGGEST;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
-import com.android.launcher3.allapps.search.AllAppsSearchBarController;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.RemoteActionItemInfo;
-import com.android.launcher3.touch.ItemClickHandler;
-import com.android.systemui.plugins.AllAppsSearchPlugin;
-import com.android.systemui.plugins.shared.SearchTarget;
-import com.android.systemui.plugins.shared.SearchTargetEvent;
-
-/**
- * A view representing a fallback search suggestion row.
- */
-public class SearchResultSuggestRow extends LinearLayout implements
- View.OnClickListener, AllAppsSearchBarController.PayloadResultHandler {
-
- private final Object[] mTargetInfo = createTargetInfo();
- private AllAppsSearchPlugin mPlugin;
- private AdapterItemWithPayload mAdapterItem;
- private TextView mTitle;
-
-
- public SearchResultSuggestRow(@NonNull Context context) {
- super(context);
- }
-
- public SearchResultSuggestRow(@NonNull Context context,
- @Nullable AttributeSet attrs) {
- super(context, attrs);
- }
-
- public SearchResultSuggestRow(@NonNull Context context, @Nullable AttributeSet attrs,
- int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mTitle = findViewById(R.id.title);
- setOnClickListener(this);
- }
- @Override
- public void applyAdapterInfo(AdapterItemWithPayload adapterItemWithPayload) {
- mAdapterItem = adapterItemWithPayload;
- SearchTarget payload = adapterItemWithPayload.getPayload();
- mPlugin = adapterItemWithPayload.getPlugin();
-
- if (payload.mRemoteAction != null) {
- RemoteActionItemInfo itemInfo = new RemoteActionItemInfo(payload.mRemoteAction,
- payload.bundle.getString(SearchTarget.REMOTE_ACTION_TOKEN),
- payload.bundle.getBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START));
- setTag(itemInfo);
- }
- showIfAvailable(mTitle, payload.mRemoteAction.getTitle().toString());
- setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT));
- adapterItemWithPayload.setSelectionHandler(this::handleSelection);
- }
-
- @Override
- public Object[] getTargetInfo() {
- return mTargetInfo;
- }
-
- private void handleSelection(int eventType) {
- ItemInfo itemInfo = (ItemInfo) getTag();
- Launcher launcher = Launcher.getLauncher(getContext());
- if (itemInfo instanceof RemoteActionItemInfo) return;
-
- RemoteActionItemInfo remoteItemInfo = (RemoteActionItemInfo) itemInfo;
- ItemClickHandler.onClickRemoteAction(launcher, remoteItemInfo);
- SearchTargetEvent searchTargetEvent = getSearchTargetEvent(SUGGEST, eventType);
- searchTargetEvent.bundle = new Bundle();
- searchTargetEvent.remoteAction = remoteItemInfo.getRemoteAction();
- searchTargetEvent.bundle.putBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START,
- remoteItemInfo.shouldStartInLauncher());
- searchTargetEvent.bundle.putString(SearchTarget.REMOTE_ACTION_TOKEN,
- remoteItemInfo.getToken());
-
- if (mPlugin != null) {
- mPlugin.notifySearchTargetEvent(searchTargetEvent);
- }
- }
-
- @Override
- public void onClick(View view) {
- handleSelection(SearchTargetEvent.SELECT);
- }
-
- private void showIfAvailable(TextView view, @Nullable String string) {
- System.out.println("Plugin suggest string:" + string);
- if (TextUtils.isEmpty(string)) {
- view.setVisibility(GONE);
- } else {
- System.out.println("Plugin suggest string:" + string);
- view.setVisibility(VISIBLE);
- view.setText(string);
- }
- }
-}
diff --git a/src/com/android/launcher3/views/SearchSectionHeaderView.java b/src/com/android/launcher3/views/SearchSectionHeaderView.java
index 0fe0a43ff5..d439ee3d68 100644
--- a/src/com/android/launcher3/views/SearchSectionHeaderView.java
+++ b/src/com/android/launcher3/views/SearchSectionHeaderView.java
@@ -52,9 +52,4 @@ public class SearchSectionHeaderView extends TextView implements
setVisibility(INVISIBLE);
}
}
-
- @Override
- public Object[] getTargetInfo() {
- return null;
- }
}
diff --git a/src/com/android/launcher3/views/SearchSettingsRowView.java b/src/com/android/launcher3/views/SearchSettingsRowView.java
index a1a0172547..93bcee2585 100644
--- a/src/com/android/launcher3/views/SearchSettingsRowView.java
+++ b/src/com/android/launcher3/views/SearchSettingsRowView.java
@@ -48,8 +48,6 @@ public class SearchSettingsRowView extends LinearLayout implements
private TextView mBreadcrumbsView;
private Intent mIntent;
private AllAppsSearchPlugin mPlugin;
- private final Object[] mTargetInfo = createTargetInfo();
-
public SearchSettingsRowView(@NonNull Context context) {
super(context);
@@ -89,11 +87,6 @@ public class SearchSettingsRowView extends LinearLayout implements
adapterItemWithPayload.setSelectionHandler(this::handleSelection);
}
- @Override
- public Object[] getTargetInfo() {
- return mTargetInfo;
- }
-
private void showIfAvailable(TextView view, @Nullable String string) {
if (TextUtils.isEmpty(string)) {
view.setVisibility(GONE);
@@ -115,7 +108,7 @@ public class SearchSettingsRowView extends LinearLayout implements
Launcher launcher = Launcher.getLauncher(getContext());
launcher.startActivityForResult(mIntent, 0);
- SearchTargetEvent searchTargetEvent = getSearchTargetEvent(
+ SearchTargetEvent searchTargetEvent = new SearchTargetEvent(
SearchTarget.ItemType.SETTINGS_ROW, eventType);
searchTargetEvent.bundle = new Bundle();
searchTargetEvent.bundle.putParcelable("intent", mIntent);
diff --git a/src/com/android/launcher3/views/ThumbnailSearchResultView.java b/src/com/android/launcher3/views/ThumbnailSearchResultView.java
deleted file mode 100644
index bbc47739f3..0000000000
--- a/src/com/android/launcher3/views/ThumbnailSearchResultView.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.views;
-
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.net.Uri;
-import android.util.AttributeSet;
-
-import androidx.core.graphics.drawable.RoundedBitmapDrawable;
-import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
-import com.android.launcher3.allapps.search.AllAppsSearchBarController;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.RemoteActionItemInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.touch.ItemClickHandler;
-import com.android.launcher3.util.Themes;
-import com.android.systemui.plugins.AllAppsSearchPlugin;
-import com.android.systemui.plugins.shared.SearchTarget;
-import com.android.systemui.plugins.shared.SearchTargetEvent;
-
-/**
- * A view representing a high confidence app search result that includes shortcuts
- */
-public class ThumbnailSearchResultView extends androidx.appcompat.widget.AppCompatImageView
- implements AllAppsSearchBarController.PayloadResultHandler {
-
- private final Object[] mTargetInfo = createTargetInfo();
- AllAppsSearchPlugin mPlugin;
- int mPosition;
-
- public ThumbnailSearchResultView(Context context) {
- super(context);
- }
-
- public ThumbnailSearchResultView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public ThumbnailSearchResultView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- private void handleSelection(int eventType) {
- Launcher launcher = Launcher.getLauncher(getContext());
- ItemInfo itemInfo = (ItemInfo) getTag();
- if (itemInfo instanceof RemoteActionItemInfo) {
- RemoteActionItemInfo remoteItemInfo = (RemoteActionItemInfo) itemInfo;
- ItemClickHandler.onClickRemoteAction(launcher, remoteItemInfo);
- } else {
- ItemClickHandler.onClickAppShortcut(this, (WorkspaceItemInfo) itemInfo, launcher);
- }
- if (mPlugin != null) {
- SearchTargetEvent event = getSearchTargetEvent(
- SearchTarget.ItemType.SCREENSHOT, eventType);
- mPlugin.notifySearchTargetEvent(event);
- }
- }
-
- @Override
- public void applyAdapterInfo(AdapterItemWithPayload adapterItem) {
- Launcher launcher = Launcher.getLauncher(getContext());
- mPosition = adapterItem.position;
-
- SearchTarget target = adapterItem.getPayload();
- Bitmap bitmap;
- if (target.mRemoteAction != null) {
- RemoteActionItemInfo itemInfo = new RemoteActionItemInfo(target.mRemoteAction,
- target.bundle.getString(SearchTarget.REMOTE_ACTION_TOKEN),
- target.bundle.getBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START));
- ItemClickHandler.onClickRemoteAction(launcher, itemInfo);
- bitmap = ((BitmapDrawable) target.mRemoteAction.getIcon()
- .loadDrawable(getContext())).getBitmap();
- setTag(itemInfo);
- } else {
- bitmap = (Bitmap) target.bundle.getParcelable("bitmap");
- WorkspaceItemInfo itemInfo = new WorkspaceItemInfo();
- itemInfo.intent = new Intent(Intent.ACTION_VIEW)
- .setData(Uri.parse(target.bundle.getString("uri")))
- .setType("image/*")
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- setTag(itemInfo);
- }
- RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(null, bitmap);
- drawable.setCornerRadius(Themes.getDialogCornerRadius(getContext()));
- setImageDrawable(drawable);
- setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT));
- mPlugin = adapterItem.getPlugin();
- adapterItem.setSelectionHandler(this::handleSelection);
- }
-
- @Override
- public Object[] getTargetInfo() {
- return mTargetInfo;
- }
-}
diff --git a/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java b/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java
index aa3ab8f7e0..4fa670f44a 100644
--- a/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java
+++ b/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java
@@ -32,7 +32,7 @@ import java.util.function.Consumer;
@ProvidesInterface(action = AllAppsSearchPlugin.ACTION, version = AllAppsSearchPlugin.VERSION)
public interface AllAppsSearchPlugin extends Plugin {
String ACTION = "com.android.systemui.action.PLUGIN_ALL_APPS_SEARCH_ACTIONS";
- int VERSION = 7;
+ int VERSION = 6;
void setup(Activity activity, View view);
@@ -42,12 +42,6 @@ public interface AllAppsSearchPlugin extends Plugin {
void onStateTransitionStart(int fromState, int toState);
void onStateTransitionComplete(int state);
- /**
- * Send launcher window focus and visibility changed signals.
- */
- void onWindowFocusChanged(boolean hasFocus);
- void onWindowVisibilityChanged(int visibility);
-
/**
* Send signal when user starts typing, perform search, when search ends
*/
diff --git a/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java b/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java
index 3f0dc39cc1..c6b8300499 100644
--- a/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java
+++ b/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java
@@ -15,7 +15,6 @@
*/
package com.android.systemui.plugins.shared;
-import android.app.RemoteAction;
import android.content.pm.ShortcutInfo;
import android.os.Bundle;
@@ -26,69 +25,17 @@ import java.util.List;
*/
public class SearchTarget implements Comparable {
-
- /**
- * A bundle key for boolean value of whether remote action should be started in launcher or not
- */
- public static final String REMOTE_ACTION_SHOULD_START = "should_start_for_result";
- public static final String REMOTE_ACTION_TOKEN = "action_token";
-
-
public enum ViewType {
-
- /**
- * Consists of N number of icons. (N: launcher column count)
- */
TOP_HIT(0),
-
- /**
- * Consists of 1 icon and two subsidiary icons.
- */
HERO(1),
-
- /**
- * Main/sub/breadcrumb texts are rendered.
- */
DETAIL(2),
-
- /**
- * Consists of an icon, three detail strings.
- */
ROW(3),
-
- /**
- * Consists of an icon, three detail strings and a button.
- */
ROW_WITH_BUTTON(4),
-
- /**
- * Consists of a single slice view
- */
SLICE(5),
-
- /**
- * Similar to hero section.
- */
SHORTCUT(6),
-
- /**
- * Person icon and handling app icons are rendered.
- */
- PEOPLE(7),
-
- /**
- * N number of 1x1 ratio thumbnail is rendered.
- * (current N = 3)
- */
- THUMBNAIL(8),
-
- /**
- * Fallback search icon and relevant text is rendered.
- */
- SUGGEST(9);
+ PEOPLE(7);
private final int mId;
-
ViewType(int id) {
mId = id;
}
@@ -105,15 +52,9 @@ public class SearchTarget implements Comparable {
APP(3, "", ViewType.TOP_HIT),
APP_HERO(4, "", ViewType.HERO),
SHORTCUT(5, "Shortcuts", ViewType.SHORTCUT),
- PEOPLE(6, "People", ViewType.PEOPLE),
- SCREENSHOT(7, "Screenshots", ViewType.THUMBNAIL),
- ACTION(8, "Actions", ViewType.SHORTCUT),
- SUGGEST(9, "Fallback Search", ViewType.SUGGEST),
- CHROME_TAB(10, "Chrome Tab", ViewType.SHORTCUT);
+ PEOPLE(6, "People", ViewType.PEOPLE);
private final int mId;
-
- /** Used to render section title. */
private final String mTitle;
private final ViewType mViewType;
@@ -140,21 +81,19 @@ public class SearchTarget implements Comparable {
public List shortcuts;
public Bundle bundle;
public float score;
- public String mSessionId;
- public RemoteAction mRemoteAction;
/**
* Constructor to create the search target. Bundle is currently temporary to hold
* search target primitives that cannot be expressed as java primitive objects
* or AOSP native objects.
+ *
*/
public SearchTarget(ItemType itemType, List shortcuts,
- Bundle bundle, float score, String sessionId) {
+ Bundle bundle, float score) {
this.type = itemType;
this.shortcuts = shortcuts;
this.bundle = bundle;
this.score = score;
- this.mSessionId = sessionId;
}
@Override
diff --git a/src_plugins/com/android/systemui/plugins/shared/SearchTargetEvent.java b/src_plugins/com/android/systemui/plugins/shared/SearchTargetEvent.java
index 5016abc1e9..ac4bc333c6 100644
--- a/src_plugins/com/android/systemui/plugins/shared/SearchTargetEvent.java
+++ b/src_plugins/com/android/systemui/plugins/shared/SearchTargetEvent.java
@@ -15,7 +15,6 @@
*/
package com.android.systemui.plugins.shared;
-import android.app.RemoteAction;
import android.content.pm.ShortcutInfo;
import android.os.Bundle;
@@ -30,17 +29,12 @@ public class SearchTargetEvent {
public SearchTarget.ItemType type;
public ShortcutInfo shortcut;
- public RemoteAction remoteAction;
public int eventType;
public Bundle bundle;
- public int index;
- public String sessionIdentifier;
+ public float score;
- public SearchTargetEvent(SearchTarget.ItemType itemType, int eventType, int index,
- String sessionId) {
+ public SearchTargetEvent(SearchTarget.ItemType itemType, int eventType) {
this.type = itemType;
this.eventType = eventType;
- this.index = index;
- this.sessionIdentifier = sessionId;
}
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
index a4e53a1cc0..ec3f93ff1b 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -16,13 +16,13 @@
package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
-import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_ALLAPPS;
import android.content.Context;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
/**
* Definition for AllApps state
@@ -41,7 +41,7 @@ public class AllAppsState extends LauncherState {
};
public AllAppsState(int id) {
- super(id, LAUNCHER_STATE_ALLAPPS, STATE_FLAGS);
+ super(id, ContainerType.ALLAPPS, STATE_FLAGS);
}
@Override
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
index da5a94f6fd..d102bccaad 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -15,11 +15,10 @@
*/
package com.android.launcher3.uioverrides.states;
-import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
-
import android.content.Context;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
/**
* Definition for overview state
@@ -27,7 +26,7 @@ import com.android.launcher3.LauncherState;
public class OverviewState extends LauncherState {
public OverviewState(int id) {
- super(id, LAUNCHER_STATE_OVERVIEW, FLAG_DISABLE_RESTORE);
+ super(id, ContainerType.WORKSPACE, FLAG_DISABLE_RESTORE);
}
@Override
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index e118481570..5e42d9b988 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -279,8 +279,6 @@ public abstract class AbstractLauncherUiTest {
if (userManager != null) {
for (UserHandle userHandle : userManager.getUserProfiles()) {
if (!userHandle.isSystem()) {
- Log.d(TestProtocol.WORK_PROFILE_REMOVED,
- "removing user " + userHandle.getIdentifier());
mDevice.executeShellCommand("pm remove-user " + userHandle.getIdentifier());
}
}
diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src/com/android/launcher3/ui/WorkTabTest.java
index 8d594de926..f5f93c429f 100644
--- a/tests/src/com/android/launcher3/ui/WorkTabTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkTabTest.java
@@ -55,9 +55,7 @@ public class WorkTabTest extends AbstractLauncherUiTest {
private static final int WORK_PAGE = AllAppsContainerView.AdapterHolder.WORK;
@Before
- @Override
- public void setUp() throws Exception {
- super.setUp();
+ public void createWorkProfile() throws Exception {
String output =
mDevice.executeShellCommand(
"pm create-user --profileOf 0 --managed TestProfile");
@@ -138,8 +136,7 @@ public class WorkTabTest extends AbstractLauncherUiTest {
});
executeOnLauncher(launcher -> Log.d(TestProtocol.WORK_PROFILE_REMOVED,
- "work profile status (" + mProfileUserId + ") :"
- + launcher.getAppsView().isWorkTabVisible()));
+ "Work profile status: " + launcher.getAppsView().isPersonalTabVisible()));
// verify work edu is seen next
waitForLauncherCondition("Launcher did not show the next edu screen", l ->