Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f40c5795 authored by Thiru Ramasamy's avatar Thiru Ramasamy Committed by Android (Google) Code Review
Browse files

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

parents 88ea05ad c1c2bfa7
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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));
        }
    }
}
+20 −2
Original line number Diff line number Diff line
@@ -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)) {
Loading