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:
Hyunyoung Song
2016-04-12 18:32:04 -07:00
parent 30a716157b
commit ddec1c739e
13 changed files with 292 additions and 310 deletions
+45 -38
View File
@@ -32,59 +32,66 @@ message Target {
// For container type and item type // For container type and item type
// Used mainly for ContainerType.FOLDER, ItemType.* // Used mainly for ContainerType.FOLDER, ItemType.*
optional Target parent = 2; optional int32 page_index = 2;
optional int32 page_index = 3; optional int32 rank = 3;
optional int32 rank = 4; optional int32 grid_x = 4;
optional int32 grid_x = 5; optional int32 grid_y = 5;
optional int32 grid_y = 6;
// For container types only // For container types only
optional ContainerType container_type = 7; optional ContainerType container_type = 6;
optional int32 cardinality = 8; optional int32 cardinality = 7;
// For control types only // For control types only
optional ControlType control_type = 9; optional ControlType control_type = 8;
// For item types only // For item types only
optional ItemType item_type = 10; optional ItemType item_type = 9;
optional int32 package_name_hash = 11; optional int32 package_name_hash = 10;
optional int32 component_hash = 12; // Used for ItemType.WIDGET optional int32 component_hash = 11; // Used for ItemType.WIDGET
optional int32 intent_hash = 13; // Used for ItemType.SHORTCUT optional int32 intent_hash = 12; // Used for ItemType.SHORTCUT
optional int32 span_x = 14 [default = 1];// Used for ItemType.WIDGET optional int32 span_x = 13 [default = 1];// Used for ItemType.WIDGET
optional int32 span_y = 15 [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 { enum ItemType {
APP_ICON = 0; DEFAULT_ITEMTYPE = 0;
SHORTCUT = 1; APP_ICON = 1;
WIDGET = 2; SHORTCUT = 2;
FOLDER_ICON = 3; WIDGET = 3;
FOLDER_ICON = 4;
} }
// Used to define what type of container a Target would represent.
enum ContainerType { enum ContainerType {
WORKSPACE = 0; DEFAULT_CONTAINERTYPE = 0;
HOTSEAT = 1; WORKSPACE = 1;
FOLDER = 2; HOTSEAT = 2;
ALLAPPS = 3; FOLDER = 3;
WIDGETS = 4; ALLAPPS = 4;
OVERVIEW = 5; WIDGETS = 5;
PREDICTION = 6; OVERVIEW = 6;
SEARCHRESULT = 7; PREDICTION = 7;
SEARCHRESULT = 8;
} }
// Used to define what type of control a Target would represent.
enum ControlType { enum ControlType {
ALL_APPS_BUTTON = 0; DEFAULT_CONTROLTYPE = 0;
WIDGETS_BUTTON = 1; ALL_APPS_BUTTON = 1;
WALLPAPER_BUTTON = 2; WIDGETS_BUTTON = 2;
SETTINGS_BUTTON = 3; WALLPAPER_BUTTON = 3;
REMOVE_TARGET = 4; SETTINGS_BUTTON = 4;
UNINSTALL_TARGET = 5; REMOVE_TARGET = 5;
APPINFO_TARGET = 6; UNINSTALL_TARGET = 6;
RESIZE_HANDLE = 7; APPINFO_TARGET = 7;
FAST_SCROLL_HANDLE = 8; RESIZE_HANDLE = 8;
VERTICAL_SCROLL = 9;
// HOME, BACK, GO_TO_PLAYSTORE // HOME, BACK, GO_TO_PLAYSTORE
} }
// Used to define the action component of the LauncherEvent.
message Action { message Action {
enum Type { enum Type {
TOUCH = 0; TOUCH = 0;
@@ -113,10 +120,10 @@ message LauncherEvent {
required Action action = 1; required Action action = 1;
// List of targets that touch actions can be operated on. // List of targets that touch actions can be operated on.
optional Target src_target = 2; repeated Target src_target = 2;
optional Target dest_target = 3; repeated Target dest_target = 3;
optional int64 action_duration_millis = 4; optional int64 action_duration_millis = 4;
optional int64 elapsed_container_millis = 5; optional int64 elapsed_container_millis = 5;
optional int64 elapsed_session_millis = 6; optional int64 elapsed_session_millis = 6;
} }
+4
View File
@@ -68,6 +68,10 @@
filter the activities shown in the launcher. Can be empty. --> filter the activities shown in the launcher. Can be empty. -->
<string name="app_filter_class" translatable="false"></string> <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. --> <!-- Name of an icon provider class. -->
<string name="icon_provider_class" translatable="false"></string> <string name="icon_provider_class" translatable="false"></string>
+10 -4
View File
@@ -19,7 +19,6 @@ package com.android.launcher3;
import android.content.Context; import android.content.Context;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
@@ -28,8 +27,12 @@ import android.view.ViewDebug;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.TextView; 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 public class Hotseat extends FrameLayout
implements Stats.LaunchSourceProvider{ implements UserEventLogger.LaunchSourceProvider{
private CellLayout mContent; private CellLayout mContent;
@@ -157,7 +160,10 @@ public class Hotseat extends FrameLayout
} }
@Override @Override
public void fillInLaunchSourceData(View v, Bundle sourceData) { public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_HOTSEAT); target.itemType = LauncherLogProto.APP_ICON;
target.gridX = info.cellX;
target.gridY = info.cellY;
targetParent.containerType = LauncherLogProto.HOTSEAT;
} }
} }
+14 -15
View File
@@ -148,6 +148,7 @@ public class Launcher extends Activity
static final boolean DEBUG_WIDGETS = false; static final boolean DEBUG_WIDGETS = false;
static final boolean DEBUG_STRICT_MODE = false; static final boolean DEBUG_STRICT_MODE = false;
static final boolean DEBUG_RESUME_TIME = 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 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; protected static final int REQUEST_LAST = 100;
// To turn on these properties, type // 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"; static final String DUMP_STATE_PROPERTY = "launcher_dump_state";
// The Intent extra that defines whether to ignore the launch animation // The Intent extra that defines whether to ignore the launch animation
@@ -365,7 +366,6 @@ public class Launcher extends Activity
int appWidgetId; int appWidgetId;
} }
private Stats mStats;
private UserEventLogger mUserEventLogger; private UserEventLogger mUserEventLogger;
public FocusIndicatorView mFocusHandler; public FocusIndicatorView mFocusHandler;
@@ -425,7 +425,6 @@ public class Launcher extends Activity
mDragController = new DragController(this); mDragController = new DragController(this);
mStateTransitionAnimation = new LauncherStateTransitionAnimation(this); mStateTransitionAnimation = new LauncherStateTransitionAnimation(this);
mStats = new Stats(this);
initLogger(); initLogger();
mAppWidgetManager = AppWidgetManagerCompat.getInstance(this); 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. * 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 * 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(); mUserEventLogger = mLauncherCallbacks.getLogger();
} }
if (mUserEventLogger == null) { if (mUserEventLogger == null) {
mUserEventLogger = new UserEventLogger() { mUserEventLogger = new UserEventLogger(this) {
@Override @Override
public void processEvent(LauncherLogProto.LauncherEvent ev) { public void processEvent(LauncherLogProto.LauncherEvent ev) {
if (ev.action.touch == LauncherLogProto.Action.TAP && ev.srcTarget.itemType == LauncherLogProto.APP_ICON) { if (!DEBUG_LOGGING) {
Log.d(TAG, String.format(Locale.US, "action:%s target:%s\n\telapsed container %d ms session %d ms", return;
LoggerUtils.getActionStr(ev.action),
LoggerUtils.getTargetStr(ev.srcTarget),
ev.elapsedContainerMillis,
ev.elapsedSessionMillis));
} }
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); boolean success = startActivitySafely(v, intent, tag);
mStats.recordLaunch(v, intent, shortcut); mUserEventLogger.logLaunch(v, intent);
if (success && v instanceof BubbleTextView) { if (success && v instanceof BubbleTextView) {
mWaitingForResume = (BubbleTextView) v; mWaitingForResume = (BubbleTextView) v;
@@ -3488,6 +3486,7 @@ public class Launcher extends Activity
List<ComponentKey> apps = mLauncherCallbacks.getPredictedApps(); List<ComponentKey> apps = mLauncherCallbacks.getPredictedApps();
if (apps != null) { if (apps != null) {
mAppsView.setPredictedApps(apps); mAppsView.setPredictedApps(apps);
mUserEventLogger.setPredictedApps(apps);
} }
} }
} }
@@ -1,12 +1,11 @@
package com.android.launcher3; package com.android.launcher3;
import android.content.ComponentName;
import android.content.Intent; import android.content.Intent;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Bundle; import android.os.Bundle;
import android.view.Menu; import android.view.Menu;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import com.android.launcher3.allapps.AllAppsSearchBarController; import com.android.launcher3.allapps.AllAppsSearchBarController;
import com.android.launcher3.logging.UserEventLogger; import com.android.launcher3.logging.UserEventLogger;
import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.ComponentKey;
+2 -2
View File
@@ -39,8 +39,8 @@ public class LauncherFiles {
// TODO: Delete these files on upgrade // TODO: Delete these files on upgrade
public static final List<String> OBSOLETE_FILES = Collections.unmodifiableList(Arrays.asList( public static final List<String> OBSOLETE_FILES = Collections.unmodifiableList(Arrays.asList(
"launches.log", "launches.logTap",
"stats.log", "stats.logTap",
"launcher.preferences", "launcher.preferences",
"com.android.launcher3.compat.PackageInstallerCompatV16.queue")); "com.android.launcher3.compat.PackageInstallerCompatV16.queue"));
} }
-152
View File
@@ -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);
}
}
}
+10 -5
View File
@@ -39,7 +39,6 @@ import android.graphics.Rect;
import android.graphics.Region.Op; import android.graphics.Region.Op;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Parcelable; import android.os.Parcelable;
@@ -73,6 +72,9 @@ import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.dragndrop.SpringLoadedDragController; import com.android.launcher3.dragndrop.SpringLoadedDragController;
import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon; 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.LongArrayMap;
import com.android.launcher3.util.Thunk; import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.WallpaperOffsetInterpolator; import com.android.launcher3.util.WallpaperOffsetInterpolator;
@@ -92,7 +94,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public class Workspace extends PagedView public class Workspace extends PagedView
implements DropTarget, DragSource, DragScroller, View.OnTouchListener, implements DropTarget, DragSource, DragScroller, View.OnTouchListener,
DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener, DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener,
Insettable, DropTargetSource, AccessibilityDragSource, Stats.LaunchSourceProvider { Insettable, DropTargetSource, AccessibilityDragSource, UserEventLogger.LaunchSourceProvider {
private static final String TAG = "Launcher.Workspace"; private static final String TAG = "Launcher.Workspace";
private static boolean ENFORCE_DRAG_EVENT_ORDER = false; private static boolean ENFORCE_DRAG_EVENT_ORDER = false;
@@ -4264,9 +4266,12 @@ public class Workspace extends PagedView
} }
@Override @Override
public void fillInLaunchSourceData(View v, Bundle sourceData) { public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_HOMESCREEN); target.itemType = LauncherLogProto.APP_ICON;
sourceData.putInt(Stats.SOURCE_EXTRA_CONTAINER_PAGE, getCurrentPage()); 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.content.res.Resources;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
@@ -27,17 +26,19 @@ import android.view.View;
import com.android.launcher3.BaseRecyclerView; import com.android.launcher3.BaseRecyclerView;
import com.android.launcher3.BubbleTextView; import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.Stats;
import com.android.launcher3.Utilities; 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; import java.util.List;
/** /**
* A RecyclerView with custom fast scroll support for the all apps view. * A RecyclerView with custom fast scroll support for the all apps view.
*/ */
public class AllAppsRecyclerView extends BaseRecyclerView public class AllAppsRecyclerView extends BaseRecyclerView
implements Stats.LaunchSourceProvider { implements LaunchSourceProvider {
private AlphabeticalAppsList mApps; private AlphabeticalAppsList mApps;
private AllAppsFastScrollHelper mFastScrollHelper; private AllAppsFastScrollHelper mFastScrollHelper;
@@ -165,11 +166,9 @@ public class AllAppsRecyclerView extends BaseRecyclerView
} }
@Override @Override
public void fillInLaunchSourceData(View v, Bundle sourceData) { public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_ALL_APPS);
if (mApps.hasFilter()) { if (mApps.hasFilter()) {
sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER, targetParent.containerType = LauncherLogProto.SEARCHRESULT;
Stats.SUB_CONTAINER_ALL_APPS_SEARCH);
} else { } else {
if (v instanceof BubbleTextView) { if (v instanceof BubbleTextView) {
BubbleTextView icon = (BubbleTextView) v; BubbleTextView icon = (BubbleTextView) v;
@@ -178,14 +177,13 @@ public class AllAppsRecyclerView extends BaseRecyclerView
List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems(); List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
AlphabeticalAppsList.AdapterItem item = items.get(position); AlphabeticalAppsList.AdapterItem item = items.get(position);
if (item.viewType == AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) { if (item.viewType == AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) {
sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER, targetParent.containerType = LauncherLogProto.PREDICTION;
Stats.SUB_CONTAINER_ALL_APPS_PREDICTION);
return; return;
} }
} }
} }
sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER,
Stats.SUB_CONTAINER_ALL_APPS_A_Z); targetParent.containerType = LauncherLogProto.ALLAPPS;
} }
} }
+10 -8
View File
@@ -29,7 +29,6 @@ import android.graphics.Point;
import android.graphics.PointF; import android.graphics.PointF;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Build; import android.os.Build;
import android.os.Bundle;
import android.text.InputType; import android.text.InputType;
import android.text.Selection; import android.text.Selection;
import android.text.Spannable; import android.text.Spannable;
@@ -70,7 +69,6 @@ import com.android.launcher3.LogDecelerateInterpolator;
import com.android.launcher3.OnAlarmListener; import com.android.launcher3.OnAlarmListener;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.ShortcutInfo; import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.Stats;
import com.android.launcher3.UninstallDropTarget.DropTargetSource; import com.android.launcher3.UninstallDropTarget.DropTargetSource;
import com.android.launcher3.Utilities; import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace.ItemOperator; 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;
import com.android.launcher3.dragndrop.DragController.DragListener; import com.android.launcher3.dragndrop.DragController.DragListener;
import com.android.launcher3.dragndrop.DragLayer; 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.Thunk;
import com.android.launcher3.util.UiThreadCircularReveal; import com.android.launcher3.util.UiThreadCircularReveal;
@@ -92,7 +93,7 @@ import java.util.Comparator;
public class Folder extends LinearLayout implements DragSource, View.OnClickListener, public class Folder extends LinearLayout implements DragSource, View.OnClickListener,
View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener, View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener,
View.OnFocusChangeListener, DragListener, DropTargetSource, AccessibilityDragSource, View.OnFocusChangeListener, DragListener, DropTargetSource, AccessibilityDragSource,
Stats.LaunchSourceProvider { LaunchSourceProvider {
private static final String TAG = "Launcher.Folder"; private static final String TAG = "Launcher.Folder";
/** /**
@@ -1416,11 +1417,12 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
} }
@Override @Override
public void fillInLaunchSourceData(View v, Bundle sourceData) { public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
// Fill in from the folder icon's launch source provider first target.itemType = LauncherLogProto.APP_ICON;
Stats.LaunchSourceUtils.populateSourceDataFromAncestorProvider(mFolderIcon, sourceData); target.gridX = info.cellX;
sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER, Stats.SUB_CONTAINER_FOLDER); target.gridY = info.cellY;
sourceData.putInt(Stats.SOURCE_EXTRA_SUB_CONTAINER_PAGE, mContent.getCurrentPage()); target.pageIndex = mContent.getCurrentPage();
targetParent.containerType = LauncherLogProto.FOLDER;
} }
private class OnScrollHintListener implements OnAlarmListener { private class OnScrollHintListener implements OnAlarmListener {
@@ -5,7 +5,6 @@ import android.util.Log;
import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings;
import com.android.launcher3.ShortcutInfo; import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.Stats;
import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
@@ -18,16 +17,6 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
*/ */
public class LoggerUtils { public class LoggerUtils {
private static final String TAG = "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) { public static String getActionStr(LauncherLogProto.Action action) {
switch(action.touch) { switch(action.touch) {
@@ -62,8 +51,10 @@ public class LoggerUtils {
default: typeStr = "UNKNOWN"; default: typeStr = "UNKNOWN";
} }
return typeStr + " " + t.packageNameHash + " grid=(" + t.gridX + "," + t.gridY + ") " return typeStr + ", packageHash=" + t.packageNameHash
+ getContainerStr(t.parent); + ", componentHash=" + t.componentHash
+ ", intentHash=" + t.intentHash
+ ", grid=(" + t.gridX + "," + t.gridY + "), id=" + t.pageIndex;
} }
private static String getControlStr(Target t) { private static String getControlStr(Target t) {
@@ -76,7 +67,6 @@ public class LoggerUtils {
case LauncherLogProto.UNINSTALL_TARGET: return "UNINSTALL_TARGET"; case LauncherLogProto.UNINSTALL_TARGET: return "UNINSTALL_TARGET";
case LauncherLogProto.APPINFO_TARGET: return "APPINFO_TARGET"; case LauncherLogProto.APPINFO_TARGET: return "APPINFO_TARGET";
case LauncherLogProto.RESIZE_HANDLE: return "RESIZE_HANDLE"; case LauncherLogProto.RESIZE_HANDLE: return "RESIZE_HANDLE";
case LauncherLogProto.FAST_SCROLL_HANDLE: return "FAST_SCROLL_HANDLE";
default: return "UNKNOWN"; default: return "UNKNOWN";
} }
} }
@@ -114,4 +104,22 @@ public class LoggerUtils {
} }
return str + " id=" + t.pageIndex; 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; 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.util.Log;
import android.view.View;
import android.view.ViewParent;
import com.android.launcher3.ShortcutInfo; import com.android.launcher3.ItemInfo;
import com.android.launcher3.Stats; import com.android.launcher3.Launcher;
import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.R;
import com.android.launcher3.userevent.nano.LauncherLogProto; 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 { 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 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 mElapsedContainerMillis;
private long mElapsedSessionMillis; private long mElapsedSessionMillis;
private long mActionDurationMillis; 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) { public UserEventLogger(Launcher launcher) {
if (FeatureFlags.LAUNCHER3_LEGACY_LOGGING) return; mLauncher = launcher;
mLaunchBroadcastPermission =
launcher.getResources().getString(R.string.receive_launch_broadcasts_permission);
LauncherLogProto.LauncherEvent event = new LauncherLogProto.LauncherEvent(); if (DEBUG_BROADCASTS) {
event.action = new LauncherLogProto.Action(); launcher.registerReceiver(
event.action.type = LauncherLogProto.Action.TOUCH; new BroadcastReceiver() {
event.action.touch = LauncherLogProto.Action.TAP; @Override
public void onReceive(Context context, Intent intent) {
event.srcTarget = new LauncherLogProto.Target(); Log.v(TAG, "got broadcast: " + intent + " for launched intent: "
event.srcTarget.type = LauncherLogProto.Target.ITEM; + intent.getStringExtra(EXTRA_INTENT));
event.srcTarget.itemType = LauncherLogProto.APP_ICON; }
// TODO: package hash name should be different per device. },
event.srcTarget.packageNameHash = provider.hashCode(); new IntentFilter(ACTION_LAUNCH),
mLaunchBroadcastPermission,
event.srcTarget.parent = new LauncherLogProto.Target(); null
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 (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) { // APP_ICON SHORTCUT WIDGET
Log.d(TAG, String.format("parent bundle: %s %s %s %s", // --------------------------------------------------------------
bundle.getString(Stats.SOURCE_EXTRA_CONTAINER), // packageNameHash required optional required
bundle.getString(Stats.SOURCE_EXTRA_CONTAINER_PAGE), // componentNameHash required required
bundle.getString(Stats.SOURCE_EXTRA_SUB_CONTAINER), // intentHash required
bundle.getString(Stats.SOURCE_EXTRA_SUB_CONTAINER_PAGE))); // --------------------------------------------------------------
}
/**
* 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.elapsedContainerMillis = System.currentTimeMillis() - mElapsedContainerMillis;
event.elapsedSessionMillis = System.currentTimeMillis() - mElapsedSessionMillis; event.elapsedSessionMillis = System.currentTimeMillis() - mElapsedSessionMillis;
processEvent(event); 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() { public final void resetElapsedContainerMillis() {
mElapsedContainerMillis = System.currentTimeMillis(); mElapsedContainerMillis = System.currentTimeMillis();
if(DEBUG) {
Log.d(TAG, "resetElapsedContainerMillis " + mElapsedContainerMillis);
}
} }
public final void resetElapsedSessionMillis() { public final void resetElapsedSessionMillis() {
mElapsedSessionMillis = System.currentTimeMillis(); mElapsedSessionMillis = System.currentTimeMillis();
mElapsedContainerMillis = System.currentTimeMillis(); mElapsedContainerMillis = System.currentTimeMillis();
if(DEBUG) {
Log.d(TAG, "resetElapsedSessionMillis " + mElapsedSessionMillis);
}
} }
public final void resetActionDurationMillis() { public final void resetActionDurationMillis() {
mActionDurationMillis = System.currentTimeMillis(); mActionDurationMillis = System.currentTimeMillis();
if(DEBUG) {
Log.d(TAG, "resetElapsedContainerMillis " + mElapsedContainerMillis);
}
} }
public abstract void processEvent(LauncherLogProto.LauncherEvent ev); 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; package com.android.launcher3.testing;
import android.content.ComponentName;
import android.content.Intent; import android.content.Intent;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Rect; import android.graphics.Rect;
@@ -12,9 +11,8 @@ import android.widget.FrameLayout;
import com.android.launcher3.AppInfo; import com.android.launcher3.AppInfo;
import com.android.launcher3.Launcher; import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherCallbacks; 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.allapps.AllAppsSearchBarController;
import com.android.launcher3.logging.UserEventLogger;
import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.ComponentKey;
import java.io.FileDescriptor; import java.io.FileDescriptor;