Refactor UserEventLogging, Add predictedRank, replace Bundle with Proto
b/26494415 - Removed bundle object that became redundant now that we have LauncherEvent proto - Combined Stats and UserEventLogger as they are effectively doing same thing - Removed parent field inside Target - added predictedRank target inside Target b/27967359 - make com.android.launcher3.action.LAUNCH broadcast explicit Later CL: finish packageName/intent/componentHash/predictedRank fields Change-Id: I441fb46c834f73e58a4d2324e8da7971e8713ec8
This commit is contained in:
parent
30a716157b
commit
ddec1c739e
|
@ -32,59 +32,66 @@ message Target {
|
|||
|
||||
// For container type and item type
|
||||
// Used mainly for ContainerType.FOLDER, ItemType.*
|
||||
optional Target parent = 2;
|
||||
optional int32 page_index = 3;
|
||||
optional int32 rank = 4;
|
||||
optional int32 grid_x = 5;
|
||||
optional int32 grid_y = 6;
|
||||
optional int32 page_index = 2;
|
||||
optional int32 rank = 3;
|
||||
optional int32 grid_x = 4;
|
||||
optional int32 grid_y = 5;
|
||||
|
||||
// For container types only
|
||||
optional ContainerType container_type = 7;
|
||||
optional int32 cardinality = 8;
|
||||
optional ContainerType container_type = 6;
|
||||
optional int32 cardinality = 7;
|
||||
|
||||
// For control types only
|
||||
optional ControlType control_type = 9;
|
||||
optional ControlType control_type = 8;
|
||||
|
||||
// For item types only
|
||||
optional ItemType item_type = 10;
|
||||
optional int32 package_name_hash = 11;
|
||||
optional int32 component_hash = 12; // Used for ItemType.WIDGET
|
||||
optional int32 intent_hash = 13; // Used for ItemType.SHORTCUT
|
||||
optional int32 span_x = 14 [default = 1];// Used for ItemType.WIDGET
|
||||
optional int32 span_y = 15 [default = 1];// Used for ItemType.WIDGET
|
||||
optional ItemType item_type = 9;
|
||||
optional int32 package_name_hash = 10;
|
||||
optional int32 component_hash = 11; // Used for ItemType.WIDGET
|
||||
optional int32 intent_hash = 12; // Used for ItemType.SHORTCUT
|
||||
optional int32 span_x = 13 [default = 1];// Used for ItemType.WIDGET
|
||||
optional int32 span_y = 14 [default = 1];// Used for ItemType.WIDGET
|
||||
optional int32 predictedRank = 15;
|
||||
}
|
||||
|
||||
// Used to define what type of item a Target would represent.
|
||||
enum ItemType {
|
||||
APP_ICON = 0;
|
||||
SHORTCUT = 1;
|
||||
WIDGET = 2;
|
||||
FOLDER_ICON = 3;
|
||||
DEFAULT_ITEMTYPE = 0;
|
||||
APP_ICON = 1;
|
||||
SHORTCUT = 2;
|
||||
WIDGET = 3;
|
||||
FOLDER_ICON = 4;
|
||||
}
|
||||
|
||||
// Used to define what type of container a Target would represent.
|
||||
enum ContainerType {
|
||||
WORKSPACE = 0;
|
||||
HOTSEAT = 1;
|
||||
FOLDER = 2;
|
||||
ALLAPPS = 3;
|
||||
WIDGETS = 4;
|
||||
OVERVIEW = 5;
|
||||
PREDICTION = 6;
|
||||
SEARCHRESULT = 7;
|
||||
DEFAULT_CONTAINERTYPE = 0;
|
||||
WORKSPACE = 1;
|
||||
HOTSEAT = 2;
|
||||
FOLDER = 3;
|
||||
ALLAPPS = 4;
|
||||
WIDGETS = 5;
|
||||
OVERVIEW = 6;
|
||||
PREDICTION = 7;
|
||||
SEARCHRESULT = 8;
|
||||
}
|
||||
|
||||
// Used to define what type of control a Target would represent.
|
||||
enum ControlType {
|
||||
ALL_APPS_BUTTON = 0;
|
||||
WIDGETS_BUTTON = 1;
|
||||
WALLPAPER_BUTTON = 2;
|
||||
SETTINGS_BUTTON = 3;
|
||||
REMOVE_TARGET = 4;
|
||||
UNINSTALL_TARGET = 5;
|
||||
APPINFO_TARGET = 6;
|
||||
RESIZE_HANDLE = 7;
|
||||
FAST_SCROLL_HANDLE = 8;
|
||||
DEFAULT_CONTROLTYPE = 0;
|
||||
ALL_APPS_BUTTON = 1;
|
||||
WIDGETS_BUTTON = 2;
|
||||
WALLPAPER_BUTTON = 3;
|
||||
SETTINGS_BUTTON = 4;
|
||||
REMOVE_TARGET = 5;
|
||||
UNINSTALL_TARGET = 6;
|
||||
APPINFO_TARGET = 7;
|
||||
RESIZE_HANDLE = 8;
|
||||
VERTICAL_SCROLL = 9;
|
||||
// HOME, BACK, GO_TO_PLAYSTORE
|
||||
}
|
||||
|
||||
// Used to define the action component of the LauncherEvent.
|
||||
message Action {
|
||||
enum Type {
|
||||
TOUCH = 0;
|
||||
|
@ -113,10 +120,10 @@ message LauncherEvent {
|
|||
required Action action = 1;
|
||||
|
||||
// List of targets that touch actions can be operated on.
|
||||
optional Target src_target = 2;
|
||||
optional Target dest_target = 3;
|
||||
repeated Target src_target = 2;
|
||||
repeated Target dest_target = 3;
|
||||
|
||||
optional int64 action_duration_millis = 4;
|
||||
optional int64 elapsed_container_millis = 5;
|
||||
optional int64 elapsed_session_millis = 6;
|
||||
}
|
||||
}
|
|
@ -68,6 +68,10 @@
|
|||
filter the activities shown in the launcher. Can be empty. -->
|
||||
<string name="app_filter_class" translatable="false"></string>
|
||||
|
||||
<!-- List of package names that com.android.launcher3.action.LAUNCH
|
||||
should be targeting. Can be empty. -->
|
||||
<array name="launch_broadcast_targets" translatable="false"></array>
|
||||
|
||||
<!-- Name of an icon provider class. -->
|
||||
<string name="icon_provider_class" translatable="false"></string>
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ package com.android.launcher3;
|
|||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
|
@ -28,8 +27,12 @@ import android.view.ViewDebug;
|
|||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.launcher3.logging.UserEventLogger;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
|
||||
|
||||
public class Hotseat extends FrameLayout
|
||||
implements Stats.LaunchSourceProvider{
|
||||
implements UserEventLogger.LaunchSourceProvider{
|
||||
|
||||
private CellLayout mContent;
|
||||
|
||||
|
@ -157,7 +160,10 @@ public class Hotseat extends FrameLayout
|
|||
}
|
||||
|
||||
@Override
|
||||
public void fillInLaunchSourceData(View v, Bundle sourceData) {
|
||||
sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_HOTSEAT);
|
||||
public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
|
||||
target.itemType = LauncherLogProto.APP_ICON;
|
||||
target.gridX = info.cellX;
|
||||
target.gridY = info.cellY;
|
||||
targetParent.containerType = LauncherLogProto.HOTSEAT;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,6 +148,7 @@ public class Launcher extends Activity
|
|||
static final boolean DEBUG_WIDGETS = false;
|
||||
static final boolean DEBUG_STRICT_MODE = false;
|
||||
static final boolean DEBUG_RESUME_TIME = false;
|
||||
static final boolean DEBUG_LOGGING = false;
|
||||
|
||||
static final boolean ENABLE_DEBUG_INTENTS = false; // allow DebugIntents to run
|
||||
|
||||
|
@ -174,7 +175,7 @@ public class Launcher extends Activity
|
|||
protected static final int REQUEST_LAST = 100;
|
||||
|
||||
// To turn on these properties, type
|
||||
// adb shell setprop log.tag.PROPERTY_NAME [VERBOSE | SUPPRESS]
|
||||
// adb shell setprop logTap.tag.PROPERTY_NAME [VERBOSE | SUPPRESS]
|
||||
static final String DUMP_STATE_PROPERTY = "launcher_dump_state";
|
||||
|
||||
// The Intent extra that defines whether to ignore the launch animation
|
||||
|
@ -365,7 +366,6 @@ public class Launcher extends Activity
|
|||
int appWidgetId;
|
||||
}
|
||||
|
||||
private Stats mStats;
|
||||
private UserEventLogger mUserEventLogger;
|
||||
|
||||
public FocusIndicatorView mFocusHandler;
|
||||
|
@ -425,7 +425,6 @@ public class Launcher extends Activity
|
|||
mDragController = new DragController(this);
|
||||
mStateTransitionAnimation = new LauncherStateTransitionAnimation(this);
|
||||
|
||||
mStats = new Stats(this);
|
||||
initLogger();
|
||||
|
||||
mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
|
||||
|
@ -638,10 +637,6 @@ public class Launcher extends Activity
|
|||
}
|
||||
}
|
||||
|
||||
public Stats getStats() {
|
||||
return mStats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logger object is a singleton and does not have to be coupled with the foreground activity.
|
||||
* Since most user event logging is done on the UI, the object is retrieved from the
|
||||
|
@ -652,16 +647,19 @@ public class Launcher extends Activity
|
|||
mUserEventLogger = mLauncherCallbacks.getLogger();
|
||||
}
|
||||
if (mUserEventLogger == null) {
|
||||
mUserEventLogger = new UserEventLogger() {
|
||||
mUserEventLogger = new UserEventLogger(this) {
|
||||
@Override
|
||||
public void processEvent(LauncherLogProto.LauncherEvent ev) {
|
||||
if (ev.action.touch == LauncherLogProto.Action.TAP && ev.srcTarget.itemType == LauncherLogProto.APP_ICON) {
|
||||
Log.d(TAG, String.format(Locale.US, "action:%s target:%s\n\telapsed container %d ms session %d ms",
|
||||
LoggerUtils.getActionStr(ev.action),
|
||||
LoggerUtils.getTargetStr(ev.srcTarget),
|
||||
ev.elapsedContainerMillis,
|
||||
ev.elapsedSessionMillis));
|
||||
if (!DEBUG_LOGGING) {
|
||||
return;
|
||||
}
|
||||
Log.d("UserEvent", String.format(Locale.US,
|
||||
"action:%s\nchild:%s\nparent:%s\nelapsed container %d ms session %d ms",
|
||||
LoggerUtils.getActionStr(ev.action),
|
||||
LoggerUtils.getTargetStr(ev.srcTarget[0]),
|
||||
LoggerUtils.getTargetStr(ev.srcTarget[1]),
|
||||
ev.elapsedContainerMillis,
|
||||
ev.elapsedSessionMillis));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -2705,7 +2703,7 @@ public class Launcher extends Activity
|
|||
}
|
||||
|
||||
boolean success = startActivitySafely(v, intent, tag);
|
||||
mStats.recordLaunch(v, intent, shortcut);
|
||||
mUserEventLogger.logLaunch(v, intent);
|
||||
|
||||
if (success && v instanceof BubbleTextView) {
|
||||
mWaitingForResume = (BubbleTextView) v;
|
||||
|
@ -3488,6 +3486,7 @@ public class Launcher extends Activity
|
|||
List<ComponentKey> apps = mLauncherCallbacks.getPredictedApps();
|
||||
if (apps != null) {
|
||||
mAppsView.setPredictedApps(apps);
|
||||
mUserEventLogger.setPredictedApps(apps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
package com.android.launcher3;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.android.launcher3.allapps.AllAppsSearchBarController;
|
||||
import com.android.launcher3.logging.UserEventLogger;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
|
|
|
@ -39,8 +39,8 @@ public class LauncherFiles {
|
|||
|
||||
// TODO: Delete these files on upgrade
|
||||
public static final List<String> OBSOLETE_FILES = Collections.unmodifiableList(Arrays.asList(
|
||||
"launches.log",
|
||||
"stats.log",
|
||||
"launches.logTap",
|
||||
"stats.logTap",
|
||||
"launcher.preferences",
|
||||
"com.android.launcher3.compat.PackageInstallerCompatV16.queue"));
|
||||
}
|
||||
|
|
|
@ -1,152 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewParent;
|
||||
|
||||
import com.android.launcher3.config.ProviderConfig;
|
||||
|
||||
public class Stats {
|
||||
|
||||
/**
|
||||
* Implemented by containers to provide a launch source for a given child.
|
||||
*/
|
||||
public interface LaunchSourceProvider {
|
||||
void fillInLaunchSourceData(View v, Bundle sourceData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helpers to add the source to a launch intent.
|
||||
*/
|
||||
public static class LaunchSourceUtils {
|
||||
/**
|
||||
* Create a default bundle for LaunchSourceProviders to fill in their data.
|
||||
*/
|
||||
public static Bundle createSourceData() {
|
||||
Bundle sourceData = new Bundle();
|
||||
sourceData.putString(SOURCE_EXTRA_CONTAINER, CONTAINER_HOMESCREEN);
|
||||
// Have default container/sub container pages
|
||||
sourceData.putInt(SOURCE_EXTRA_CONTAINER_PAGE, 0);
|
||||
sourceData.putInt(SOURCE_EXTRA_SUB_CONTAINER_PAGE, 0);
|
||||
return sourceData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the next launch source provider in the parents of the view hierarchy and populates
|
||||
* the source data from that provider.
|
||||
*/
|
||||
public static void populateSourceDataFromAncestorProvider(View v, Bundle sourceData) {
|
||||
if (v == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Stats.LaunchSourceProvider provider = null;
|
||||
ViewParent parent = v.getParent();
|
||||
while (parent != null && parent instanceof View) {
|
||||
if (parent instanceof Stats.LaunchSourceProvider) {
|
||||
provider = (Stats.LaunchSourceProvider) parent;
|
||||
break;
|
||||
}
|
||||
parent = parent.getParent();
|
||||
}
|
||||
|
||||
if (provider != null) {
|
||||
provider.fillInLaunchSourceData(v, sourceData);
|
||||
} else if (ProviderConfig.IS_DOGFOOD_BUILD) {
|
||||
throw new RuntimeException("Expected LaunchSourceProvider");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final boolean DEBUG_BROADCASTS = false;
|
||||
|
||||
public static final String ACTION_LAUNCH = "com.android.launcher3.action.LAUNCH";
|
||||
public static final String EXTRA_INTENT = "intent";
|
||||
public static final String EXTRA_CONTAINER = "container";
|
||||
public static final String EXTRA_SCREEN = "screen";
|
||||
public static final String EXTRA_CELLX = "cellX";
|
||||
public static final String EXTRA_CELLY = "cellY";
|
||||
public static final String EXTRA_SOURCE = "source";
|
||||
|
||||
public static final String SOURCE_EXTRA_CONTAINER = "container";
|
||||
public static final String SOURCE_EXTRA_CONTAINER_PAGE = "container_page";
|
||||
public static final String SOURCE_EXTRA_SUB_CONTAINER = "sub_container";
|
||||
public static final String SOURCE_EXTRA_SUB_CONTAINER_PAGE = "sub_container_page";
|
||||
|
||||
public static final String CONTAINER_SEARCH_BOX = "search_box";
|
||||
public static final String CONTAINER_ALL_APPS = "all_apps";
|
||||
public static final String CONTAINER_HOMESCREEN = "homescreen"; // aka. Workspace
|
||||
public static final String CONTAINER_HOTSEAT = "hotseat";
|
||||
|
||||
public static final String SUB_CONTAINER_FOLDER = "folder";
|
||||
public static final String SUB_CONTAINER_ALL_APPS_A_Z = "a-z";
|
||||
public static final String SUB_CONTAINER_ALL_APPS_PREDICTION = "prediction";
|
||||
public static final String SUB_CONTAINER_ALL_APPS_SEARCH = "search";
|
||||
|
||||
private final Launcher mLauncher;
|
||||
private final String mLaunchBroadcastPermission;
|
||||
|
||||
public Stats(Launcher launcher) {
|
||||
mLauncher = launcher;
|
||||
mLaunchBroadcastPermission =
|
||||
launcher.getResources().getString(R.string.receive_launch_broadcasts_permission);
|
||||
|
||||
if (DEBUG_BROADCASTS) {
|
||||
launcher.registerReceiver(
|
||||
new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.v("Stats", "got broadcast: " + intent + " for launched intent: "
|
||||
+ intent.getStringExtra(EXTRA_INTENT));
|
||||
}
|
||||
},
|
||||
new IntentFilter(ACTION_LAUNCH),
|
||||
mLaunchBroadcastPermission,
|
||||
null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void recordLaunch(View v, Intent intent, ShortcutInfo shortcut) {
|
||||
intent = new Intent(intent);
|
||||
intent.setSourceBounds(null);
|
||||
|
||||
final String flat = intent.toUri(0);
|
||||
Intent broadcastIntent = new Intent(ACTION_LAUNCH).putExtra(EXTRA_INTENT, flat);
|
||||
if (shortcut != null) {
|
||||
broadcastIntent.putExtra(EXTRA_CONTAINER, shortcut.container)
|
||||
.putExtra(EXTRA_SCREEN, shortcut.screenId)
|
||||
.putExtra(EXTRA_CELLX, shortcut.cellX)
|
||||
.putExtra(EXTRA_CELLY, shortcut.cellY);
|
||||
}
|
||||
|
||||
Bundle sourceExtras = LaunchSourceUtils.createSourceData();
|
||||
LaunchSourceUtils.populateSourceDataFromAncestorProvider(v, sourceExtras);
|
||||
broadcastIntent.putExtra(EXTRA_SOURCE, sourceExtras);
|
||||
mLauncher.sendBroadcast(broadcastIntent, mLaunchBroadcastPermission);
|
||||
if (intent.getComponent() != null) {
|
||||
mLauncher.getLogger().logAppLaunch(intent.getComponent().getPackageName(), shortcut, sourceExtras);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -39,7 +39,6 @@ import android.graphics.Rect;
|
|||
import android.graphics.Region.Op;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcelable;
|
||||
|
@ -73,6 +72,9 @@ import com.android.launcher3.dragndrop.DragView;
|
|||
import com.android.launcher3.dragndrop.SpringLoadedDragController;
|
||||
import com.android.launcher3.folder.Folder;
|
||||
import com.android.launcher3.folder.FolderIcon;
|
||||
import com.android.launcher3.logging.UserEventLogger;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
|
||||
import com.android.launcher3.util.LongArrayMap;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.util.WallpaperOffsetInterpolator;
|
||||
|
@ -92,7 +94,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
public class Workspace extends PagedView
|
||||
implements DropTarget, DragSource, DragScroller, View.OnTouchListener,
|
||||
DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener,
|
||||
Insettable, DropTargetSource, AccessibilityDragSource, Stats.LaunchSourceProvider {
|
||||
Insettable, DropTargetSource, AccessibilityDragSource, UserEventLogger.LaunchSourceProvider {
|
||||
private static final String TAG = "Launcher.Workspace";
|
||||
|
||||
private static boolean ENFORCE_DRAG_EVENT_ORDER = false;
|
||||
|
@ -4264,9 +4266,12 @@ public class Workspace extends PagedView
|
|||
}
|
||||
|
||||
@Override
|
||||
public void fillInLaunchSourceData(View v, Bundle sourceData) {
|
||||
sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_HOMESCREEN);
|
||||
sourceData.putInt(Stats.SOURCE_EXTRA_CONTAINER_PAGE, getCurrentPage());
|
||||
public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
|
||||
target.itemType = LauncherLogProto.APP_ICON;
|
||||
target.gridX = info.cellX;
|
||||
target.gridY = info.cellY;
|
||||
target.pageIndex = getCurrentPage();
|
||||
targetParent.containerType = LauncherLogProto.WORKSPACE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -19,7 +19,6 @@ import android.content.Context;
|
|||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
@ -27,17 +26,19 @@ import android.view.View;
|
|||
import com.android.launcher3.BaseRecyclerView;
|
||||
import com.android.launcher3.BubbleTextView;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Stats;
|
||||
import com.android.launcher3.Utilities;
|
||||
|
||||
import com.android.launcher3.logging.UserEventLogger.LaunchSourceProvider;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A RecyclerView with custom fast scroll support for the all apps view.
|
||||
*/
|
||||
public class AllAppsRecyclerView extends BaseRecyclerView
|
||||
implements Stats.LaunchSourceProvider {
|
||||
implements LaunchSourceProvider {
|
||||
|
||||
private AlphabeticalAppsList mApps;
|
||||
private AllAppsFastScrollHelper mFastScrollHelper;
|
||||
|
@ -165,11 +166,9 @@ public class AllAppsRecyclerView extends BaseRecyclerView
|
|||
}
|
||||
|
||||
@Override
|
||||
public void fillInLaunchSourceData(View v, Bundle sourceData) {
|
||||
sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_ALL_APPS);
|
||||
public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
|
||||
if (mApps.hasFilter()) {
|
||||
sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER,
|
||||
Stats.SUB_CONTAINER_ALL_APPS_SEARCH);
|
||||
targetParent.containerType = LauncherLogProto.SEARCHRESULT;
|
||||
} else {
|
||||
if (v instanceof BubbleTextView) {
|
||||
BubbleTextView icon = (BubbleTextView) v;
|
||||
|
@ -178,14 +177,13 @@ public class AllAppsRecyclerView extends BaseRecyclerView
|
|||
List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
|
||||
AlphabeticalAppsList.AdapterItem item = items.get(position);
|
||||
if (item.viewType == AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) {
|
||||
sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER,
|
||||
Stats.SUB_CONTAINER_ALL_APPS_PREDICTION);
|
||||
targetParent.containerType = LauncherLogProto.PREDICTION;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER,
|
||||
Stats.SUB_CONTAINER_ALL_APPS_A_Z);
|
||||
|
||||
targetParent.containerType = LauncherLogProto.ALLAPPS;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ import android.graphics.Point;
|
|||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
import android.text.Selection;
|
||||
import android.text.Spannable;
|
||||
|
@ -70,7 +69,6 @@ import com.android.launcher3.LogDecelerateInterpolator;
|
|||
import com.android.launcher3.OnAlarmListener;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.ShortcutInfo;
|
||||
import com.android.launcher3.Stats;
|
||||
import com.android.launcher3.UninstallDropTarget.DropTargetSource;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.Workspace.ItemOperator;
|
||||
|
@ -79,6 +77,9 @@ import com.android.launcher3.config.FeatureFlags;
|
|||
import com.android.launcher3.dragndrop.DragController;
|
||||
import com.android.launcher3.dragndrop.DragController.DragListener;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.logging.UserEventLogger.LaunchSourceProvider;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.util.UiThreadCircularReveal;
|
||||
|
||||
|
@ -92,7 +93,7 @@ import java.util.Comparator;
|
|||
public class Folder extends LinearLayout implements DragSource, View.OnClickListener,
|
||||
View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener,
|
||||
View.OnFocusChangeListener, DragListener, DropTargetSource, AccessibilityDragSource,
|
||||
Stats.LaunchSourceProvider {
|
||||
LaunchSourceProvider {
|
||||
private static final String TAG = "Launcher.Folder";
|
||||
|
||||
/**
|
||||
|
@ -1416,11 +1417,12 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
|
|||
}
|
||||
|
||||
@Override
|
||||
public void fillInLaunchSourceData(View v, Bundle sourceData) {
|
||||
// Fill in from the folder icon's launch source provider first
|
||||
Stats.LaunchSourceUtils.populateSourceDataFromAncestorProvider(mFolderIcon, sourceData);
|
||||
sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER, Stats.SUB_CONTAINER_FOLDER);
|
||||
sourceData.putInt(Stats.SOURCE_EXTRA_SUB_CONTAINER_PAGE, mContent.getCurrentPage());
|
||||
public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
|
||||
target.itemType = LauncherLogProto.APP_ICON;
|
||||
target.gridX = info.cellX;
|
||||
target.gridY = info.cellY;
|
||||
target.pageIndex = mContent.getCurrentPage();
|
||||
targetParent.containerType = LauncherLogProto.FOLDER;
|
||||
}
|
||||
|
||||
private class OnScrollHintListener implements OnAlarmListener {
|
||||
|
|
|
@ -5,7 +5,6 @@ import android.util.Log;
|
|||
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.ShortcutInfo;
|
||||
import com.android.launcher3.Stats;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
|
||||
|
@ -18,16 +17,6 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
|
|||
*/
|
||||
public class LoggerUtils {
|
||||
private static final String TAG = "LoggerUtils";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
static int getContainerType(ShortcutInfo shortcut) {
|
||||
switch ((int) shortcut.container) {
|
||||
case LauncherSettings.Favorites.CONTAINER_DESKTOP: return LauncherLogProto.WORKSPACE;
|
||||
case LauncherSettings.Favorites.CONTAINER_HOTSEAT: return LauncherLogProto.HOTSEAT;
|
||||
default:
|
||||
return (int) shortcut.container;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getActionStr(LauncherLogProto.Action action) {
|
||||
switch(action.touch) {
|
||||
|
@ -62,8 +51,10 @@ public class LoggerUtils {
|
|||
default: typeStr = "UNKNOWN";
|
||||
}
|
||||
|
||||
return typeStr + " " + t.packageNameHash + " grid=(" + t.gridX + "," + t.gridY + ") "
|
||||
+ getContainerStr(t.parent);
|
||||
return typeStr + ", packageHash=" + t.packageNameHash
|
||||
+ ", componentHash=" + t.componentHash
|
||||
+ ", intentHash=" + t.intentHash
|
||||
+ ", grid=(" + t.gridX + "," + t.gridY + "), id=" + t.pageIndex;
|
||||
}
|
||||
|
||||
private static String getControlStr(Target t) {
|
||||
|
@ -76,7 +67,6 @@ public class LoggerUtils {
|
|||
case LauncherLogProto.UNINSTALL_TARGET: return "UNINSTALL_TARGET";
|
||||
case LauncherLogProto.APPINFO_TARGET: return "APPINFO_TARGET";
|
||||
case LauncherLogProto.RESIZE_HANDLE: return "RESIZE_HANDLE";
|
||||
case LauncherLogProto.FAST_SCROLL_HANDLE: return "FAST_SCROLL_HANDLE";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
@ -114,4 +104,22 @@ public class LoggerUtils {
|
|||
}
|
||||
return str + " id=" + t.pageIndex;
|
||||
}
|
||||
|
||||
|
||||
public static LauncherLogProto.LauncherEvent initLauncherEvent(
|
||||
int actionType,
|
||||
int childTargetType,
|
||||
int parentTargetType){
|
||||
LauncherLogProto.LauncherEvent event = new LauncherLogProto.LauncherEvent();
|
||||
|
||||
event.srcTarget = new LauncherLogProto.Target[2];
|
||||
event.srcTarget[0] = new LauncherLogProto.Target();
|
||||
event.srcTarget[0].type = childTargetType;
|
||||
event.srcTarget[1] = new LauncherLogProto.Target();
|
||||
event.srcTarget[1].type = parentTargetType;
|
||||
|
||||
event.action = new LauncherLogProto.Action();
|
||||
event.action.type = actionType;
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,71 +1,182 @@
|
|||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3.logging;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewParent;
|
||||
|
||||
import com.android.launcher3.ShortcutInfo;
|
||||
import com.android.launcher3.Stats;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
|
||||
import java.util.Locale;
|
||||
import com.google.protobuf.nano.MessageNano;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class UserEventLogger {
|
||||
|
||||
private final static int MAXIMUM_VIEW_HIERARCHY_LEVEL = 5;
|
||||
/**
|
||||
* Implemented by containers to provide a launch source for a given child.
|
||||
*/
|
||||
public interface LaunchSourceProvider {
|
||||
|
||||
/**
|
||||
* Copies data from the source to the destination proto.
|
||||
* @param v source of the data
|
||||
* @param info source of the data
|
||||
* @param target dest of the data
|
||||
* @param targetParent dest of the data
|
||||
*/
|
||||
void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively finds the parent of the given child which implements IconLogInfoProvider
|
||||
*/
|
||||
public static LaunchSourceProvider getLaunchProviderRecursive(View v) {
|
||||
ViewParent parent = null;
|
||||
if (v != null) {
|
||||
parent = v.getParent();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Optimization to only check up to 5 parents.
|
||||
int count = MAXIMUM_VIEW_HIERARCHY_LEVEL;
|
||||
while (parent != null && count-- > 0) {
|
||||
if (parent instanceof LaunchSourceProvider) {
|
||||
return (LaunchSourceProvider) parent;
|
||||
} else {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String TAG = "UserEventLogger";
|
||||
private boolean DEBUG = false;
|
||||
private static final boolean DEBUG_BROADCASTS = true;
|
||||
|
||||
public static final String ACTION_LAUNCH = "com.android.launcher3.action.LAUNCH";
|
||||
public static final String EXTRA_INTENT = "intent";;
|
||||
public static final String EXTRA_SOURCE = "source";
|
||||
|
||||
private final Launcher mLauncher;
|
||||
private final String mLaunchBroadcastPermission;
|
||||
|
||||
private long mElapsedContainerMillis;
|
||||
private long mElapsedSessionMillis;
|
||||
private long mActionDurationMillis;
|
||||
|
||||
// Used for filling in predictedRank on {@link Target}s.
|
||||
private List<ComponentKey> mPredictedApps;
|
||||
|
||||
public final void logAppLaunch(String provider, ShortcutInfo shortcut, Bundle bundle) {
|
||||
if (FeatureFlags.LAUNCHER3_LEGACY_LOGGING) return;
|
||||
public UserEventLogger(Launcher launcher) {
|
||||
mLauncher = launcher;
|
||||
mLaunchBroadcastPermission =
|
||||
launcher.getResources().getString(R.string.receive_launch_broadcasts_permission);
|
||||
|
||||
LauncherLogProto.LauncherEvent event = new LauncherLogProto.LauncherEvent();
|
||||
event.action = new LauncherLogProto.Action();
|
||||
event.action.type = LauncherLogProto.Action.TOUCH;
|
||||
event.action.touch = LauncherLogProto.Action.TAP;
|
||||
|
||||
event.srcTarget = new LauncherLogProto.Target();
|
||||
event.srcTarget.type = LauncherLogProto.Target.ITEM;
|
||||
event.srcTarget.itemType = LauncherLogProto.APP_ICON;
|
||||
// TODO: package hash name should be different per device.
|
||||
event.srcTarget.packageNameHash = provider.hashCode();
|
||||
|
||||
event.srcTarget.parent = new LauncherLogProto.Target();
|
||||
String subContainer = bundle.getString(Stats.SOURCE_EXTRA_SUB_CONTAINER);
|
||||
|
||||
if (shortcut != null) {
|
||||
event.srcTarget.parent.containerType = LoggerUtils.getContainerType(shortcut);
|
||||
event.srcTarget.pageIndex = (int) shortcut.screenId;
|
||||
event.srcTarget.gridX = shortcut.cellX;
|
||||
event.srcTarget.gridX = shortcut.cellY;
|
||||
if (DEBUG_BROADCASTS) {
|
||||
launcher.registerReceiver(
|
||||
new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.v(TAG, "got broadcast: " + intent + " for launched intent: "
|
||||
+ intent.getStringExtra(EXTRA_INTENT));
|
||||
}
|
||||
},
|
||||
new IntentFilter(ACTION_LAUNCH),
|
||||
mLaunchBroadcastPermission,
|
||||
null
|
||||
);
|
||||
}
|
||||
if (subContainer != null) {
|
||||
event.srcTarget.parent.type = LauncherLogProto.Target.CONTAINER;
|
||||
if (subContainer.equals(Stats.SUB_CONTAINER_FOLDER)) {
|
||||
event.srcTarget.parent.containerType = LauncherLogProto.FOLDER;
|
||||
} else if (subContainer.equals(Stats.SUB_CONTAINER_ALL_APPS_A_Z)) {
|
||||
event.srcTarget.parent.containerType = LauncherLogProto.ALLAPPS;
|
||||
} else if (subContainer.equals(Stats.CONTAINER_HOTSEAT)) {
|
||||
event.srcTarget.parent.containerType = LauncherLogProto.HOTSEAT;
|
||||
} else if (subContainer.equals(Stats.SUB_CONTAINER_ALL_APPS_PREDICTION)) {
|
||||
event.srcTarget.parent.containerType = LauncherLogProto.PREDICTION;
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, String.format("parent bundle: %s %s %s %s",
|
||||
bundle.getString(Stats.SOURCE_EXTRA_CONTAINER),
|
||||
bundle.getString(Stats.SOURCE_EXTRA_CONTAINER_PAGE),
|
||||
bundle.getString(Stats.SOURCE_EXTRA_SUB_CONTAINER),
|
||||
bundle.getString(Stats.SOURCE_EXTRA_SUB_CONTAINER_PAGE)));
|
||||
}
|
||||
// APP_ICON SHORTCUT WIDGET
|
||||
// --------------------------------------------------------------
|
||||
// packageNameHash required optional required
|
||||
// componentNameHash required required
|
||||
// intentHash required
|
||||
// --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Prepare {@link LauncherEvent} and {@link Intent} and then attach the event
|
||||
* to the intent and then broadcast.
|
||||
*/
|
||||
public final void broadcastEvent(LauncherEvent ev, Intent intent) {
|
||||
intent = new Intent(intent);
|
||||
intent.setSourceBounds(null);
|
||||
|
||||
final String flat = intent.toUri(0);
|
||||
Intent broadcastIntent = new Intent(ACTION_LAUNCH).putExtra(EXTRA_INTENT, flat);
|
||||
|
||||
broadcastIntent.putExtra(EXTRA_SOURCE, MessageNano.toByteArray(ev));
|
||||
String[] packages = ((Context)mLauncher).getResources().getStringArray(R.array.launch_broadcast_targets);
|
||||
for(String p: packages) {
|
||||
broadcastIntent.setPackage(p);
|
||||
mLauncher.sendBroadcast(broadcastIntent, mLaunchBroadcastPermission);
|
||||
}
|
||||
}
|
||||
|
||||
public final void logLaunch(View v, Intent intent) {
|
||||
LauncherEvent event = LoggerUtils.initLauncherEvent(
|
||||
Action.TOUCH, Target.ITEM, Target.CONTAINER);
|
||||
event.action.touch = Action.TAP;
|
||||
|
||||
// Fill in grid(x,y), pageIndex of the child and container type of the parent
|
||||
// TODO: make this percolate up the view hierarchy if needed.
|
||||
int idx = 0;
|
||||
LaunchSourceProvider provider = getLaunchProviderRecursive(v);
|
||||
provider.fillInLaunchSourceData(v, (ItemInfo) v.getTag(), event.srcTarget[idx], event.srcTarget[idx + 1]);
|
||||
|
||||
// TODO: Fill in all the hashes and the predictedRank
|
||||
|
||||
// Fill in the duration of time spent navigating in Launcher and the container.
|
||||
event.elapsedContainerMillis = System.currentTimeMillis() - mElapsedContainerMillis;
|
||||
event.elapsedSessionMillis = System.currentTimeMillis() - mElapsedSessionMillis;
|
||||
processEvent(event);
|
||||
|
||||
broadcastEvent(event, intent);
|
||||
}
|
||||
|
||||
public void logTap(View v) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void logLongPress() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void logDragNDrop() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void setPredictedApps(List<ComponentKey> predictedApps) {
|
||||
mPredictedApps = predictedApps;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,25 +184,22 @@ public abstract class UserEventLogger {
|
|||
*/
|
||||
public final void resetElapsedContainerMillis() {
|
||||
mElapsedContainerMillis = System.currentTimeMillis();
|
||||
if(DEBUG) {
|
||||
Log.d(TAG, "resetElapsedContainerMillis " + mElapsedContainerMillis);
|
||||
}
|
||||
}
|
||||
|
||||
public final void resetElapsedSessionMillis() {
|
||||
mElapsedSessionMillis = System.currentTimeMillis();
|
||||
mElapsedContainerMillis = System.currentTimeMillis();
|
||||
if(DEBUG) {
|
||||
Log.d(TAG, "resetElapsedSessionMillis " + mElapsedSessionMillis);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final void resetActionDurationMillis() {
|
||||
mActionDurationMillis = System.currentTimeMillis();
|
||||
if(DEBUG) {
|
||||
Log.d(TAG, "resetElapsedContainerMillis " + mElapsedContainerMillis);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void processEvent(LauncherLogProto.LauncherEvent ev);
|
||||
}
|
||||
|
||||
public int getPredictedRank(ComponentKey key) {
|
||||
if (mPredictedApps == null) return -1;
|
||||
return mPredictedApps.indexOf(key);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.android.launcher3.testing;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Rect;
|
||||
|
@ -12,9 +11,8 @@ import android.widget.FrameLayout;
|
|||
import com.android.launcher3.AppInfo;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherCallbacks;
|
||||
import com.android.launcher3.compat.UserHandleCompat;
|
||||
import com.android.launcher3.logging.UserEventLogger;
|
||||
import com.android.launcher3.allapps.AllAppsSearchBarController;
|
||||
import com.android.launcher3.logging.UserEventLogger;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
|
|
Loading…
Reference in New Issue