Merge "Converting StatsLogManager to kotlin" into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
baacf9f4df
@@ -1,950 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.quickstep.logging;
|
||||
|
||||
import static android.view.Surface.ROTATION_180;
|
||||
import static android.view.Surface.ROTATION_270;
|
||||
import static android.view.Surface.ROTATION_90;
|
||||
|
||||
import static androidx.core.util.Preconditions.checkNotNull;
|
||||
import static androidx.core.util.Preconditions.checkState;
|
||||
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_NON_ACTIONABLE;
|
||||
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.ALL_APPS_CONTAINER;
|
||||
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.EXTENDED_CONTAINERS;
|
||||
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.FOLDER;
|
||||
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.SEARCH_RESULT_CONTAINER;
|
||||
import static com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers.ContainerCase.DEVICE_SEARCH_RESULT_CONTAINER;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORKSPACE_SNAPSHOT;
|
||||
import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DISPLAY_ROTATION__ROTATION_0;
|
||||
import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DISPLAY_ROTATION__ROTATION_180;
|
||||
import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DISPLAY_ROTATION__ROTATION_270;
|
||||
import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DISPLAY_ROTATION__ROTATION_90;
|
||||
import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__ALLAPPS;
|
||||
import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__BACKGROUND;
|
||||
import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__HOME;
|
||||
import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__OVERVIEW;
|
||||
import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__RECENTS_ORIENTATION_HANDLER__LANDSCAPE;
|
||||
import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__RECENTS_ORIENTATION_HANDLER__PORTRAIT;
|
||||
import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__RECENTS_ORIENTATION_HANDLER__SEASCAPE;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.StatsEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.slice.SliceItem;
|
||||
|
||||
import com.android.internal.jank.Cuj;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.logger.LauncherAtom;
|
||||
import com.android.launcher3.logger.LauncherAtom.Attribute;
|
||||
import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
|
||||
import com.android.launcher3.logger.LauncherAtom.FolderContainer.ParentContainerCase;
|
||||
import com.android.launcher3.logger.LauncherAtom.FolderIcon;
|
||||
import com.android.launcher3.logger.LauncherAtom.FromState;
|
||||
import com.android.launcher3.logger.LauncherAtom.LauncherAttributes;
|
||||
import com.android.launcher3.logger.LauncherAtom.ToState;
|
||||
import com.android.launcher3.logger.LauncherAtomExtensions.DeviceSearchResultContainer;
|
||||
import com.android.launcher3.logger.LauncherAtomExtensions.DeviceSearchResultContainer.SearchAttributes;
|
||||
import com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers;
|
||||
import com.android.launcher3.logging.InstanceId;
|
||||
import com.android.launcher3.logging.StatsLogManager;
|
||||
import com.android.launcher3.model.data.CollectionInfo;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.util.DisplayController;
|
||||
import com.android.launcher3.util.Executors;
|
||||
import com.android.launcher3.util.LogConfig;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
|
||||
import com.android.systemui.shared.system.SysUiStatsLog;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* This class calls StatsLog compile time generated methods.
|
||||
*
|
||||
* To see if the logs are properly sent to statsd, execute following command.
|
||||
* <ul>
|
||||
* $ wwdebug (to turn on the logcat printout)
|
||||
* $ wwlogcat (see logcat with grep filter on)
|
||||
* $ statsd_testdrive (see how ww is writing the proto to statsd buffer)
|
||||
* </ul>
|
||||
*/
|
||||
public class StatsLogCompatManager extends StatsLogManager {
|
||||
|
||||
private static final String TAG = "StatsLog";
|
||||
private static final String LATENCY_TAG = "StatsLatencyLog";
|
||||
private static final String IMPRESSION_TAG = "StatsImpressionLog";
|
||||
private static final boolean IS_VERBOSE = Utilities.isPropertyEnabled(LogConfig.STATSLOG);
|
||||
private static final boolean DEBUG = !Utilities.isRunningInTestHarness();
|
||||
private static final InstanceId DEFAULT_INSTANCE_ID = InstanceId.fakeInstanceId(0);
|
||||
// LauncherAtom.ItemInfo.getDefaultInstance() should be used but until launcher proto migrates
|
||||
// from nano to lite, bake constant to prevent robo test failure.
|
||||
private static final int DEFAULT_PAGE_INDEX = -2;
|
||||
private static final int FOLDER_HIERARCHY_OFFSET = 100;
|
||||
private static final int SEARCH_RESULT_HIERARCHY_OFFSET = 200;
|
||||
private static final int EXTENDED_CONTAINERS_HIERARCHY_OFFSET = 300;
|
||||
private static final int ALL_APPS_HIERARCHY_OFFSET = 400;
|
||||
|
||||
/**
|
||||
* Flags for converting SearchAttribute to integer value.
|
||||
*/
|
||||
private static final int SEARCH_ATTRIBUTES_CORRECTED_QUERY = 1 << 0;
|
||||
private static final int SEARCH_ATTRIBUTES_DIRECT_MATCH = 1 << 1;
|
||||
private static final int SEARCH_ATTRIBUTES_ENTRY_STATE_ALL_APPS = 1 << 2;
|
||||
private static final int SEARCH_ATTRIBUTES_ENTRY_STATE_QSB = 1 << 3;
|
||||
private static final int SEARCH_ATTRIBUTES_ENTRY_STATE_OVERVIEW = 1 << 4;
|
||||
private static final int SEARCH_ATTRIBUTES_ENTRY_STATE_TASKBAR = 1 << 5;
|
||||
|
||||
public static final CopyOnWriteArrayList<StatsLogConsumer> LOGS_CONSUMER =
|
||||
new CopyOnWriteArrayList<>();
|
||||
|
||||
private StatsLogCompatManager(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is purely used to support dagger bindings to be overridden in launcher variants.
|
||||
* Very similar to {@link dagger.assisted.AssistedFactory}. But
|
||||
* {@link dagger.assisted.AssistedFactory} cannot be overridden and this makes dagger binding
|
||||
* difficult.
|
||||
*/
|
||||
public static class StatsLogCompatManagerFactory extends StatsLogManagerFactory {
|
||||
@Inject
|
||||
StatsLogCompatManagerFactory() {
|
||||
super();
|
||||
}
|
||||
|
||||
public StatsLogManager create(Context context) {
|
||||
return new StatsLogCompatManager(context);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StatsLogger createLogger() {
|
||||
return new StatsCompatLogger(mContext, mActivityContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StatsLatencyLogger createLatencyLogger() {
|
||||
return new StatsCompatLatencyLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StatsImpressionLogger createImpressionLogger() {
|
||||
return new StatsCompatImpressionLogger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously writes an itemInfo to stats log
|
||||
*/
|
||||
@WorkerThread
|
||||
public static void writeSnapshot(LauncherAtom.ItemInfo info, InstanceId instanceId) {
|
||||
if (IS_VERBOSE) {
|
||||
Log.d(TAG, String.format("\nwriteSnapshot(%d):\n%s", instanceId.getId(), info));
|
||||
}
|
||||
if (Utilities.isRunningInTestHarness()) {
|
||||
return;
|
||||
}
|
||||
SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_SNAPSHOT,
|
||||
LAUNCHER_WORKSPACE_SNAPSHOT.getId() /* event_id */,
|
||||
info.getItemCase().getNumber() /* target_id */,
|
||||
instanceId.getId() /* instance_id */,
|
||||
0 /* uid */,
|
||||
getPackageName(info) /* package_name */,
|
||||
getComponentName(info) /* component_name */,
|
||||
getGridX(info, false) /* grid_x */,
|
||||
getGridY(info, false) /* grid_y */,
|
||||
getPageId(info) /* page_id */,
|
||||
getGridX(info, true) /* grid_x_parent */,
|
||||
getGridY(info, true) /* grid_y_parent */,
|
||||
getParentPageId(info) /* page_id_parent */,
|
||||
getHierarchy(info) /* hierarchy */,
|
||||
info.getIsWork() /* is_work_profile */,
|
||||
0 /* origin */,
|
||||
getCardinality(info) /* cardinality */,
|
||||
info.getWidget().getSpanX(),
|
||||
info.getWidget().getSpanY(),
|
||||
getFeatures(info),
|
||||
getAttributes(info) /* attributes */
|
||||
);
|
||||
}
|
||||
|
||||
private static byte[] getAttributes(LauncherAtom.ItemInfo itemInfo) {
|
||||
LauncherAttributes.Builder responseBuilder = LauncherAttributes.newBuilder();
|
||||
itemInfo.getItemAttributesList().stream().map(Attribute::getNumber).forEach(
|
||||
responseBuilder::addItemAttributes);
|
||||
return responseBuilder.build().toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds {@link StatsEvent} from {@link LauncherAtom.ItemInfo}. Used for pulled atom callback
|
||||
* implementation.
|
||||
*/
|
||||
public static StatsEvent buildStatsEvent(LauncherAtom.ItemInfo info,
|
||||
@Nullable InstanceId instanceId) {
|
||||
return SysUiStatsLog.buildStatsEvent(
|
||||
SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT, // atom ID,
|
||||
LAUNCHER_WORKSPACE_SNAPSHOT.getId(), // event_id = 1;
|
||||
info.getItemCase().getNumber(), // item_id = 2;
|
||||
instanceId == null ? 0 : instanceId.getId(), //instance_id = 3;
|
||||
0, //uid = 4 [(is_uid) = true];
|
||||
getPackageName(info), // package_name = 5;
|
||||
getComponentName(info), // component_name = 6;
|
||||
getGridX(info, false), //grid_x = 7 [default = -1];
|
||||
getGridY(info, false), //grid_y = 8 [default = -1];
|
||||
getPageId(info), // page_id = 9 [default = -2];
|
||||
getGridX(info, true), //grid_x_parent = 10 [default = -1];
|
||||
getGridY(info, true), //grid_y_parent = 11 [default = -1];
|
||||
getParentPageId(info), //page_id_parent = 12 [default = -2];
|
||||
getHierarchy(info), // container_id = 13;
|
||||
info.getIsWork(), // is_work_profile = 14;
|
||||
0, // attribute_id = 15;
|
||||
getCardinality(info), // cardinality = 16;
|
||||
info.getWidget().getSpanX(), // span_x = 17 [default = 1];
|
||||
info.getWidget().getSpanY(), // span_y = 18 [default = 1];
|
||||
getAttributes(info) /* attributes = 19 [(log_mode) = MODE_BYTES] */,
|
||||
info.getIsKidsMode() /* is_kids_mode = 20 */
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helps to construct and write statsd compatible log message.
|
||||
*/
|
||||
private static class StatsCompatLogger implements StatsLogger {
|
||||
|
||||
private static final ItemInfo DEFAULT_ITEM_INFO = new ItemInfo();
|
||||
static {
|
||||
DEFAULT_ITEM_INFO.itemType = ITEM_TYPE_NON_ACTIONABLE;
|
||||
}
|
||||
private final Context mContext;
|
||||
private final Optional<ActivityContext> mActivityContext;
|
||||
private ItemInfo mItemInfo = DEFAULT_ITEM_INFO;
|
||||
private InstanceId mInstanceId = DEFAULT_INSTANCE_ID;
|
||||
private OptionalInt mRank = OptionalInt.empty();
|
||||
private Optional<ContainerInfo> mContainerInfo = Optional.empty();
|
||||
private int mSrcState = LAUNCHER_STATE_UNSPECIFIED;
|
||||
private int mDstState = LAUNCHER_STATE_UNSPECIFIED;
|
||||
private Optional<FromState> mFromState = Optional.empty();
|
||||
private Optional<ToState> mToState = Optional.empty();
|
||||
private Optional<String> mEditText = Optional.empty();
|
||||
private SliceItem mSliceItem;
|
||||
private LauncherAtom.Slice mSlice;
|
||||
private Optional<Integer> mCardinality = Optional.empty();
|
||||
private int mInputType = SysUiStatsLog.LAUNCHER_UICHANGED__INPUT_TYPE__UNKNOWN;
|
||||
private Optional<Integer> mFeatures = Optional.empty();
|
||||
private Optional<String> mPackageName = Optional.empty();
|
||||
/**
|
||||
* Indicates the current rotation of the display. Uses {@link android.view.Surface values.}
|
||||
*/
|
||||
private final int mDisplayRotation;
|
||||
|
||||
StatsCompatLogger(Context context, ActivityContext activityContext) {
|
||||
mContext = context;
|
||||
mActivityContext = Optional.ofNullable(activityContext);
|
||||
mDisplayRotation = DisplayController.INSTANCE.get(mContext).getInfo().rotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLogger withItemInfo(ItemInfo itemInfo) {
|
||||
if (mContainerInfo.isPresent()) {
|
||||
throw new IllegalArgumentException(
|
||||
"ItemInfo and ContainerInfo are mutual exclusive; cannot log both.");
|
||||
}
|
||||
this.mItemInfo = itemInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLogger withInstanceId(InstanceId instanceId) {
|
||||
this.mInstanceId = instanceId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLogger withRank(int rank) {
|
||||
this.mRank = OptionalInt.of(rank);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLogger withSrcState(int srcState) {
|
||||
this.mSrcState = srcState;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLogger withDstState(int dstState) {
|
||||
this.mDstState = dstState;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLogger withContainerInfo(ContainerInfo containerInfo) {
|
||||
checkState(mItemInfo == DEFAULT_ITEM_INFO,
|
||||
"ItemInfo and ContainerInfo are mutual exclusive; cannot log both.");
|
||||
this.mContainerInfo = Optional.of(containerInfo);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLogger withFromState(FromState fromState) {
|
||||
this.mFromState = Optional.of(fromState);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLogger withToState(ToState toState) {
|
||||
this.mToState = Optional.of(toState);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLogger withEditText(String editText) {
|
||||
this.mEditText = Optional.of(editText);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLogger withSliceItem(@NonNull SliceItem sliceItem) {
|
||||
checkState(mItemInfo == DEFAULT_ITEM_INFO && mSlice == null,
|
||||
"ItemInfo, Slice and SliceItem are mutual exclusive; cannot set more than one"
|
||||
+ " of them.");
|
||||
this.mSliceItem = checkNotNull(sliceItem, "expected valid sliceItem but received null");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLogger withSlice(LauncherAtom.Slice slice) {
|
||||
checkState(mItemInfo == DEFAULT_ITEM_INFO && mSliceItem == null,
|
||||
"ItemInfo, Slice and SliceItem are mutual exclusive; cannot set more than one"
|
||||
+ " of them.");
|
||||
checkNotNull(slice, "expected valid slice but received null");
|
||||
checkNotNull(slice.getUri(), "expected valid slice uri but received null");
|
||||
this.mSlice = slice;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLogger withCardinality(int cardinality) {
|
||||
this.mCardinality = Optional.of(cardinality);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLogger withInputType(int inputType) {
|
||||
this.mInputType = inputType;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLogger withFeatures(int feature) {
|
||||
this.mFeatures = Optional.of(feature);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLogger withPackageName(@Nullable String packageName) {
|
||||
mPackageName = Optional.ofNullable(packageName);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(EventEnum event) {
|
||||
if (DEBUG) {
|
||||
String name = (event instanceof Enum) ? ((Enum) event).name() :
|
||||
event.getId() + "";
|
||||
Log.d(TAG, name);
|
||||
}
|
||||
|
||||
if (mSlice == null && mSliceItem != null) {
|
||||
mSlice = LauncherAtom.Slice.newBuilder().setUri(
|
||||
mSliceItem.getSlice().getUri().toString()).build();
|
||||
}
|
||||
|
||||
if (mSlice != null) {
|
||||
Executors.MODEL_EXECUTOR.execute(
|
||||
() -> {
|
||||
LauncherAtom.ItemInfo.Builder itemInfoBuilder =
|
||||
LauncherAtom.ItemInfo.newBuilder().setSlice(mSlice);
|
||||
mContainerInfo.ifPresent(itemInfoBuilder::setContainerInfo);
|
||||
write(event, applyOverwrites(itemInfoBuilder.build()));
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (mItemInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Item is inside a collection, fetch collection info in a BG thread
|
||||
// and then write to StatsLog.
|
||||
if (mItemInfo.container < 0) {
|
||||
LauncherAppState.INSTANCE.get(mContext).getModel().enqueueModelUpdateTask(
|
||||
(taskController, dataModel, apps) -> write(event, applyOverwrites(
|
||||
mItemInfo.buildProto(
|
||||
(CollectionInfo) dataModel.itemsIdMap
|
||||
.get(mItemInfo.container),
|
||||
mContext))));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToInteractionJankMonitor(EventEnum event, View view) {
|
||||
if (!(event instanceof LauncherEvent)) {
|
||||
return;
|
||||
}
|
||||
switch ((LauncherEvent) event) {
|
||||
case LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN:
|
||||
InteractionJankMonitorWrapper.begin(
|
||||
view,
|
||||
Cuj.CUJ_LAUNCHER_ALL_APPS_SCROLL);
|
||||
break;
|
||||
case LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END:
|
||||
InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_ALL_APPS_SCROLL);
|
||||
break;
|
||||
case LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_BEGIN:
|
||||
InteractionJankMonitorWrapper.begin(view, Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_LOCK);
|
||||
break;
|
||||
case LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_END:
|
||||
InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_LOCK);
|
||||
break;
|
||||
case LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_BEGIN:
|
||||
InteractionJankMonitorWrapper.begin(
|
||||
view,
|
||||
Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK);
|
||||
break;
|
||||
case LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_END:
|
||||
InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK);
|
||||
break;
|
||||
case LAUNCHER_WORK_UTILITY_VIEW_EXPAND_ANIMATION_BEGIN:
|
||||
InteractionJankMonitorWrapper.begin(
|
||||
view,
|
||||
Cuj.CUJ_LAUNCHER_WORK_UTILITY_VIEW_EXPAND);
|
||||
break;
|
||||
case LAUNCHER_WORK_UTILITY_VIEW_EXPAND_ANIMATION_END:
|
||||
InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_WORK_UTILITY_VIEW_EXPAND);
|
||||
break;
|
||||
case LAUNCHER_WORK_UTILITY_VIEW_SHRINK_ANIMATION_BEGIN:
|
||||
InteractionJankMonitorWrapper.begin(
|
||||
view,
|
||||
Cuj.CUJ_LAUNCHER_WORK_UTILITY_VIEW_SHRINK);
|
||||
break;
|
||||
case LAUNCHER_WORK_UTILITY_VIEW_SHRINK_ANIMATION_END:
|
||||
InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_WORK_UTILITY_VIEW_SHRINK);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private LauncherAtom.ItemInfo applyOverwrites(LauncherAtom.ItemInfo atomInfo) {
|
||||
LauncherAtom.ItemInfo.Builder itemInfoBuilder = atomInfo.toBuilder();
|
||||
|
||||
mRank.ifPresent(itemInfoBuilder::setRank);
|
||||
mContainerInfo.ifPresent(itemInfoBuilder::setContainerInfo);
|
||||
|
||||
mActivityContext.ifPresent(activityContext ->
|
||||
activityContext.applyOverwritesToLogItem(itemInfoBuilder));
|
||||
|
||||
if (mFromState.isPresent() || mToState.isPresent() || mEditText.isPresent()) {
|
||||
FolderIcon.Builder folderIconBuilder = itemInfoBuilder
|
||||
.getFolderIcon()
|
||||
.toBuilder();
|
||||
mFromState.ifPresent(folderIconBuilder::setFromLabelState);
|
||||
mToState.ifPresent(folderIconBuilder::setToLabelState);
|
||||
mEditText.ifPresent(folderIconBuilder::setLabelInfo);
|
||||
itemInfoBuilder.setFolderIcon(folderIconBuilder);
|
||||
}
|
||||
return itemInfoBuilder.build();
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private void write(EventEnum event, LauncherAtom.ItemInfo atomInfo) {
|
||||
InstanceId instanceId = mInstanceId;
|
||||
int srcState = mSrcState;
|
||||
int dstState = mDstState;
|
||||
int inputType = mInputType;
|
||||
String packageName = mPackageName.orElseGet(() -> getPackageName(atomInfo));
|
||||
if (IS_VERBOSE) {
|
||||
String name = (event instanceof Enum) ? ((Enum) event).name() :
|
||||
event.getId() + "";
|
||||
StringBuilder logStringBuilder = new StringBuilder("\n");
|
||||
if (instanceId != DEFAULT_INSTANCE_ID) {
|
||||
logStringBuilder.append(String.format("InstanceId:%s ", instanceId));
|
||||
}
|
||||
logStringBuilder.append(name);
|
||||
if (srcState != LAUNCHER_STATE_UNSPECIFIED
|
||||
|| dstState != LAUNCHER_STATE_UNSPECIFIED) {
|
||||
logStringBuilder.append(
|
||||
String.format("(State:%s->%s)", getStateString(srcState),
|
||||
getStateString(dstState)));
|
||||
}
|
||||
if (atomInfo.hasContainerInfo()) {
|
||||
logStringBuilder.append("\n").append(atomInfo);
|
||||
}
|
||||
if (!TextUtils.isEmpty(packageName)) {
|
||||
logStringBuilder.append(String.format("\nPackage name: %s", packageName));
|
||||
}
|
||||
Log.d(TAG, logStringBuilder.toString());
|
||||
}
|
||||
|
||||
for (StatsLogConsumer consumer : LOGS_CONSUMER) {
|
||||
consumer.consume(event, atomInfo);
|
||||
}
|
||||
|
||||
// TODO: remove this when b/231648228 is fixed.
|
||||
if (Utilities.isRunningInTestHarness()) {
|
||||
return;
|
||||
}
|
||||
int cardinality = mCardinality.orElseGet(() -> getCardinality(atomInfo));
|
||||
int features = mFeatures.orElseGet(() -> getFeatures(atomInfo));
|
||||
SysUiStatsLog.write(
|
||||
SysUiStatsLog.LAUNCHER_EVENT,
|
||||
SysUiStatsLog.LAUNCHER_UICHANGED__ACTION__DEFAULT_ACTION /* deprecated */,
|
||||
srcState,
|
||||
dstState,
|
||||
null /* launcher extensions, deprecated */,
|
||||
false /* quickstep_enabled, deprecated */,
|
||||
event.getId() /* event_id */,
|
||||
atomInfo.getItemCase().getNumber() /* target_id */,
|
||||
instanceId.getId() /* instance_id TODO */,
|
||||
0 /* uid TODO */,
|
||||
packageName /* package_name */,
|
||||
getComponentName(atomInfo) /* component_name */,
|
||||
getGridX(atomInfo, false) /* grid_x */,
|
||||
getGridY(atomInfo, false) /* grid_y */,
|
||||
getPageId(atomInfo) /* page_id */,
|
||||
getGridX(atomInfo, true) /* grid_x_parent */,
|
||||
getGridY(atomInfo, true) /* grid_y_parent */,
|
||||
getParentPageId(atomInfo) /* page_id_parent */,
|
||||
getHierarchy(atomInfo) /* hierarchy */,
|
||||
false /* is_work_profile, deprecated */,
|
||||
atomInfo.getRank() /* rank */,
|
||||
atomInfo.getFolderIcon().getFromLabelState().getNumber() /* fromState */,
|
||||
atomInfo.getFolderIcon().getToLabelState().getNumber() /* toState */,
|
||||
atomInfo.getFolderIcon().getLabelInfo() /* edittext */,
|
||||
cardinality /* cardinality */,
|
||||
features /* features */,
|
||||
getSearchAttributes(atomInfo) /* searchAttributes */,
|
||||
getAttributes(atomInfo) /* attributes */,
|
||||
inputType /* input_type */,
|
||||
atomInfo.getUserType() /* user_type */,
|
||||
getDisplayRotation() /* display_rotation */,
|
||||
getRecentsOrientationHandler(atomInfo) /* recents_orientation_handler */);
|
||||
}
|
||||
|
||||
private int getDisplayRotation() {
|
||||
return switch (mDisplayRotation) {
|
||||
case ROTATION_90 -> LAUNCHER_UICHANGED__DISPLAY_ROTATION__ROTATION_90;
|
||||
case ROTATION_180 -> LAUNCHER_UICHANGED__DISPLAY_ROTATION__ROTATION_180;
|
||||
case ROTATION_270 -> LAUNCHER_UICHANGED__DISPLAY_ROTATION__ROTATION_270;
|
||||
default -> LAUNCHER_UICHANGED__DISPLAY_ROTATION__ROTATION_0;
|
||||
};
|
||||
}
|
||||
|
||||
private int getRecentsOrientationHandler(LauncherAtom.ItemInfo itemInfo) {
|
||||
var orientationHandler =
|
||||
itemInfo.getContainerInfo().getTaskSwitcherContainer().getOrientationHandler();
|
||||
return switch (orientationHandler) {
|
||||
case PORTRAIT -> LAUNCHER_UICHANGED__RECENTS_ORIENTATION_HANDLER__PORTRAIT;
|
||||
case LANDSCAPE -> LAUNCHER_UICHANGED__RECENTS_ORIENTATION_HANDLER__LANDSCAPE;
|
||||
case SEASCAPE -> LAUNCHER_UICHANGED__RECENTS_ORIENTATION_HANDLER__SEASCAPE;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helps to construct and log statsd compatible latency events.
|
||||
*/
|
||||
private static class StatsCompatLatencyLogger implements StatsLatencyLogger {
|
||||
private InstanceId mInstanceId = DEFAULT_INSTANCE_ID;
|
||||
private LatencyType mType = LatencyType.UNKNOWN;
|
||||
private int mPackageId = 0;
|
||||
private long mLatencyInMillis;
|
||||
private int mQueryLength = -1;
|
||||
private int mSubEventType = 0;
|
||||
private int mCardinality = -1;
|
||||
|
||||
@Override
|
||||
public StatsLatencyLogger withInstanceId(InstanceId instanceId) {
|
||||
this.mInstanceId = instanceId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLatencyLogger withType(LatencyType type) {
|
||||
this.mType = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLatencyLogger withPackageId(int packageId) {
|
||||
this.mPackageId = packageId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLatencyLogger withLatency(long latencyInMillis) {
|
||||
this.mLatencyInMillis = latencyInMillis;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLatencyLogger withQueryLength(int queryLength) {
|
||||
this.mQueryLength = queryLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLatencyLogger withSubEventType(int type) {
|
||||
this.mSubEventType = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsLatencyLogger withCardinality(int cardinality) {
|
||||
this.mCardinality = cardinality;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(EventEnum event) {
|
||||
if (IS_VERBOSE) {
|
||||
String name = (event instanceof Enum) ? ((Enum) event).name() :
|
||||
event.getId() + "";
|
||||
StringBuilder logStringBuilder = new StringBuilder("\n");
|
||||
logStringBuilder.append(String.format("InstanceId:%s ", mInstanceId));
|
||||
logStringBuilder.append(String.format("%s=%sms", name, mLatencyInMillis));
|
||||
Log.d(LATENCY_TAG, logStringBuilder.toString());
|
||||
}
|
||||
|
||||
SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_LATENCY,
|
||||
event.getId(), // event_id
|
||||
mInstanceId.getId(), // instance_id
|
||||
mPackageId, // package_id
|
||||
mLatencyInMillis, // latency_in_millis
|
||||
mType.getId(), //type
|
||||
mQueryLength, // query_length
|
||||
mSubEventType, // sub_event_type
|
||||
mCardinality // cardinality
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helps to construct and log statsd compatible impression events.
|
||||
*/
|
||||
private static class StatsCompatImpressionLogger implements StatsImpressionLogger {
|
||||
private InstanceId mInstanceId = DEFAULT_INSTANCE_ID;
|
||||
private State mLauncherState = State.UNKNOWN;
|
||||
private int mQueryLength = -1;
|
||||
|
||||
// Fields used for Impression Logging V2.
|
||||
private int mResultType;
|
||||
private boolean mAboveKeyboard = false;
|
||||
private int mUid;
|
||||
private int mResultSource;
|
||||
|
||||
@Override
|
||||
public StatsImpressionLogger withInstanceId(InstanceId instanceId) {
|
||||
this.mInstanceId = instanceId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsImpressionLogger withState(State state) {
|
||||
this.mLauncherState = state;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsImpressionLogger withQueryLength(int queryLength) {
|
||||
this.mQueryLength = queryLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsImpressionLogger withResultType(int resultType) {
|
||||
mResultType = resultType;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public StatsImpressionLogger withAboveKeyboard(boolean aboveKeyboard) {
|
||||
mAboveKeyboard = aboveKeyboard;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsImpressionLogger withUid(int uid) {
|
||||
mUid = uid;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatsImpressionLogger withResultSource(int resultSource) {
|
||||
mResultSource = resultSource;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(EventEnum event) {
|
||||
if (IS_VERBOSE) {
|
||||
String name = (event instanceof Enum) ? ((Enum) event).name() :
|
||||
event.getId() + "";
|
||||
StringBuilder logStringBuilder = new StringBuilder("\n");
|
||||
logStringBuilder.append(String.format("InstanceId:%s ", mInstanceId));
|
||||
logStringBuilder.append(String.format("ImpressionEvent:%s ", name));
|
||||
logStringBuilder.append(String.format("\n\tLauncherState = %s ", mLauncherState));
|
||||
logStringBuilder.append(String.format("\tQueryLength = %s ", mQueryLength));
|
||||
logStringBuilder.append(String.format(
|
||||
"\n\t ResultType = %s is_above_keyboard = %s"
|
||||
+ " uid = %s result_source = %s",
|
||||
mResultType,
|
||||
mAboveKeyboard, mUid, mResultSource));
|
||||
|
||||
Log.d(IMPRESSION_TAG, logStringBuilder.toString());
|
||||
}
|
||||
|
||||
|
||||
SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_IMPRESSION_EVENT_V2,
|
||||
event.getId(), // event_id
|
||||
mInstanceId.getId(), // instance_id
|
||||
mLauncherState.getLauncherState(), // state
|
||||
mQueryLength, // query_length
|
||||
mResultType, //result type
|
||||
mAboveKeyboard, // above keyboard
|
||||
mUid, // uid
|
||||
mResultSource // result source
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static int getCardinality(LauncherAtom.ItemInfo info) {
|
||||
if (Utilities.isRunningInTestHarness()) {
|
||||
return 0;
|
||||
}
|
||||
switch (info.getContainerInfo().getContainerCase()) {
|
||||
case PREDICTED_HOTSEAT_CONTAINER:
|
||||
return info.getContainerInfo().getPredictedHotseatContainer().getCardinality();
|
||||
case TASK_BAR_CONTAINER:
|
||||
return info.getContainerInfo().getTaskBarContainer().getCardinality();
|
||||
case SEARCH_RESULT_CONTAINER:
|
||||
return info.getContainerInfo().getSearchResultContainer().getQueryLength();
|
||||
case EXTENDED_CONTAINERS:
|
||||
ExtendedContainers extendedCont = info.getContainerInfo().getExtendedContainers();
|
||||
if (extendedCont.getContainerCase() == DEVICE_SEARCH_RESULT_CONTAINER) {
|
||||
DeviceSearchResultContainer deviceSearchResultCont = extendedCont
|
||||
.getDeviceSearchResultContainer();
|
||||
return deviceSearchResultCont.hasQueryLength() ? deviceSearchResultCont
|
||||
.getQueryLength() : -1;
|
||||
}
|
||||
default:
|
||||
return switch (info.getItemCase()) {
|
||||
case FOLDER_ICON -> info.getFolderIcon().getCardinality();
|
||||
case TASK_VIEW -> info.getTaskView().getCardinality();
|
||||
default -> 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static String getPackageName(LauncherAtom.ItemInfo info) {
|
||||
return switch (info.getItemCase()) {
|
||||
case APPLICATION -> info.getApplication().getPackageName();
|
||||
case SHORTCUT -> info.getShortcut().getShortcutName();
|
||||
case WIDGET -> info.getWidget().getPackageName();
|
||||
case TASK -> info.getTask().getPackageName();
|
||||
case SEARCH_ACTION_ITEM -> info.getSearchActionItem().getPackageName();
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private static String getComponentName(LauncherAtom.ItemInfo info) {
|
||||
return switch (info.getItemCase()) {
|
||||
case APPLICATION -> info.getApplication().getComponentName();
|
||||
case SHORTCUT -> info.getShortcut().getShortcutName();
|
||||
case WIDGET -> info.getWidget().getComponentName();
|
||||
case TASK -> info.getTask().getComponentName();
|
||||
case TASK_VIEW -> info.getTaskView().getComponentName();
|
||||
case SEARCH_ACTION_ITEM -> info.getSearchActionItem().getTitle();
|
||||
case SLICE -> info.getSlice().getUri();
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private static int getGridX(LauncherAtom.ItemInfo info, boolean parent) {
|
||||
ContainerInfo containerInfo = info.getContainerInfo();
|
||||
if (containerInfo.getContainerCase() == FOLDER) {
|
||||
if (parent) {
|
||||
return containerInfo.getFolder().getWorkspace().getGridX();
|
||||
} else {
|
||||
return containerInfo.getFolder().getGridX();
|
||||
}
|
||||
} else if (containerInfo.getContainerCase() == EXTENDED_CONTAINERS) {
|
||||
return containerInfo.getExtendedContainers()
|
||||
.getDeviceSearchResultContainer().getGridX();
|
||||
} else {
|
||||
return containerInfo.getWorkspace().getGridX();
|
||||
}
|
||||
}
|
||||
|
||||
private static int getGridY(LauncherAtom.ItemInfo info, boolean parent) {
|
||||
if (info.getContainerInfo().getContainerCase() == FOLDER) {
|
||||
if (parent) {
|
||||
return info.getContainerInfo().getFolder().getWorkspace().getGridY();
|
||||
} else {
|
||||
return info.getContainerInfo().getFolder().getGridY();
|
||||
}
|
||||
} else {
|
||||
return info.getContainerInfo().getWorkspace().getGridY();
|
||||
}
|
||||
}
|
||||
|
||||
private static int getPageId(LauncherAtom.ItemInfo info) {
|
||||
return switch (info.getItemCase()) {
|
||||
case TASK -> info.getTask().getIndex();
|
||||
case TASK_VIEW -> info.getTaskView().getIndex();
|
||||
default -> getPageIdFromContainerInfo(info.getContainerInfo());
|
||||
};
|
||||
}
|
||||
|
||||
private static int getPageIdFromContainerInfo(LauncherAtom.ContainerInfo containerInfo) {
|
||||
return switch (containerInfo.getContainerCase()) {
|
||||
case FOLDER -> containerInfo.getFolder().getPageIndex();
|
||||
case HOTSEAT -> containerInfo.getHotseat().getIndex();
|
||||
case PREDICTED_HOTSEAT_CONTAINER ->
|
||||
containerInfo.getPredictedHotseatContainer().getIndex();
|
||||
case TASK_BAR_CONTAINER -> containerInfo.getTaskBarContainer().getIndex();
|
||||
default -> containerInfo.getWorkspace().getPageIndex();
|
||||
};
|
||||
}
|
||||
|
||||
private static int getParentPageId(LauncherAtom.ItemInfo info) {
|
||||
return switch (info.getContainerInfo().getContainerCase()) {
|
||||
case FOLDER -> {
|
||||
if (info.getContainerInfo().getFolder().getParentContainerCase()
|
||||
== ParentContainerCase.HOTSEAT) {
|
||||
yield info.getContainerInfo().getFolder().getHotseat().getIndex();
|
||||
}
|
||||
yield info.getContainerInfo().getFolder().getWorkspace().getPageIndex();
|
||||
}
|
||||
case SEARCH_RESULT_CONTAINER ->
|
||||
info.getContainerInfo().getSearchResultContainer().getWorkspace()
|
||||
.getPageIndex();
|
||||
default -> info.getContainerInfo().getWorkspace().getPageIndex();
|
||||
};
|
||||
}
|
||||
|
||||
private static int getHierarchy(LauncherAtom.ItemInfo info) {
|
||||
if (Utilities.isRunningInTestHarness()) {
|
||||
return 0;
|
||||
}
|
||||
if (info.getContainerInfo().getContainerCase() == FOLDER) {
|
||||
return info.getContainerInfo().getFolder().getParentContainerCase().getNumber()
|
||||
+ FOLDER_HIERARCHY_OFFSET;
|
||||
} else if (info.getContainerInfo().getContainerCase() == SEARCH_RESULT_CONTAINER) {
|
||||
return info.getContainerInfo().getSearchResultContainer().getParentContainerCase()
|
||||
.getNumber() + SEARCH_RESULT_HIERARCHY_OFFSET;
|
||||
} else if (info.getContainerInfo().getContainerCase() == EXTENDED_CONTAINERS) {
|
||||
return info.getContainerInfo().getExtendedContainers().getContainerCase().getNumber()
|
||||
+ EXTENDED_CONTAINERS_HIERARCHY_OFFSET;
|
||||
} else if (info.getContainerInfo().getContainerCase() == ALL_APPS_CONTAINER) {
|
||||
return info.getContainerInfo().getAllAppsContainer().getParentContainerCase()
|
||||
.getNumber() + ALL_APPS_HIERARCHY_OFFSET;
|
||||
} else {
|
||||
return info.getContainerInfo().getContainerCase().getNumber();
|
||||
}
|
||||
}
|
||||
|
||||
private static String getStateString(int state) {
|
||||
return switch (state) {
|
||||
case LAUNCHER_UICHANGED__DST_STATE__BACKGROUND -> "BACKGROUND";
|
||||
case LAUNCHER_UICHANGED__DST_STATE__HOME -> "HOME";
|
||||
case LAUNCHER_UICHANGED__DST_STATE__OVERVIEW -> "OVERVIEW";
|
||||
case LAUNCHER_UICHANGED__DST_STATE__ALLAPPS -> "ALLAPPS";
|
||||
default -> "INVALID";
|
||||
};
|
||||
}
|
||||
|
||||
private static int getFeatures(LauncherAtom.ItemInfo info) {
|
||||
return switch (info.getItemCase()) {
|
||||
case WIDGET -> info.getWidget().getWidgetFeatures();
|
||||
case TASK_VIEW -> info.getTaskView().getType();
|
||||
default -> 0;
|
||||
};
|
||||
}
|
||||
|
||||
private static int getSearchAttributes(LauncherAtom.ItemInfo info) {
|
||||
if (Utilities.isRunningInTestHarness()) {
|
||||
return 0;
|
||||
}
|
||||
ContainerInfo containerInfo = info.getContainerInfo();
|
||||
if (containerInfo.getContainerCase() == EXTENDED_CONTAINERS
|
||||
&& containerInfo.getExtendedContainers().getContainerCase()
|
||||
== DEVICE_SEARCH_RESULT_CONTAINER
|
||||
&& containerInfo.getExtendedContainers()
|
||||
.getDeviceSearchResultContainer().hasSearchAttributes()
|
||||
) {
|
||||
return searchAttributesToInt(containerInfo.getExtendedContainers()
|
||||
.getDeviceSearchResultContainer().getSearchAttributes());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int searchAttributesToInt(SearchAttributes searchAttributes) {
|
||||
int response = 0;
|
||||
if (searchAttributes.getCorrectedQuery()) {
|
||||
response = response | SEARCH_ATTRIBUTES_CORRECTED_QUERY;
|
||||
}
|
||||
if (searchAttributes.getDirectMatch()) {
|
||||
response = response | SEARCH_ATTRIBUTES_DIRECT_MATCH;
|
||||
}
|
||||
if (searchAttributes.getEntryState() == SearchAttributes.EntryState.ALL_APPS) {
|
||||
response = response | SEARCH_ATTRIBUTES_ENTRY_STATE_ALL_APPS;
|
||||
} else if (searchAttributes.getEntryState() == SearchAttributes.EntryState.QSB) {
|
||||
response = response | SEARCH_ATTRIBUTES_ENTRY_STATE_QSB;
|
||||
} else if (searchAttributes.getEntryState() == SearchAttributes.EntryState.OVERVIEW) {
|
||||
response = response | SEARCH_ATTRIBUTES_ENTRY_STATE_OVERVIEW;
|
||||
} else if (searchAttributes.getEntryState() == SearchAttributes.EntryState.TASKBAR) {
|
||||
response = response | SEARCH_ATTRIBUTES_ENTRY_STATE_TASKBAR;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface to get stats log while it is dispatched to the system
|
||||
*/
|
||||
public interface StatsLogConsumer {
|
||||
|
||||
@WorkerThread
|
||||
void consume(EventEnum event, LauncherAtom.ItemInfo atomInfo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,798 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.quickstep.logging
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import android.util.StatsEvent
|
||||
import android.view.Surface
|
||||
import android.view.View
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.slice.SliceItem
|
||||
import com.android.internal.jank.Cuj
|
||||
import com.android.launcher3.LauncherAppState
|
||||
import com.android.launcher3.LauncherSettings.Favorites
|
||||
import com.android.launcher3.Utilities
|
||||
import com.android.launcher3.logger.LauncherAtom
|
||||
import com.android.launcher3.logger.LauncherAtom.ContainerInfo
|
||||
import com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.ALL_APPS_CONTAINER
|
||||
import com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.EXTENDED_CONTAINERS
|
||||
import com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.FOLDER
|
||||
import com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.HOTSEAT
|
||||
import com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.PREDICTED_HOTSEAT_CONTAINER
|
||||
import com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.SEARCH_RESULT_CONTAINER
|
||||
import com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.TASK_BAR_CONTAINER
|
||||
import com.android.launcher3.logger.LauncherAtom.FolderContainer.ParentContainerCase
|
||||
import com.android.launcher3.logger.LauncherAtom.FromState
|
||||
import com.android.launcher3.logger.LauncherAtom.ItemInfo.ItemCase.APPLICATION
|
||||
import com.android.launcher3.logger.LauncherAtom.ItemInfo.ItemCase.FOLDER_ICON
|
||||
import com.android.launcher3.logger.LauncherAtom.ItemInfo.ItemCase.SEARCH_ACTION_ITEM
|
||||
import com.android.launcher3.logger.LauncherAtom.ItemInfo.ItemCase.SHORTCUT
|
||||
import com.android.launcher3.logger.LauncherAtom.ItemInfo.ItemCase.SLICE
|
||||
import com.android.launcher3.logger.LauncherAtom.ItemInfo.ItemCase.TASK
|
||||
import com.android.launcher3.logger.LauncherAtom.ItemInfo.ItemCase.TASK_VIEW
|
||||
import com.android.launcher3.logger.LauncherAtom.ItemInfo.ItemCase.WIDGET
|
||||
import com.android.launcher3.logger.LauncherAtom.LauncherAttributes
|
||||
import com.android.launcher3.logger.LauncherAtom.Slice
|
||||
import com.android.launcher3.logger.LauncherAtom.TaskSwitcherContainer.OrientationHandler.LANDSCAPE
|
||||
import com.android.launcher3.logger.LauncherAtom.TaskSwitcherContainer.OrientationHandler.PORTRAIT
|
||||
import com.android.launcher3.logger.LauncherAtom.TaskSwitcherContainer.OrientationHandler.SEASCAPE
|
||||
import com.android.launcher3.logger.LauncherAtom.ToState
|
||||
import com.android.launcher3.logger.LauncherAtomExtensions.DeviceSearchResultContainer.SearchAttributes
|
||||
import com.android.launcher3.logger.LauncherAtomExtensions.DeviceSearchResultContainer.SearchAttributes.EntryState.ALL_APPS
|
||||
import com.android.launcher3.logger.LauncherAtomExtensions.DeviceSearchResultContainer.SearchAttributes.EntryState.OVERVIEW
|
||||
import com.android.launcher3.logger.LauncherAtomExtensions.DeviceSearchResultContainer.SearchAttributes.EntryState.QSB
|
||||
import com.android.launcher3.logger.LauncherAtomExtensions.DeviceSearchResultContainer.SearchAttributes.EntryState.TASKBAR
|
||||
import com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers.ContainerCase.DEVICE_SEARCH_RESULT_CONTAINER
|
||||
import com.android.launcher3.logging.InstanceId
|
||||
import com.android.launcher3.logging.StatsLogManager
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_BEGIN
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_END
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_BEGIN
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_END
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORKSPACE_SNAPSHOT
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORK_UTILITY_VIEW_EXPAND_ANIMATION_BEGIN
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORK_UTILITY_VIEW_EXPAND_ANIMATION_END
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORK_UTILITY_VIEW_SHRINK_ANIMATION_BEGIN
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORK_UTILITY_VIEW_SHRINK_ANIMATION_END
|
||||
import com.android.launcher3.logging.StatsLogManager.StatsImpressionLogger.State
|
||||
import com.android.launcher3.logging.StatsLogManager.StatsLatencyLogger.LatencyType
|
||||
import com.android.launcher3.logging.StatsLogManager.StatsLatencyLogger.LatencyType.UNKNOWN
|
||||
import com.android.launcher3.model.data.CollectionInfo
|
||||
import com.android.launcher3.model.data.ItemInfo
|
||||
import com.android.launcher3.util.DisplayController
|
||||
import com.android.launcher3.util.Executors
|
||||
import com.android.launcher3.util.LogConfig
|
||||
import com.android.launcher3.views.ActivityContext
|
||||
import com.android.systemui.shared.system.InteractionJankMonitorWrapper
|
||||
import com.android.systemui.shared.system.SysUiStatsLog
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* This class calls StatsLog compile time generated methods.
|
||||
*
|
||||
* To see if the logs are properly sent to statsd, execute following command.
|
||||
*
|
||||
* $ wwdebug (to turn on the logcat printout) $ wwlogcat (see logcat with grep filter on) $
|
||||
* statsd_testdrive (see how ww is writing the proto to statsd buffer)
|
||||
*/
|
||||
class StatsLogCompatManager private constructor(context: Context) : StatsLogManager(context) {
|
||||
/**
|
||||
* This class is purely used to support dagger bindings to be overridden in launcher variants.
|
||||
* Very similar to [dagger.assisted.AssistedFactory]. But [dagger.assisted.AssistedFactory]
|
||||
* cannot be overridden and this makes dagger binding difficult.
|
||||
*/
|
||||
class StatsLogCompatManagerFactory @Inject internal constructor() : StatsLogManagerFactory() {
|
||||
override fun create(context: Context): StatsLogManager {
|
||||
return StatsLogCompatManager(context)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createLogger(): StatsLogger {
|
||||
return StatsCompatLogger(mContext, mActivityContext)
|
||||
}
|
||||
|
||||
override fun createLatencyLogger(): StatsLatencyLogger {
|
||||
return StatsCompatLatencyLogger()
|
||||
}
|
||||
|
||||
override fun createImpressionLogger(): StatsImpressionLogger {
|
||||
return StatsCompatImpressionLogger()
|
||||
}
|
||||
|
||||
/** Helps to construct and write statsd compatible log message. */
|
||||
private class StatsCompatLogger(
|
||||
private val context: Context,
|
||||
private val activityContext: ActivityContext?,
|
||||
) : StatsLogger {
|
||||
|
||||
private var mItemInfo: ItemInfo? = DEFAULT_ITEM_INFO
|
||||
private var mInstanceId: InstanceId? = DEFAULT_INSTANCE_ID
|
||||
private var mRank: Int? = null
|
||||
private var mContainerInfo: ContainerInfo? = null
|
||||
private var mSrcState = LAUNCHER_STATE_UNSPECIFIED
|
||||
private var mDstState = LAUNCHER_STATE_UNSPECIFIED
|
||||
private var mFromState: FromState? = null
|
||||
private var mToState: ToState? = null
|
||||
private var mEditText: String? = null
|
||||
private var mSliceItem: SliceItem? = null
|
||||
private var mSlice: Slice? = null
|
||||
private var mCardinality: Int? = null
|
||||
private var mInputType = SysUiStatsLog.LAUNCHER_UICHANGED__INPUT_TYPE__UNKNOWN
|
||||
private var mFeatures: Int? = null
|
||||
private var mPackageName: String? = null
|
||||
|
||||
/** Indicates the current rotation of the display. Uses [values.][android.view.Surface] */
|
||||
private val mDisplayRotation = DisplayController.INSTANCE[context].info.rotation
|
||||
|
||||
override fun withItemInfo(itemInfo: ItemInfo?) = apply {
|
||||
require(mContainerInfo == null) {
|
||||
"ItemInfo and ContainerInfo are mutual exclusive; cannot log both."
|
||||
}
|
||||
mItemInfo = itemInfo
|
||||
}
|
||||
|
||||
override fun withInstanceId(instanceId: InstanceId?) = apply { mInstanceId = instanceId }
|
||||
|
||||
override fun withRank(rank: Int) = apply { mRank = rank }
|
||||
|
||||
override fun withSrcState(srcState: Int) = apply { mSrcState = srcState }
|
||||
|
||||
override fun withDstState(dstState: Int) = apply { mDstState = dstState }
|
||||
|
||||
override fun withContainerInfo(containerInfo: ContainerInfo?) = apply {
|
||||
require(mItemInfo === DEFAULT_ITEM_INFO) {
|
||||
"ItemInfo and ContainerInfo are mutual exclusive; cannot log both."
|
||||
}
|
||||
this.mContainerInfo = containerInfo
|
||||
}
|
||||
|
||||
override fun withFromState(fromState: FromState?) = apply { this.mFromState = fromState }
|
||||
|
||||
override fun withToState(toState: ToState?) = apply { this.mToState = toState }
|
||||
|
||||
override fun withEditText(editText: String?) = apply { this.mEditText = editText }
|
||||
|
||||
override fun withSliceItem(sliceItem: SliceItem) = apply {
|
||||
require(mItemInfo === DEFAULT_ITEM_INFO && mSlice == null) {
|
||||
"ItemInfo, Slice and SliceItem are mutual exclusive; cannot set more than one of them."
|
||||
}
|
||||
this.mSliceItem = sliceItem
|
||||
}
|
||||
|
||||
override fun withSlice(slice: Slice) = apply {
|
||||
require(mItemInfo === DEFAULT_ITEM_INFO && mSliceItem == null) {
|
||||
"ItemInfo, Slice and SliceItem are mutual exclusive; cannot set more than one of them."
|
||||
}
|
||||
this.mSlice = slice
|
||||
}
|
||||
|
||||
override fun withCardinality(cardinality: Int) = apply { this.mCardinality = cardinality }
|
||||
|
||||
override fun withInputType(inputType: Int) = apply { this.mInputType = inputType }
|
||||
|
||||
override fun withFeatures(feature: Int) = apply { this.mFeatures = feature }
|
||||
|
||||
override fun withPackageName(packageName: String?) = apply { mPackageName = packageName }
|
||||
|
||||
override fun log(event: EventEnum) {
|
||||
if (DEBUG) {
|
||||
val name = if (event is Enum<*>) event.name else event.id.toString() + ""
|
||||
Log.d(TAG, name)
|
||||
}
|
||||
|
||||
if (mSlice == null && mSliceItem != null)
|
||||
mSlice = Slice.newBuilder().setUri(mSliceItem!!.slice!!.uri.toString()).build()
|
||||
|
||||
if (mSlice != null) {
|
||||
Executors.MODEL_EXECUTOR.execute {
|
||||
val itemInfoBuilder = LauncherAtom.ItemInfo.newBuilder().setSlice(mSlice)
|
||||
mContainerInfo?.let { itemInfoBuilder.setContainerInfo(it) }
|
||||
write(event, applyOverwrites(itemInfoBuilder.build()))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
val info = mItemInfo ?: return
|
||||
|
||||
// If the item is inside a collection, fetch collection info in a BG thread
|
||||
// and then write to StatsLog.
|
||||
LauncherAppState.INSTANCE[context].model.enqueueModelUpdateTask { _, dataModel, _ ->
|
||||
write(
|
||||
event,
|
||||
applyOverwrites(
|
||||
info.buildProto(
|
||||
dataModel.itemsIdMap[info.container] as CollectionInfo?,
|
||||
context,
|
||||
)
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun sendToInteractionJankMonitor(event: EventEnum?, view: View?) {
|
||||
if (event !is LauncherEvent) return
|
||||
when (event) {
|
||||
LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN ->
|
||||
InteractionJankMonitorWrapper.begin(view, Cuj.CUJ_LAUNCHER_ALL_APPS_SCROLL)
|
||||
|
||||
LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END ->
|
||||
InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_ALL_APPS_SCROLL)
|
||||
LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_BEGIN ->
|
||||
InteractionJankMonitorWrapper.begin(view, Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_LOCK)
|
||||
|
||||
LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_END ->
|
||||
InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_LOCK)
|
||||
LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_BEGIN ->
|
||||
InteractionJankMonitorWrapper.begin(view, Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK)
|
||||
|
||||
LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_END ->
|
||||
InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK)
|
||||
LAUNCHER_WORK_UTILITY_VIEW_EXPAND_ANIMATION_BEGIN ->
|
||||
InteractionJankMonitorWrapper.begin(
|
||||
view,
|
||||
Cuj.CUJ_LAUNCHER_WORK_UTILITY_VIEW_EXPAND,
|
||||
)
|
||||
|
||||
LAUNCHER_WORK_UTILITY_VIEW_EXPAND_ANIMATION_END ->
|
||||
InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_WORK_UTILITY_VIEW_EXPAND)
|
||||
|
||||
LAUNCHER_WORK_UTILITY_VIEW_SHRINK_ANIMATION_BEGIN ->
|
||||
InteractionJankMonitorWrapper.begin(
|
||||
view,
|
||||
Cuj.CUJ_LAUNCHER_WORK_UTILITY_VIEW_SHRINK,
|
||||
)
|
||||
|
||||
LAUNCHER_WORK_UTILITY_VIEW_SHRINK_ANIMATION_END ->
|
||||
InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_WORK_UTILITY_VIEW_SHRINK)
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
fun applyOverwrites(atomInfo: LauncherAtom.ItemInfo): LauncherAtom.ItemInfo =
|
||||
atomInfo
|
||||
.toBuilder()
|
||||
.apply {
|
||||
mRank?.let { setRank(it) }
|
||||
mContainerInfo?.let { setContainerInfo(it) }
|
||||
activityContext?.applyOverwritesToLogItem(this)
|
||||
|
||||
if (mFromState != null || mToState != null || mEditText != null) {
|
||||
val folderIconBuilder = folderIcon.toBuilder()
|
||||
mFromState?.let { folderIconBuilder.setFromLabelState(it) }
|
||||
mToState?.let { folderIconBuilder.setToLabelState(it) }
|
||||
mEditText?.let { folderIconBuilder.setLabelInfo(it) }
|
||||
|
||||
setFolderIcon(folderIconBuilder)
|
||||
}
|
||||
}
|
||||
.build()
|
||||
|
||||
@WorkerThread
|
||||
fun write(event: EventEnum, atomInfo: LauncherAtom.ItemInfo) {
|
||||
val instanceId = mInstanceId
|
||||
val srcState = mSrcState
|
||||
val dstState = mDstState
|
||||
val inputType = mInputType
|
||||
val packageName = mPackageName ?: getPackageName(atomInfo)
|
||||
|
||||
if (IS_VERBOSE) {
|
||||
val name =
|
||||
if (event is Enum<*>) (event as Enum<*>).name else event.id.toString() + ""
|
||||
val logStringBuilder = StringBuilder("\n")
|
||||
if (instanceId !== DEFAULT_INSTANCE_ID)
|
||||
logStringBuilder.append("InstanceId:$instanceId")
|
||||
|
||||
logStringBuilder.append(name)
|
||||
|
||||
if (
|
||||
srcState != LAUNCHER_STATE_UNSPECIFIED || dstState != LAUNCHER_STATE_UNSPECIFIED
|
||||
) {
|
||||
logStringBuilder.append(
|
||||
"(State:${getStateString(srcState)}->${getStateString(dstState)})"
|
||||
)
|
||||
}
|
||||
|
||||
if (atomInfo.hasContainerInfo()) logStringBuilder.append("\n$atomInfo")
|
||||
packageName?.let { logStringBuilder.append("\nPackage name: $it") }
|
||||
|
||||
Log.d(TAG, logStringBuilder.toString())
|
||||
}
|
||||
|
||||
for (consumer in LOGS_CONSUMER) {
|
||||
consumer.consume(event, atomInfo)
|
||||
}
|
||||
|
||||
// TODO: remove this when b/231648228 is fixed.
|
||||
if (Utilities.isRunningInTestHarness()) {
|
||||
return
|
||||
}
|
||||
val cardinality = mCardinality ?: getCardinality(atomInfo)
|
||||
|
||||
val features = mFeatures ?: getFeatures(atomInfo)
|
||||
|
||||
SysUiStatsLog.write(
|
||||
SysUiStatsLog.LAUNCHER_EVENT,
|
||||
SysUiStatsLog.LAUNCHER_UICHANGED__ACTION__DEFAULT_ACTION, /* deprecated */
|
||||
srcState,
|
||||
dstState,
|
||||
null, /* launcher extensions, deprecated */
|
||||
false, /* quickstep_enabled, deprecated */
|
||||
event.id, /* event_id */
|
||||
atomInfo.itemCase.number, /* target_id */
|
||||
instanceId!!.id, /* instance_id TODO */
|
||||
0, /* uid TODO */
|
||||
packageName, /* package_name */
|
||||
getComponentName(atomInfo), /* component_name */
|
||||
getGridX(atomInfo, false), /* grid_x */
|
||||
getGridY(atomInfo, false), /* grid_y */
|
||||
getPageId(atomInfo), /* page_id */
|
||||
getGridX(atomInfo, true), /* grid_x_parent */
|
||||
getGridY(atomInfo, true), /* grid_y_parent */
|
||||
getParentPageId(atomInfo), /* page_id_parent */
|
||||
getHierarchy(atomInfo), /* hierarchy */
|
||||
false, /* is_work_profile, deprecated */
|
||||
atomInfo.rank, /* rank */
|
||||
atomInfo.folderIcon.fromLabelState.number, /* fromState */
|
||||
atomInfo.folderIcon.toLabelState.number, /* toState */
|
||||
atomInfo.folderIcon.labelInfo, /* edittext */
|
||||
cardinality, /* cardinality */
|
||||
features, /* features */
|
||||
getSearchAttributes(atomInfo), /* searchAttributes */
|
||||
getAttributes(atomInfo), /* attributes */
|
||||
inputType, /* input_type */
|
||||
atomInfo.userType, /* user_type */
|
||||
displayRotation, /* display_rotation */
|
||||
getRecentsOrientationHandler(atomInfo), /* recents_orientation_handler */
|
||||
)
|
||||
}
|
||||
|
||||
val displayRotation: Int
|
||||
get() =
|
||||
when (mDisplayRotation) {
|
||||
Surface.ROTATION_90 ->
|
||||
SysUiStatsLog.LAUNCHER_UICHANGED__DISPLAY_ROTATION__ROTATION_90
|
||||
Surface.ROTATION_180 ->
|
||||
SysUiStatsLog.LAUNCHER_UICHANGED__DISPLAY_ROTATION__ROTATION_180
|
||||
Surface.ROTATION_270 ->
|
||||
SysUiStatsLog.LAUNCHER_UICHANGED__DISPLAY_ROTATION__ROTATION_270
|
||||
else -> SysUiStatsLog.LAUNCHER_UICHANGED__DISPLAY_ROTATION__ROTATION_0
|
||||
}
|
||||
|
||||
fun getRecentsOrientationHandler(itemInfo: LauncherAtom.ItemInfo): Int {
|
||||
val orientationHandler = itemInfo.containerInfo.taskSwitcherContainer.orientationHandler
|
||||
return when (orientationHandler) {
|
||||
PORTRAIT -> SysUiStatsLog.LAUNCHER_UICHANGED__RECENTS_ORIENTATION_HANDLER__PORTRAIT
|
||||
LANDSCAPE ->
|
||||
SysUiStatsLog.LAUNCHER_UICHANGED__RECENTS_ORIENTATION_HANDLER__LANDSCAPE
|
||||
SEASCAPE -> SysUiStatsLog.LAUNCHER_UICHANGED__RECENTS_ORIENTATION_HANDLER__SEASCAPE
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DEFAULT_ITEM_INFO = ItemInfo()
|
||||
|
||||
init {
|
||||
DEFAULT_ITEM_INFO.itemType = Favorites.ITEM_TYPE_NON_ACTIONABLE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Helps to construct and log statsd compatible latency events. */
|
||||
private class StatsCompatLatencyLogger : StatsLatencyLogger {
|
||||
private var mInstanceId: InstanceId? = DEFAULT_INSTANCE_ID
|
||||
private var mType: LatencyType? = UNKNOWN
|
||||
private var mPackageId = 0
|
||||
private var mLatencyInMillis: Long = 0
|
||||
private var mQueryLength = -1
|
||||
private var mSubEventType = 0
|
||||
private var mCardinality = -1
|
||||
|
||||
override fun withInstanceId(instanceId: InstanceId?) = apply {
|
||||
this.mInstanceId = instanceId
|
||||
}
|
||||
|
||||
override fun withType(type: LatencyType?) = apply { this.mType = type }
|
||||
|
||||
override fun withPackageId(packageId: Int) = apply { this.mPackageId = packageId }
|
||||
|
||||
override fun withLatency(latencyInMillis: Long) = apply {
|
||||
this.mLatencyInMillis = latencyInMillis
|
||||
}
|
||||
|
||||
override fun withQueryLength(queryLength: Int) = apply { this.mQueryLength = queryLength }
|
||||
|
||||
override fun withSubEventType(type: Int) = apply { this.mSubEventType = type }
|
||||
|
||||
override fun withCardinality(cardinality: Int) = apply { this.mCardinality = cardinality }
|
||||
|
||||
override fun log(event: EventEnum) {
|
||||
if (IS_VERBOSE) {
|
||||
val name =
|
||||
if (event is Enum<*>) (event as Enum<*>).name else event.id.toString() + ""
|
||||
Log.d(LATENCY_TAG, "InstanceId=$mInstanceId $name=${mLatencyInMillis}ms")
|
||||
}
|
||||
|
||||
SysUiStatsLog.write(
|
||||
SysUiStatsLog.LAUNCHER_LATENCY,
|
||||
event.id, // event_id
|
||||
mInstanceId!!.id, // instance_id
|
||||
mPackageId, // package_id
|
||||
mLatencyInMillis, // latency_in_millis
|
||||
mType!!.id, // type
|
||||
mQueryLength, // query_length
|
||||
mSubEventType, // sub_event_type
|
||||
mCardinality, // cardinality
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Helps to construct and log statsd compatible impression events. */
|
||||
private class StatsCompatImpressionLogger : StatsImpressionLogger {
|
||||
private var mInstanceId: InstanceId? = DEFAULT_INSTANCE_ID
|
||||
private var mLauncherState: State? = State.UNKNOWN
|
||||
private var mQueryLength = -1
|
||||
|
||||
// Fields used for Impression Logging V2.
|
||||
private var mResultType = 0
|
||||
private var mAboveKeyboard = false
|
||||
private var mUid = 0
|
||||
private var mResultSource = 0
|
||||
|
||||
override fun withInstanceId(instanceId: InstanceId?) = apply {
|
||||
this.mInstanceId = instanceId
|
||||
}
|
||||
|
||||
override fun withState(state: State?) = apply { this.mLauncherState = state }
|
||||
|
||||
override fun withQueryLength(queryLength: Int) = apply { this.mQueryLength = queryLength }
|
||||
|
||||
override fun withResultType(resultType: Int) = apply { mResultType = resultType }
|
||||
|
||||
override fun withAboveKeyboard(aboveKeyboard: Boolean) = apply {
|
||||
mAboveKeyboard = aboveKeyboard
|
||||
}
|
||||
|
||||
override fun withUid(uid: Int) = apply { mUid = uid }
|
||||
|
||||
override fun withResultSource(resultSource: Int) = apply { mResultSource = resultSource }
|
||||
|
||||
override fun log(event: EventEnum) {
|
||||
if (IS_VERBOSE) {
|
||||
val name =
|
||||
if (event is Enum<*>) (event as Enum<*>).name else event.id.toString() + ""
|
||||
Log.d(
|
||||
IMPRESSION_TAG,
|
||||
""""
|
||||
|InstanceId:$mInstanceId
|
||||
|ImpressionEvent:$name
|
||||
| LauncherState = $mLauncherState
|
||||
| QueryLength = $mQueryLength
|
||||
| ResultType=$mResultType is_above_keyboard=$mAboveKeyboard mUid=$mUid
|
||||
| result_source=$mResultSource
|
||||
|"""
|
||||
.trimMargin(),
|
||||
)
|
||||
}
|
||||
|
||||
SysUiStatsLog.write(
|
||||
SysUiStatsLog.LAUNCHER_IMPRESSION_EVENT_V2,
|
||||
event.id, // event_id
|
||||
mInstanceId!!.id, // instance_id
|
||||
mLauncherState!!.launcherState, // state
|
||||
mQueryLength, // query_length
|
||||
mResultType, // result type
|
||||
mAboveKeyboard, // above keyboard
|
||||
mUid, // uid
|
||||
mResultSource, // result source
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Interface to get stats log while it is dispatched to the system */
|
||||
interface StatsLogConsumer {
|
||||
@WorkerThread fun consume(event: EventEnum?, atomInfo: LauncherAtom.ItemInfo?)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "StatsLog"
|
||||
private const val LATENCY_TAG = "StatsLatencyLog"
|
||||
private const val IMPRESSION_TAG = "StatsImpressionLog"
|
||||
private val IS_VERBOSE = Utilities.isPropertyEnabled(LogConfig.STATSLOG)
|
||||
private val DEBUG = !Utilities.isRunningInTestHarness()
|
||||
private val DEFAULT_INSTANCE_ID: InstanceId = InstanceId.fakeInstanceId(0)
|
||||
|
||||
// LauncherAtom.ItemInfo.getDefaultInstance() should be used but until launcher proto
|
||||
// migrates
|
||||
// from nano to lite, bake constant to prevent robo test failure.
|
||||
private const val DEFAULT_PAGE_INDEX = -2
|
||||
private const val FOLDER_HIERARCHY_OFFSET = 100
|
||||
private const val SEARCH_RESULT_HIERARCHY_OFFSET = 200
|
||||
private const val EXTENDED_CONTAINERS_HIERARCHY_OFFSET = 300
|
||||
private const val ALL_APPS_HIERARCHY_OFFSET = 400
|
||||
|
||||
/** Flags for converting SearchAttribute to integer value. */
|
||||
private const val SEARCH_ATTRIBUTES_CORRECTED_QUERY = 1 shl 0
|
||||
private const val SEARCH_ATTRIBUTES_DIRECT_MATCH = 1 shl 1
|
||||
private const val SEARCH_ATTRIBUTES_ENTRY_STATE_ALL_APPS = 1 shl 2
|
||||
private const val SEARCH_ATTRIBUTES_ENTRY_STATE_QSB = 1 shl 3
|
||||
private const val SEARCH_ATTRIBUTES_ENTRY_STATE_OVERVIEW = 1 shl 4
|
||||
private const val SEARCH_ATTRIBUTES_ENTRY_STATE_TASKBAR = 1 shl 5
|
||||
|
||||
@JvmField val LOGS_CONSUMER: CopyOnWriteArrayList<StatsLogConsumer> = CopyOnWriteArrayList()
|
||||
|
||||
/** Synchronously writes an itemInfo to stats log */
|
||||
@WorkerThread
|
||||
@JvmStatic
|
||||
fun writeSnapshot(info: LauncherAtom.ItemInfo, instanceId: InstanceId) {
|
||||
if (IS_VERBOSE) {
|
||||
Log.d(TAG, String.format("\nwriteSnapshot(%d):\n%s", instanceId.id, info))
|
||||
}
|
||||
if (Utilities.isRunningInTestHarness()) {
|
||||
return
|
||||
}
|
||||
SysUiStatsLog.write(
|
||||
SysUiStatsLog.LAUNCHER_SNAPSHOT,
|
||||
LAUNCHER_WORKSPACE_SNAPSHOT.id, /* event_id */
|
||||
info.itemCase.number, /* target_id */
|
||||
instanceId.id, /* instance_id */
|
||||
0, /* uid */
|
||||
getPackageName(info), /* package_name */
|
||||
getComponentName(info), /* component_name */
|
||||
getGridX(info, false), /* grid_x */
|
||||
getGridY(info, false), /* grid_y */
|
||||
getPageId(info), /* page_id */
|
||||
getGridX(info, true), /* grid_x_parent */
|
||||
getGridY(info, true), /* grid_y_parent */
|
||||
getParentPageId(info), /* page_id_parent */
|
||||
getHierarchy(info), /* hierarchy */
|
||||
info.isWork, /* is_work_profile */
|
||||
0, /* origin */
|
||||
getCardinality(info), /* cardinality */
|
||||
info.widget.spanX,
|
||||
info.widget.spanY,
|
||||
getFeatures(info),
|
||||
getAttributes(info), /* attributes */
|
||||
)
|
||||
}
|
||||
|
||||
private fun getAttributes(itemInfo: LauncherAtom.ItemInfo): ByteArray =
|
||||
LauncherAttributes.newBuilder()
|
||||
.apply { itemInfo.itemAttributesList.forEach { addItemAttributes(it.number) } }
|
||||
.build()
|
||||
.toByteArray()
|
||||
|
||||
/**
|
||||
* Builds [StatsEvent] from [LauncherAtom.ItemInfo]. Used for pulled atom callback
|
||||
* implementation.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun buildStatsEvent(info: LauncherAtom.ItemInfo, instanceId: InstanceId?): StatsEvent {
|
||||
return SysUiStatsLog.buildStatsEvent(
|
||||
SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT, // atom ID,
|
||||
LAUNCHER_WORKSPACE_SNAPSHOT.id, // event_id = 1;
|
||||
info.itemCase.number, // item_id = 2;
|
||||
instanceId?.id ?: 0, // instance_id = 3;
|
||||
0, // uid = 4 [(is_uid) = true];
|
||||
getPackageName(info), // package_name = 5;
|
||||
getComponentName(info), // component_name = 6;
|
||||
getGridX(info, false), // grid_x = 7 [default = -1];
|
||||
getGridY(info, false), // grid_y = 8 [default = -1];
|
||||
getPageId(info), // page_id = 9 [default = -2];
|
||||
getGridX(info, true), // grid_x_parent = 10 [default = -1];
|
||||
getGridY(info, true), // grid_y_parent = 11 [default = -1];
|
||||
getParentPageId(info), // page_id_parent = 12 [default = -2];
|
||||
getHierarchy(info), // container_id = 13;
|
||||
info.isWork, // is_work_profile = 14;
|
||||
0, // attribute_id = 15;
|
||||
getCardinality(info), // cardinality = 16;
|
||||
info.widget.spanX, // span_x = 17 [default = 1];
|
||||
info.widget.spanY, // span_y = 18 [default = 1];
|
||||
getAttributes(info), /* attributes = 19 [(log_mode) = MODE_BYTES] */
|
||||
info.isKidsMode, /* is_kids_mode = 20 */
|
||||
)
|
||||
}
|
||||
|
||||
private fun getCardinality(info: LauncherAtom.ItemInfo): Int {
|
||||
if (Utilities.isRunningInTestHarness()) return 0
|
||||
|
||||
when (info.containerInfo.containerCase) {
|
||||
PREDICTED_HOTSEAT_CONTAINER ->
|
||||
return info.containerInfo.predictedHotseatContainer.cardinality
|
||||
TASK_BAR_CONTAINER -> return info.containerInfo.taskBarContainer.cardinality
|
||||
SEARCH_RESULT_CONTAINER ->
|
||||
return info.containerInfo.searchResultContainer.queryLength
|
||||
EXTENDED_CONTAINERS -> {
|
||||
val extendedCont = info.containerInfo.extendedContainers
|
||||
if (extendedCont.containerCase == DEVICE_SEARCH_RESULT_CONTAINER) {
|
||||
val deviceSearchResultCont = extendedCont.deviceSearchResultContainer
|
||||
return if (deviceSearchResultCont.hasQueryLength())
|
||||
deviceSearchResultCont.queryLength
|
||||
else -1
|
||||
}
|
||||
return when (info.itemCase) {
|
||||
FOLDER_ICON -> info.folderIcon.cardinality
|
||||
TASK_VIEW -> info.taskView.cardinality
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
else ->
|
||||
return when (info.itemCase) {
|
||||
FOLDER_ICON -> info.folderIcon.cardinality
|
||||
TASK_VIEW -> info.taskView.cardinality
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPackageName(info: LauncherAtom.ItemInfo): String? =
|
||||
when (info.itemCase) {
|
||||
APPLICATION -> info.application.packageName
|
||||
SHORTCUT -> info.shortcut.shortcutName
|
||||
WIDGET -> info.widget.packageName
|
||||
TASK -> info.task.packageName
|
||||
SEARCH_ACTION_ITEM -> info.searchActionItem.packageName
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun getComponentName(info: LauncherAtom.ItemInfo): String? =
|
||||
when (info.itemCase) {
|
||||
APPLICATION -> info.application.componentName
|
||||
SHORTCUT -> info.shortcut.shortcutName
|
||||
WIDGET -> info.widget.componentName
|
||||
TASK -> info.task.componentName
|
||||
TASK_VIEW -> info.taskView.componentName
|
||||
SEARCH_ACTION_ITEM -> info.searchActionItem.title
|
||||
SLICE -> info.slice.uri
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun getGridX(info: LauncherAtom.ItemInfo, parent: Boolean): Int {
|
||||
val containerInfo = info.containerInfo
|
||||
return if (containerInfo.containerCase == FOLDER) {
|
||||
if (parent) {
|
||||
containerInfo.folder.workspace.gridX
|
||||
} else {
|
||||
containerInfo.folder.gridX
|
||||
}
|
||||
} else if (containerInfo.containerCase == EXTENDED_CONTAINERS) {
|
||||
containerInfo.extendedContainers.deviceSearchResultContainer.gridX
|
||||
} else {
|
||||
containerInfo.workspace.gridX
|
||||
}
|
||||
}
|
||||
|
||||
private fun getGridY(info: LauncherAtom.ItemInfo, parent: Boolean): Int =
|
||||
if (info.containerInfo.containerCase == FOLDER) {
|
||||
if (parent) {
|
||||
info.containerInfo.folder.workspace.gridY
|
||||
} else {
|
||||
info.containerInfo.folder.gridY
|
||||
}
|
||||
} else {
|
||||
info.containerInfo.workspace.gridY
|
||||
}
|
||||
|
||||
private fun getPageId(info: LauncherAtom.ItemInfo): Int =
|
||||
when (info.itemCase) {
|
||||
TASK -> info.task.index
|
||||
TASK_VIEW -> info.taskView.index
|
||||
else -> getPageIdFromContainerInfo(info.containerInfo)
|
||||
}
|
||||
|
||||
private fun getPageIdFromContainerInfo(containerInfo: ContainerInfo): Int =
|
||||
when (containerInfo.containerCase) {
|
||||
FOLDER -> containerInfo.folder.pageIndex
|
||||
HOTSEAT -> containerInfo.hotseat.index
|
||||
PREDICTED_HOTSEAT_CONTAINER -> containerInfo.predictedHotseatContainer.index
|
||||
TASK_BAR_CONTAINER -> containerInfo.taskBarContainer.index
|
||||
else -> containerInfo.workspace.pageIndex
|
||||
}
|
||||
|
||||
private fun getParentPageId(info: LauncherAtom.ItemInfo): Int =
|
||||
info.containerInfo.run {
|
||||
when {
|
||||
containerCase == FOLDER &&
|
||||
folder.parentContainerCase == ParentContainerCase.HOTSEAT ->
|
||||
folder.hotseat.index
|
||||
|
||||
containerCase == FOLDER -> folder.workspace.pageIndex
|
||||
containerCase == SEARCH_RESULT_CONTAINER ->
|
||||
searchResultContainer.workspace.pageIndex
|
||||
|
||||
else -> workspace.pageIndex
|
||||
}
|
||||
}
|
||||
|
||||
private fun getHierarchy(info: LauncherAtom.ItemInfo): Int {
|
||||
if (Utilities.isRunningInTestHarness()) return 0
|
||||
|
||||
return info.containerInfo.run {
|
||||
when (containerCase) {
|
||||
FOLDER -> folder.parentContainerCase.number + FOLDER_HIERARCHY_OFFSET
|
||||
SEARCH_RESULT_CONTAINER ->
|
||||
searchResultContainer.parentContainerCase.number +
|
||||
SEARCH_RESULT_HIERARCHY_OFFSET
|
||||
EXTENDED_CONTAINERS ->
|
||||
extendedContainers.containerCase.number +
|
||||
EXTENDED_CONTAINERS_HIERARCHY_OFFSET
|
||||
ALL_APPS_CONTAINER ->
|
||||
allAppsContainer.parentContainerCase.number + ALL_APPS_HIERARCHY_OFFSET
|
||||
else -> containerCase.number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getStateString(state: Int): String =
|
||||
when (state) {
|
||||
SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__BACKGROUND -> "BACKGROUND"
|
||||
SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__HOME -> "HOME"
|
||||
SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__OVERVIEW -> "OVERVIEW"
|
||||
SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__ALLAPPS -> "ALLAPPS"
|
||||
else -> "INVALID"
|
||||
}
|
||||
|
||||
private fun getFeatures(info: LauncherAtom.ItemInfo): Int =
|
||||
when (info.itemCase) {
|
||||
WIDGET -> info.widget.widgetFeatures
|
||||
TASK_VIEW -> info.taskView.type
|
||||
else -> 0
|
||||
}
|
||||
|
||||
private fun getSearchAttributes(info: LauncherAtom.ItemInfo): Int {
|
||||
if (Utilities.isRunningInTestHarness()) return 0
|
||||
|
||||
val containerInfo = info.containerInfo
|
||||
if (
|
||||
containerInfo.containerCase == EXTENDED_CONTAINERS &&
|
||||
(containerInfo.extendedContainers.containerCase ==
|
||||
DEVICE_SEARCH_RESULT_CONTAINER) &&
|
||||
containerInfo.extendedContainers.deviceSearchResultContainer
|
||||
.hasSearchAttributes()
|
||||
) {
|
||||
return searchAttributesToInt(
|
||||
containerInfo.extendedContainers.deviceSearchResultContainer.searchAttributes
|
||||
)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
private fun searchAttributesToInt(searchAttributes: SearchAttributes): Int {
|
||||
var response = 0
|
||||
if (searchAttributes.correctedQuery)
|
||||
response = response or SEARCH_ATTRIBUTES_CORRECTED_QUERY
|
||||
|
||||
if (searchAttributes.directMatch) response = response or SEARCH_ATTRIBUTES_DIRECT_MATCH
|
||||
|
||||
response =
|
||||
response or
|
||||
when (searchAttributes.entryState) {
|
||||
ALL_APPS -> SEARCH_ATTRIBUTES_ENTRY_STATE_ALL_APPS
|
||||
QSB -> SEARCH_ATTRIBUTES_ENTRY_STATE_QSB
|
||||
OVERVIEW -> SEARCH_ATTRIBUTES_ENTRY_STATE_OVERVIEW
|
||||
TASKBAR -> SEARCH_ATTRIBUTES_ENTRY_STATE_TASKBAR
|
||||
else -> 0
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-7
@@ -40,20 +40,25 @@ import com.android.launcher3.util.SettingsCache
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Answers
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Captor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.mockito.kotlin.any
|
||||
import org.mockito.junit.MockitoJUnit
|
||||
import org.mockito.kotlin.atLeastOnce
|
||||
import org.mockito.kotlin.capture
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class SettingsChangeLoggerTest {
|
||||
|
||||
@get:Rule val mockito = MockitoJUnit.rule()
|
||||
|
||||
private val mContext: Context = ApplicationProvider.getApplicationContext()
|
||||
|
||||
private val mInstanceId = InstanceId.fakeInstanceId(1)
|
||||
@@ -64,7 +69,8 @@ class SettingsChangeLoggerTest {
|
||||
|
||||
@Mock private lateinit var mStatsLogManager: StatsLogManager
|
||||
|
||||
@Mock private lateinit var mMockLogger: StatsLogManager.StatsLogger
|
||||
@Mock(answer = Answers.RETURNS_SELF)
|
||||
private lateinit var mMockLogger: StatsLogManager.StatsLogger
|
||||
@Mock private lateinit var mTracker: DaggerSingletonTracker
|
||||
private var displayController: DisplayController = DisplayController.INSTANCE.get(mContext)
|
||||
private var settingsCache: SettingsCache = SettingsCache.INSTANCE.get(mContext)
|
||||
@@ -79,10 +85,8 @@ class SettingsChangeLoggerTest {
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
whenever(mStatsLogFactory.create(mContext)).doReturn(mStatsLogManager)
|
||||
whenever(mStatsLogManager.logger()).doReturn(mMockLogger)
|
||||
whenever(mStatsLogManager.logger().withInstanceId(any())).doReturn(mMockLogger)
|
||||
mDefaultThemedIcons = themeManager.isMonoThemeEnabled
|
||||
mDefaultAllowRotation = LauncherPrefs.get(mContext).get(ALLOW_ROTATION)
|
||||
// To match the default value of THEMED_ICONS
|
||||
@@ -128,7 +132,7 @@ class SettingsChangeLoggerTest {
|
||||
fun logSnapshot_defaultValue() {
|
||||
mSystemUnderTest.logSnapshot(mInstanceId)
|
||||
|
||||
verify(mMockLogger, atLeastOnce()).log(mEventCaptor.capture())
|
||||
verify(mMockLogger, atLeastOnce()).log(capture(mEventCaptor))
|
||||
val capturedEvents = mEventCaptor.allValues
|
||||
assertThat(capturedEvents.isNotEmpty()).isTrue()
|
||||
verifyDefaultEvent(capturedEvents)
|
||||
@@ -144,7 +148,7 @@ class SettingsChangeLoggerTest {
|
||||
SettingsChangeLogger(mContext, mTracker, displayController, settingsCache, mStatsLogFactory)
|
||||
.logSnapshot(mInstanceId)
|
||||
|
||||
verify(mMockLogger, atLeastOnce()).log(mEventCaptor.capture())
|
||||
verify(mMockLogger, atLeastOnce()).log(capture(mEventCaptor))
|
||||
val capturedEvents = mEventCaptor.allValues
|
||||
assertThat(capturedEvents.isNotEmpty()).isTrue()
|
||||
verifyDefaultEvent(capturedEvents)
|
||||
|
||||
@@ -27,7 +27,7 @@ import com.android.launcher3.LauncherConstants.TraceEvents.SINGLE_TRACE_COOKIE
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherLatencyEvent
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherLatencyEvent.LAUNCHER_LATENCY_STARTUP_TOTAL_DURATION
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherLatencyEvent.LAUNCHER_LATENCY_STARTUP_WORKSPACE_LOADER_ASYNC
|
||||
import com.android.launcher3.logging.StatsLogManager.StatsLatencyLogger.LAUNCHER_LATENCY_PACKAGE_ID
|
||||
import com.android.launcher3.logging.StatsLogManager.StatsLatencyLogger.Companion.LAUNCHER_LATENCY_PACKAGE_ID
|
||||
import com.android.launcher3.logging.StatsLogManager.StatsLatencyLogger.LatencyType
|
||||
import com.android.launcher3.util.Executors
|
||||
import com.android.launcher3.util.LockedUserState
|
||||
|
||||
+338
-813
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -25,7 +25,7 @@ import com.android.launcher3.logging.StatsLogManager.LauncherLatencyEvent.LAUNCH
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherLatencyEvent.LAUNCHER_LATENCY_STARTUP_VIEW_INFLATION
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherLatencyEvent.LAUNCHER_LATENCY_STARTUP_WORKSPACE_LOADER_ASYNC
|
||||
import com.android.launcher3.logging.StatsLogManager.StatsLatencyLogger
|
||||
import com.android.launcher3.logging.StatsLogManager.StatsLatencyLogger.LAUNCHER_LATENCY_PACKAGE_ID
|
||||
import com.android.launcher3.logging.StatsLogManager.StatsLatencyLogger.Companion.LAUNCHER_LATENCY_PACKAGE_ID
|
||||
import com.android.launcher3.logging.StatsLogManager.StatsLatencyLogger.LatencyType
|
||||
import com.android.launcher3.util.Executors.MAIN_EXECUTOR
|
||||
import com.android.launcher3.util.LauncherMultivalentJUnit
|
||||
|
||||
Reference in New Issue
Block a user