Merge "Initial draft of smart folder logging to clearcut pipeline." into ub-launcher3-master

This commit is contained in:
Thiru Ramasamy
2020-02-14 00:49:14 +00:00
committed by Android (Google) Code Review
6 changed files with 219 additions and 31 deletions
+2 -1
View File
@@ -32,7 +32,7 @@ android_library {
}
java_library_static {
name: "launcher-log-protos-lite",
name: "launcher_log_protos_lite",
srcs: [
"protos/*.proto",
"proto_overrides/*.proto",
@@ -45,4 +45,5 @@ java_library_static {
"proto_overrides",
],
},
static_libs: ["libprotobuf-java-lite"],
}
+11 -3
View File
@@ -48,7 +48,9 @@ LOCAL_STATIC_ANDROID_LIBRARIES := \
androidx.preference_preference \
iconloader_base
LOCAL_STATIC_JAVA_LIBRARIES := LauncherPluginLib
LOCAL_STATIC_JAVA_LIBRARIES := \
LauncherPluginLib \
launcher_log_protos_lite
LOCAL_SRC_FILES := \
$(call all-proto-files-under, protos) \
@@ -144,7 +146,10 @@ LOCAL_USE_AAPT2 := true
LOCAL_AAPT2_ONLY := true
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLib launcherprotosnano
LOCAL_STATIC_JAVA_LIBRARIES := \
SystemUISharedLib \
launcherprotosnano \
launcher_log_protos_lite
ifneq (,$(wildcard frameworks/base))
LOCAL_PRIVATE_PLATFORM_APIS := true
else
@@ -213,7 +218,10 @@ include $(CLEAR_VARS)
LOCAL_USE_AAPT2 := true
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLib launcherprotosnano
LOCAL_STATIC_JAVA_LIBRARIES := \
SystemUISharedLib \
launcherprotosnano \
launcher_log_protos_lite
ifneq (,$(wildcard frameworks/base))
LOCAL_PRIVATE_PLATFORM_APIS := true
else
+31 -1
View File
@@ -58,6 +58,35 @@ message Target {
optional TipType tip_type = 17;
optional int32 search_query_length = 18;
optional bool is_work_app = 19;
optional FromFolderLabelState from_folder_label_state = 20;
optional ToFolderLabelState to_folder_label_state = 21;
// Note: proto does not support duplicate enum values, even if they belong to different enum type.
// Hence "FROM" and "TO" prefix added.
enum FromFolderLabelState{
FROM_FOLDER_LABEL_STATE_UNSPECIFIED = 0;
FROM_EMPTY = 1;
FROM_CUSTOM = 2;
FROM_SUGGESTED = 3;
}
enum ToFolderLabelState{
TO_FOLDER_LABEL_STATE_UNSPECIFIED = 0;
TO_SUGGESTION0_WITH_VALID_PRIMARY = 1;
TO_SUGGESTION1_WITH_VALID_PRIMARY = 2;
TO_SUGGESTION1_WITH_EMPTY_PRIMARY = 3;
TO_SUGGESTION2_WITH_VALID_PRIMARY = 4;
TO_SUGGESTION2_WITH_EMPTY_PRIMARY = 5;
TO_SUGGESTION3_WITH_VALID_PRIMARY = 6;
TO_SUGGESTION3_WITH_EMPTY_PRIMARY = 7;
TO_EMPTY_WITH_VALID_SUGGESTIONS = 8;
TO_EMPTY_WITH_EMPTY_SUGGESTIONS = 9;
TO_EMPTY_WITH_SUGGESTIONS_DISABLED = 10;
TO_CUSTOM_WITH_VALID_SUGGESTIONS = 11;
TO_CUSTOM_WITH_EMPTY_SUGGESTIONS = 12;
TO_CUSTOM_WITH_SUGGESTIONS_DISABLED = 13;
UNCHANGED = 14;
}
}
// Used to define what type of item a Target would represent.
@@ -141,7 +170,8 @@ message Action {
AUTOMATED = 1;
COMMAND = 2;
TIP = 3;
// SOFT_KEYBOARD, HARD_KEYBOARD, ASSIST
SOFT_KEYBOARD = 4;
// HARD_KEYBOARD, ASSIST
}
enum Touch {
+154 -23
View File
@@ -16,9 +16,23 @@
package com.android.launcher3.folder;
import static android.text.TextUtils.isEmpty;
import static androidx.core.util.Preconditions.checkNotNull;
import static com.android.launcher3.FolderInfo.FLAG_MANUAL_FOLDER_NAME;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
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 static java.util.Arrays.asList;
import static java.util.Arrays.stream;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -75,22 +89,24 @@ import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.logging.LoggerUtils;
import com.android.launcher3.pageindicators.PageIndicatorDots;
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.userevent.nano.LauncherLogProto.ItemType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.userevent.LauncherLogProto.Action;
import com.android.launcher3.userevent.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.LauncherLogProto.ItemType;
import com.android.launcher3.userevent.LauncherLogProto.LauncherEvent;
import com.android.launcher3.userevent.LauncherLogProto.Target;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.views.ClipPathView;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
* Represents a set of icons chosen by the user or generated by the system.
@@ -188,6 +204,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
@Thunk int mScrollHintDir = SCROLL_NONE;
@Thunk int mCurrentScrollDir = SCROLL_NONE;
private String mPreviousLabel;
private boolean mIsPreviousLabelSuggested;
/**
* Used to inflate the Workspace from XML.
*
@@ -302,7 +321,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
public void startEditingFolderName() {
post(() -> {
if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
if (TextUtils.isEmpty(mFolderName.getText())) {
if (isEmpty(mFolderName.getText())) {
FolderNameInfo[] nameInfos =
(FolderNameInfo[]) mInfo.suggestedFolderNames.getParcelableArrayExtra(
FolderInfo.EXTRA_FOLDER_SUGGESTIONS);
@@ -326,7 +345,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
}
mInfo.title = newTitle;
mInfo.setOption(FolderInfo.FLAG_MANUAL_FOLDER_NAME, mFolderName.isEnteredCompose(),
mInfo.setOption(FLAG_MANUAL_FOLDER_NAME, mFolderName.isEnteredCompose(),
mLauncher.getModelWriter());
mFolderIcon.onTitleChanged(newTitle);
mLauncher.getModelWriter().updateItemInDatabase(mInfo);
@@ -337,7 +356,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
// suggested, apply different hint.
mFolderName.setHint("");
} else {
if (TextUtils.isEmpty(mInfo.title)) {
if (isEmpty(mInfo.title)) {
mFolderName.setHint(R.string.folder_hint_text);
mFolderName.setText("");
} else {
@@ -425,8 +444,10 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
mItemsInvalidated = true;
mInfo.addListener(this);
if (!TextUtils.isEmpty(mInfo.title)) {
if (!isEmpty(mInfo.title)) {
mFolderName.setText(mInfo.title);
mPreviousLabel = mInfo.title.toString();
mIsPreviousLabelSuggested = !mInfo.hasOption(FLAG_MANUAL_FOLDER_NAME);
mFolderName.setHint(null);
} else {
mFolderName.setText("");
@@ -452,8 +473,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
mInfo.suggestedFolderNames = new Intent().putExtra(FolderInfo.EXTRA_FOLDER_SUGGESTIONS,
nameInfos);
if (TextUtils.isEmpty(mFolderName.getText().toString())
&& !mInfo.hasOption(FolderInfo.FLAG_MANUAL_FOLDER_NAME)) {
if (isEmpty(mFolderName.getText().toString())
&& !mInfo.hasOption(FLAG_MANUAL_FOLDER_NAME)) {
showLabelSuggestion(nameInfos);
}
}
@@ -469,14 +490,14 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
}
// Open the Folder and Keyboard when the first or second suggestion is valid non-empty
// string.
boolean shouldOpen = nameInfos.length > 0 && nameInfos[0] != null && !TextUtils.isEmpty(
boolean shouldOpen = nameInfos.length > 0 && nameInfos[0] != null && !isEmpty(
nameInfos[0].getLabel())
|| nameInfos.length > 1 && nameInfos[1] != null && !TextUtils.isEmpty(
|| nameInfos.length > 1 && nameInfos[1] != null && !isEmpty(
nameInfos[1].getLabel());
CharSequence firstLabel = nameInfos[0].getLabel();
if (shouldOpen) {
if (!TextUtils.isEmpty(firstLabel)) {
if (!isEmpty(firstLabel)) {
mFolderName.setHint("");
mFolderName.setText(firstLabel);
mInfo.title = firstLabel;
@@ -484,7 +505,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
animateOpen(mInfo.contents, 0, true);
mFolderName.showKeyboard();
mFolderName.displayCompletions(
Arrays.asList(nameInfos).subList(1, nameInfos.length).stream()
asList(nameInfos).subList(1, nameInfos.length).stream()
.filter(Objects::nonNull)
.map(s -> s.getLabel().toString())
.collect(Collectors.toList()));
@@ -636,9 +657,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
if (!skipUserEventLog) {
mLauncher.getUserEventDispatcher().logActionOnItem(
Touch.TAP,
Direction.NONE,
ItemType.FOLDER_ICON, mInfo.cellX, mInfo.cellY);
LauncherLogProto.Action.Touch.TAP,
LauncherLogProto.Action.Direction.NONE,
LauncherLogProto.ItemType.FOLDER_ICON, mInfo.cellX, mInfo.cellY);
}
@@ -1420,6 +1441,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
if (hasFocus) {
startEditingFolderName();
} else {
logEditFolderLabel();
mFolderName.dispatchBackKey();
}
}
@@ -1433,11 +1455,12 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
}
@Override
public void fillInLogContainerData(View v, ItemInfo info, Target target, Target targetParent) {
public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target,
LauncherLogProto.Target targetParent) {
target.gridX = info.cellX;
target.gridY = info.cellY;
target.pageIndex = mContent.getCurrentPage();
targetParent.containerType = ContainerType.FOLDER;
targetParent.containerType = LauncherLogProto.ContainerType.FOLDER;
}
private class OnScrollHintListener implements OnAlarmListener {
@@ -1535,7 +1558,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
@Override
public int getLogContainerType() {
return ContainerType.FOLDER;
return LauncherLogProto.ContainerType.FOLDER;
}
/**
@@ -1570,7 +1593,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
}
} else {
mLauncher.getUserEventDispatcher().logActionTapOutside(
LoggerUtils.newContainerTarget(ContainerType.FOLDER));
LoggerUtils.newContainerTarget(LauncherLogProto.ContainerType.FOLDER));
close(true);
return true;
}
@@ -1600,4 +1623,112 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
super.draw(canvas);
}
}
private void logEditFolderLabel() {
LauncherEvent launcherEvent = LauncherEvent.newBuilder()
.setAction(Action.newBuilder().setType(Action.Type.SOFT_KEYBOARD))
.addSrcTarget(newEditTextTargetBuilder()
.setFromFolderLabelState(getFromFolderLabelState())
.setToFolderLabelState(getToFolderLabelState()))
.addSrcTarget(newFolderTargetBuilder())
.addSrcTarget(newParentContainerTarget())
.build();
mLauncher.getUserEventDispatcher().logLauncherEvent(launcherEvent);
mPreviousLabel = mFolderName.getText().toString();
mIsPreviousLabelSuggested = !mInfo.hasOption(FLAG_MANUAL_FOLDER_NAME);
}
private Target.FromFolderLabelState getFromFolderLabelState() {
return mPreviousLabel == null
? FROM_FOLDER_LABEL_STATE_UNSPECIFIED
: mPreviousLabel.isEmpty()
? FROM_EMPTY
: mIsPreviousLabelSuggested
? FROM_SUGGESTED
: FROM_CUSTOM;
}
private Target.ToFolderLabelState getToFolderLabelState() {
String newLabel =
checkNotNull(mFolderName.getText().toString(),
"Expected valid folder label, but found null");
Optional<String[]> suggestedLabels = Optional.ofNullable(
(FolderNameInfo[]) mInfo.suggestedFolderNames
.getParcelableArrayExtra(FolderInfo.EXTRA_FOLDER_SUGGESTIONS))
.map(folderNameInfoArray ->
stream(folderNameInfoArray)
.map(FolderNameInfo::getLabel)
.map(CharSequence::toString)
.toArray(String[]::new));
int accepted_suggestion_index = suggestedLabels
.map(folderNameInfoArray ->
IntStream.range(0, folderNameInfoArray.length)
.filter(index -> newLabel.equalsIgnoreCase(
folderNameInfoArray[index]))
.findFirst()
.orElse(-1)
).orElse(-1);
boolean hasValidPrimary = suggestedLabels
.map(labels -> labels.length > 0 && !isEmpty(labels[0]))
.orElse(false);
String primarySuffix = hasValidPrimary
? "_WITH_VALID_PRIMARY"
: "_WITH_EMPTY_PRIMARY";
boolean isEmptySuggestions = suggestedLabels
.map(labels -> stream(labels).allMatch(TextUtils::isEmpty))
.orElse(true);
boolean isSuggestionsEnabled = FeatureFlags.FOLDER_NAME_SUGGEST.get();
String suggestionsSuffix = isSuggestionsEnabled
? isEmptySuggestions
? "_WITH_EMPTY_SUGGESTIONS"
: "_WITH_VALID_SUGGESTIONS"
: "_WITH_SUGGESTIONS_DISABLED";
return newLabel.equals(mPreviousLabel)
? Target.ToFolderLabelState.UNCHANGED
: newLabel.isEmpty()
? Target.ToFolderLabelState.valueOf("TO_EMPTY" + suggestionsSuffix)
: accepted_suggestion_index >= 0
? Target.ToFolderLabelState.valueOf("TO_SUGGESTION"
+ accepted_suggestion_index
+ primarySuffix)
: Target.ToFolderLabelState.valueOf("TO_CUSTOM" + suggestionsSuffix);
}
private Target.Builder newEditTextTargetBuilder() {
return Target.newBuilder().setType(Target.Type.ITEM).setItemType(ItemType.EDITTEXT);
}
private Target.Builder newFolderTargetBuilder() {
return Target.newBuilder()
.setType(Target.Type.CONTAINER)
.setContainerType(ContainerType.FOLDER)
.setPageIndex(mInfo.screenId)
.setGridX(mInfo.cellX)
.setGridY(mInfo.cellY)
.setCardinality(mInfo.contents.size());
}
private Target.Builder newParentContainerTarget() {
Target.Builder builder = Target.newBuilder().setType(Target.Type.CONTAINER);
switch (mInfo.container) {
case CONTAINER_HOTSEAT:
return builder.setContainerType(ContainerType.HOTSEAT);
case CONTAINER_DESKTOP:
return builder.setContainerType(ContainerType.WORKSPACE);
default:
throw new AssertionError(String
.format("Expected container to be either %s or %s but found %s.",
CONTAINER_HOTSEAT,
CONTAINER_DESKTOP,
mInfo.container));
}
}
}
@@ -69,8 +69,7 @@ import java.util.UUID;
public class UserEventDispatcher implements ResourceBasedOverride {
private static final String TAG = "UserEvent";
private static final boolean IS_VERBOSE =
FeatureFlags.IS_DOGFOOD_BUILD && Utilities.isPropertyEnabled(LogConfig.USEREVENT);
private static final boolean IS_VERBOSE = Utilities.isPropertyEnabled(LogConfig.USEREVENT);
private static final String UUID_STORAGE = "uuid";
public static UserEventDispatcher newInstance(Context context,
@@ -372,6 +371,25 @@ public class UserEventDispatcher implements ResourceBasedOverride {
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();
if (!IS_VERBOSE) {
return;
}
Log.d(TAG, launcherEvent.toString());
}
public void logDeepShortcutsOpen(View icon) {
LogContainerProvider provider = StatsLogUtils.getLaunchProviderRecursive(icon);
if (icon == null || !(icon.getTag() instanceof ItemInfo || provider == null)) {
+1 -1
View File
@@ -51,7 +51,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
androidx.test.rules \
androidx.test.uiautomator_uiautomator \
mockito-target-minus-junit4 \
launcher-log-protos-lite
launcher_log_protos_lite
ifneq (,$(wildcard frameworks/base))
LOCAL_PRIVATE_PLATFORM_APIS := true