diff options
33 files changed, 435 insertions, 44 deletions
diff --git a/core/java/android/metrics/LogMaker.java b/core/java/android/metrics/LogMaker.java index 60b27b47960f..04482210c088 100644 --- a/core/java/android/metrics/LogMaker.java +++ b/core/java/android/metrics/LogMaker.java @@ -16,6 +16,7 @@ package android.metrics; import android.annotation.SystemApi; +import android.content.ComponentName; import android.util.Log; import android.util.SparseArray; @@ -118,6 +119,16 @@ public class LogMaker { return this; } + /** + * @param component to replace the existing setting. + * @hide + */ + public LogMaker setComponentName(ComponentName component) { + entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_PACKAGENAME, component.getPackageName()); + entries.put(MetricsEvent.FIELD_CLASS_NAME, component.getClassName()); + return this; + } + /** Remove the package name property. */ public LogMaker clearPackageName() { entries.remove(MetricsEvent.RESERVED_FOR_LOGBUILDER_PACKAGENAME); diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index d058e7837423..79190cbb129f 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -24,6 +24,7 @@ import android.util.ArrayMap; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.NightDisplayController; +import com.android.internal.logging.MetricsLogger; import com.android.internal.util.Preconditions; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.systemui.assist.AssistManager; @@ -257,6 +258,8 @@ public class Dependency extends SystemUI { mProviders.put(VolumeDialogController.class, () -> new VolumeDialogControllerImpl(mContext)); + mProviders.put(MetricsLogger.class, () -> new MetricsLogger()); + // Put all dependencies above here so the factory can override them if it wants. SystemUIFactory.getInstance().injectDependencies(mProviders, mContext); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java index 1709718b1301..9efe224ff52f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java @@ -14,6 +14,8 @@ package com.android.systemui.qs; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_MORE_SETTINGS; + import android.animation.Animator; import android.animation.Animator.AnimatorListener; import android.animation.AnimatorListenerAdapter; @@ -197,7 +199,7 @@ public class QSDetail extends LinearLayout { mDetailContent.removeAllViews(); mDetailContent.addView(detailView); mDetailViews.put(viewCacheIndex, detailView); - MetricsLogger.visible(mContext, adapter.getMetricsCategory()); + Dependency.get(MetricsLogger.class).visible(adapter.getMetricsCategory()); announceForAccessibility(mContext.getString( R.string.accessibility_quick_settings_detail, adapter.getTitle())); @@ -206,7 +208,7 @@ public class QSDetail extends LinearLayout { setVisibility(View.VISIBLE); } else { if (mDetailAdapter != null) { - MetricsLogger.hidden(mContext, mDetailAdapter.getMetricsCategory()); + Dependency.get(MetricsLogger.class).hidden(mDetailAdapter.getMetricsCategory()); } mClosingDetail = true; mDetailAdapter = null; @@ -238,8 +240,12 @@ public class QSDetail extends LinearLayout { protected void setupDetailFooter(DetailAdapter adapter) { final Intent settingsIntent = adapter.getSettingsIntent(); mDetailSettingsButton.setVisibility(settingsIntent != null ? VISIBLE : GONE); - mDetailSettingsButton.setOnClickListener(v -> Dependency.get(ActivityStarter.class) - .postStartActivityDismissingKeyguard(settingsIntent, 0)); + mDetailSettingsButton.setOnClickListener(v -> { + Dependency.get(MetricsLogger.class).action(ACTION_QS_MORE_SETTINGS, + mDetailAdapter.getMetricsCategory()); + Dependency.get(ActivityStarter.class) + .postStartActivityDismissingKeyguard(settingsIntent, 0); + }); } protected void setupDetailHeader(final DetailAdapter adapter) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java index 2202b5865def..a84138d85a8b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java @@ -16,6 +16,8 @@ package com.android.systemui.qs; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_DATE; + import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Context; @@ -358,6 +360,8 @@ public class QSFooter extends LinearLayout implements startSettingsActivity(); } } else if (v == mDateTimeGroup) { + Dependency.get(MetricsLogger.class).action(ACTION_QS_DATE, + mNextAlarm != null); if (mNextAlarm != null) { PendingIntent showIntent = mNextAlarm.getShowIntent(); mActivityStarter.startPendingIntentDismissingKeyguard(showIntent); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java index 29d547cfd5d2..8596b578f030 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java @@ -32,6 +32,8 @@ public interface QSHost { TileServices getTileServices(); void removeTile(String tileSpec); + int indexOf(String tileSpec); + interface Callback { void onTilesChanged(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 8298cbb7d7fe..2e6116dba7e9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -59,6 +59,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback { protected final View mBrightnessView; private final H mHandler = new H(); private final View mPageIndicator; + private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); private int mPanelPaddingBottom; private int mBrightnessPaddingTop; @@ -259,7 +260,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback { if (!mExpanded && mTileLayout instanceof PagedTileLayout) { ((PagedTileLayout) mTileLayout).setCurrentItem(0, false); } - MetricsLogger.visibility(mContext, MetricsEvent.QS_PANEL, mExpanded); + mMetricsLogger.visibility(MetricsEvent.QS_PANEL, mExpanded); if (!mExpanded) { closeDetail(); } else { @@ -475,7 +476,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback { int newVis = visible ? VISIBLE : INVISIBLE; setVisibility(newVis); if (mGridContentVisible != visible) { - MetricsLogger.visibility(mContext, MetricsEvent.QS_PANEL, newVis); + mMetricsLogger.visibility(MetricsEvent.QS_PANEL, newVis); } mGridContentVisible = visible; } @@ -483,7 +484,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback { private void logTiles() { for (int i = 0; i < mRecords.size(); i++) { TileRecord tileRecord = mRecords.get(i); - MetricsLogger.visible(mContext, tileRecord.tile.getMetricsCategory()); + mMetricsLogger.visible(tileRecord.tile.getMetricsCategory()); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index 0ca115e43c07..933054138a8a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -157,6 +157,10 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory> { return mServices; } + public int indexOf(String spec) { + return mTileSpecs.indexOf(spec); + } + @Override public void onTuningChanged(String key, String newValue) { if (!TILES_SETTING.equals(key)) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java index 6f35017b893b..b5c1bd9ff9db 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java @@ -22,6 +22,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.graphics.drawable.Drawable; +import android.metrics.LogMaker; import android.net.Uri; import android.os.Binder; import android.os.IBinder; @@ -155,6 +156,11 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener return mComponent; } + @Override + protected LogMaker populate(LogMaker logMaker) { + return super.populate(logMaker).setComponentName(mComponent); + } + public Tile getQsTile() { return mTile; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java index 948954c2bd99..1aa51b1c38bf 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java @@ -14,12 +14,19 @@ package com.android.systemui.qs.tileimpl; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_CLICK; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_LONG_PRESS; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_SECONDARY_CLICK; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_POSITION; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_VALUE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION; import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import android.app.ActivityManager; import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; +import android.metrics.LogMaker; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -29,7 +36,6 @@ import android.util.Log; import android.util.SparseArray; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.Utils; import com.android.systemui.Dependency; @@ -58,6 +64,7 @@ public abstract class QSTileImpl<TState extends State> implements QSTile { protected final H mHandler = new H(Dependency.get(Dependency.BG_LOOPER)); protected final Handler mUiHandler = new Handler(Looper.getMainLooper()); private final ArraySet<Object> mListeners = new ArraySet<>(); + private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); private final ArrayList<Callback> mCallbacks = new ArrayList<>(); protected TState mState = newTileState(); @@ -76,7 +83,7 @@ public abstract class QSTileImpl<TState extends State> implements QSTile { /** * Declare the category of this tile. * - * Categories are defined in {@link com.android.internal.logging.MetricsProto.MetricsEvent} + * Categories are defined in {@link com.android.internal.logging.nano.MetricsProto.MetricsEvent} * by editing frameworks/base/proto/src/metrics_constants.proto. */ abstract public int getMetricsCategory(); @@ -152,17 +159,28 @@ public abstract class QSTileImpl<TState extends State> implements QSTile { } public void click() { + mMetricsLogger.write(populate(new LogMaker(ACTION_QS_CLICK).setType(TYPE_ACTION))); mHandler.sendEmptyMessage(H.CLICK); } public void secondaryClick() { + mMetricsLogger.write(populate(new LogMaker(ACTION_QS_SECONDARY_CLICK).setType(TYPE_ACTION))); mHandler.sendEmptyMessage(H.SECONDARY_CLICK); } public void longClick() { + mMetricsLogger.write(populate(new LogMaker(ACTION_QS_LONG_PRESS).setType(TYPE_ACTION))); mHandler.sendEmptyMessage(H.LONG_CLICK); } + protected LogMaker populate(LogMaker logMaker) { + if (mState instanceof BooleanState) { + logMaker.addTaggedData(FIELD_QS_VALUE, ((BooleanState) mState).value ? 1 : 0); + } + return logMaker.setSubtype(getMetricsCategory()) + .addTaggedData(FIELD_QS_POSITION, mHost.indexOf(mTileSpec)); + } + public void showDetail(boolean show) { mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0).sendToTarget(); } @@ -224,7 +242,6 @@ public abstract class QSTileImpl<TState extends State> implements QSTile { } protected void handleLongClick() { - MetricsLogger.action(mContext, MetricsEvent.ACTION_QS_LONG_PRESS, getTileSpec()); Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard( getLongClickIntent(), 0); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index ed6e6ef439b5..4e4de15567d4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -83,7 +83,6 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { protected void handleClick() { // Secondary clicks are header clicks, just toggle. final boolean isEnabled = (Boolean)mState.value; - MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled); mController.setBluetoothEnabled(!isEnabled); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java index a1d3d261c4d8..22b6a634cb9a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -108,13 +108,11 @@ public class CastTile extends QSTileImpl<BooleanState> { protected void handleClick() { if (mKeyguard.isSecure() && !mKeyguard.canSkipBouncer()) { mActivityStarter.postQSRunnableDismissingKeyguard(() -> { - MetricsLogger.action(mContext, getMetricsCategory()); showDetail(true); mHost.openPanels(); }); return; } - MetricsLogger.action(mContext, getMetricsCategory()); showDetail(true); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index 4351b2ca6dc0..04be7de644e3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -98,7 +98,6 @@ public class CellularTile extends QSTileImpl<SignalState> { @Override protected void handleSecondaryClick() { - MetricsLogger.action(mContext, getMetricsCategory()); if (mDataController.isMobileDataSupported()) { showDetail(true); } else { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java index e33b6808d7dd..5b374b1bc286 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java @@ -84,7 +84,6 @@ public class ColorInversionTile extends QSTileImpl<BooleanState> { @Override protected void handleClick() { - MetricsLogger.action(mContext, getMetricsCategory(), !mState.value); mSetting.setValue(mState.value ? 0 : 1); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java index 7a25140c2fa0..b7964512a2fa 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java @@ -87,7 +87,6 @@ public class DataSaverTile extends QSTileImpl<BooleanState> implements private void toggleDataSaver() { mState.value = !mDataSaverController.isDataSaverEnabled(); - MetricsLogger.action(mContext, getMetricsCategory(), mState.value); mDataSaverController.setDataSaverEnabled(mState.value); refreshState(mState.value); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java index f35de68a837d..3c2e8973cd6e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java @@ -146,7 +146,6 @@ public class DndTile extends QSTileImpl<BooleanState> { Toast.LENGTH_LONG).show(); return; } - MetricsLogger.action(mContext, getMetricsCategory(), !mState.value); showDetail(true); int zen = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN, Global.ZEN_MODE_ALARMS); mController.setZen(zen, null, TAG); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java index 7b0fd73446aa..6d2aa9065cff 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java @@ -87,7 +87,6 @@ public class FlashlightTile extends QSTileImpl<BooleanState> implements if (ActivityManager.isUserAMonkey()) { return; } - MetricsLogger.action(mContext, getMetricsCategory(), !mState.value); boolean newState = !mState.value; refreshState(newState); mFlashlightController.setFlashlight(newState); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java index 66629371b942..5c3f65c471bf 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -106,7 +106,6 @@ public class HotspotTile extends QSTileImpl<AirplaneBooleanState> { if (!isEnabled && mAirplaneMode.getValue() != 0) { return; } - MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled); mController.setHotspotEnabled(!isEnabled); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java index c9533635d2a5..00cfbfa1eac7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java @@ -92,7 +92,6 @@ public class IntentTile extends QSTileImpl<State> { @Override protected void handleClick() { - MetricsLogger.action(mContext, getMetricsCategory(), mIntentPackage); sendIntent("click", mOnClick, mOnClickUri); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java index b5c02cb81b04..b11b15a73093 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java @@ -81,13 +81,11 @@ public class LocationTile extends QSTileImpl<BooleanState> { Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> { final boolean wasEnabled = mState.value; mHost.openPanels(); - MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled); mController.setLocationEnabled(!wasEnabled); }); return; } final boolean wasEnabled = mState.value; - MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled); mController.setLocationEnabled(!wasEnabled); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java index 32993391e29f..d147b6968856 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java @@ -85,7 +85,6 @@ public class NfcTile extends QSTileImpl<BooleanState> { @Override protected void handleClick() { if (mAdapter == null) return; - MetricsLogger.action(mContext, getMetricsCategory(), !mState.value); if (!mAdapter.isEnabled()) { mAdapter.enable(); } else { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java index 8b47216f17e4..8aa1e43dc106 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java @@ -54,7 +54,6 @@ public class NightDisplayTile extends QSTileImpl<BooleanState> @Override protected void handleClick() { final boolean activated = !mState.value; - MetricsLogger.action(mContext, getMetricsCategory(), activated); mController.setActivated(activated); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java index 130304f8619e..fb937bd09bc2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java @@ -79,7 +79,6 @@ public class RotationLockTile extends QSTileImpl<BooleanState> { @Override protected void handleClick() { if (mController == null) return; - MetricsLogger.action(mContext, getMetricsCategory(), !mState.value); final boolean newState = !mState.value; mController.setRotationLocked(!newState); refreshState(newState); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index fde2e0449c4e..79b4c4a87596 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -114,7 +114,6 @@ public class WifiTile extends QSTileImpl<SignalState> { protected void handleClick() { // Secondary clicks are header clicks, just toggle. mState.copyTo(mStateBeforeClick); - MetricsLogger.action(mContext, getMetricsCategory(), !mState.value); mController.setWifiEnabled(!mState.value); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java index 5086091f7572..6c89241aebfe 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java @@ -68,7 +68,6 @@ public class WorkModeTile extends QSTileImpl<BooleanState> implements @Override public void handleClick() { - MetricsLogger.action(mContext, getMetricsCategory(), !mState.value); mProfileController.setWorkModeEnabled(!mState.value); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java index b5f56c3b8182..4d99a46e2321 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java @@ -22,6 +22,7 @@ import android.util.ArrayMap; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.systemui.Dependency; import com.android.systemui.EventLogConstants; import com.android.systemui.EventLogTags; @@ -33,7 +34,7 @@ public class LockscreenGestureLogger { private ArrayMap<Integer, Integer> mLegacyMap; private LogMaker mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN) .setType(MetricsEvent.TYPE_ACTION); - private MetricsLogger mMetricsLogger = new MetricsLogger(); + private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); public LockscreenGestureLogger() { mLegacyMap = new ArrayMap<>(EventLogConstants.METRICS_GESTURE_TYPE_MAP.length); @@ -58,9 +59,4 @@ public class LockscreenGestureLogger { } return value; } - - @VisibleForTesting - void setMetricsLogger(MetricsLogger metricsLogger) { - mMetricsLogger = metricsLogger; - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index b82b113f3f8d..bfe55bc290e4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -484,7 +484,7 @@ public class StatusBar extends SystemUI implements DemoMode, private ScreenPinningRequest mScreenPinningRequest; - MetricsLogger mMetricsLogger = new MetricsLogger(); + private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); // ensure quick settings is disabled until the current user makes it through the setup wizard private boolean mUserSetup = false; @@ -748,12 +748,6 @@ public class StatusBar extends SystemUI implements DemoMode, private NavigationBarFragment mNavigationBar; private View mNavigationBarView; - @VisibleForTesting - void setMetricsLogger(MetricsLogger metricsLogger) { - mMetricsLogger = metricsLogger; - mLockscreenGestureLogger.setMetricsLogger(metricsLogger); - } - @Override public void start() { mNetworkController = Dependency.get(NetworkController.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java new file mode 100644 index 000000000000..c67cccc06169 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2017 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.systemui.qs; + +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_MORE_SETTINGS; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.testing.TestableLooper.RunWithLooper; +import android.testing.ViewUtils; +import android.view.LayoutInflater; +import android.view.View; + +import com.android.internal.logging.MetricsLogger; +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.qs.DetailAdapter; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +public class QSDetailTest extends SysuiTestCase { + + private MetricsLogger mMetricsLogger; + private QSDetail mQsDetail; + private QSPanel mQsPanel; + private QuickStatusBarHeader mQuickHeader; + private ActivityStarter mActivityStarter; + private DetailAdapter mMockDetailAdapter; + private TestableLooper mTestableLooper; + + @Before + public void setup() throws Exception { + mTestableLooper = TestableLooper.get(this); + mTestableLooper.runWithLooper(() -> { + mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class); + mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class); + mQsDetail = (QSDetail) LayoutInflater.from(mContext).inflate(R.layout.qs_detail, null); + mQsPanel = mock(QSPanel.class); + mQuickHeader = mock(QuickStatusBarHeader.class); + mQsDetail.setQsPanel(mQsPanel, mQuickHeader); + + mMockDetailAdapter = mock(DetailAdapter.class); + when(mMockDetailAdapter.createDetailView(any(), any(), any())) + .thenReturn(mock(View.class)); + }); + } + + @Test + public void testShowDetail_Metrics() { + ViewUtils.attachView(mQsDetail); + mTestableLooper.processAllMessages(); + + mQsDetail.handleShowingDetail(mMockDetailAdapter, 0, 0, false); + verify(mMetricsLogger).visible(eq(mMockDetailAdapter.getMetricsCategory())); + mQsDetail.handleShowingDetail(null, 0, 0, false); + verify(mMetricsLogger).hidden(eq(mMockDetailAdapter.getMetricsCategory())); + + ViewUtils.detachView(mQsDetail); + mTestableLooper.processAllMessages(); + } + + @Test + public void testMoreSettingsButton() { + ViewUtils.attachView(mQsDetail); + mTestableLooper.processAllMessages(); + + mQsDetail.handleShowingDetail(mMockDetailAdapter, 0, 0, false); + mQsDetail.findViewById(android.R.id.button2).performClick(); + + int metricsCategory = mMockDetailAdapter.getMetricsCategory(); + verify(mMetricsLogger).action(eq(ACTION_QS_MORE_SETTINGS), eq(metricsCategory)); + + verify(mActivityStarter).postStartActivityDismissingKeyguard(any(), anyInt()); + + ViewUtils.detachView(mQsDetail); + mTestableLooper.processAllMessages(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java index deb31dae6840..d77ed3d9cd6e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -19,6 +19,7 @@ import static org.mockito.Mockito.mock; import android.os.Looper; +import com.android.internal.logging.MetricsLogger; import com.android.keyguard.CarrierText; import com.android.systemui.Dependency; import com.android.systemui.R; @@ -44,12 +45,15 @@ import android.widget.FrameLayout; @RunWithLooper(setAsMainLooper = true) public class QSFragmentTest extends SysuiBaseFragmentTest { + private MetricsLogger mMockMetricsLogger; + public QSFragmentTest() { super(QSFragment.class); } @Before public void addLeakCheckDependencies() { + mMockMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class); mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, new LayoutInflaterBuilder(mContext) .replace("com.android.systemui.statusbar.policy.SplitClockView", diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java new file mode 100644 index 000000000000..49796843af6e --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2017 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.systemui.qs; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.testing.TestableLooper.RunWithLooper; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.qs.customize.QSCustomizer; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Collections; + +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +public class QSPanelTest extends SysuiTestCase { + + private MetricsLogger mMetricsLogger; + private QSPanel mQsPanel; + private QSTileHost mHost; + private QSCustomizer mCustomizer; + + @Before + public void setup() throws Exception { + TestableLooper.get(this).runWithLooper(() -> { + mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class); + mQsPanel = new QSPanel(mContext, null); + mHost = mock(QSTileHost.class); + when(mHost.getTiles()).thenReturn(Collections.emptyList()); + mCustomizer = mock(QSCustomizer.class); + mQsPanel.setHost(mHost, mCustomizer); + }); + } + + @Test + public void testSetExpanded_Metrics() { + mQsPanel.setExpanded(true); + verify(mMetricsLogger).visibility(eq(MetricsEvent.QS_PANEL), eq(true)); + mQsPanel.setExpanded(false); + verify(mMetricsLogger).visibility(eq(MetricsEvent.QS_PANEL), eq(false)); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java new file mode 100644 index 000000000000..9ed9d28cd96c --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2017 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.systemui.qs.tileimpl; + +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_CLICK; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_LONG_PRESS; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_SECONDARY_CLICK; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_POSITION; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_VALUE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Matchers.argThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Intent; +import android.metrics.LogMaker; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.testing.TestableLooper.RunWithLooper; + +import com.android.internal.logging.MetricsLogger; +import com.android.systemui.Dependency; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.qs.QSTile; +import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QSTileHost; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentMatcher; + +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +public class QSTileImplTest extends SysuiTestCase { + + public static final int POSITION = 14; + private TestableLooper mTestableLooper; + private TileImpl mTile; + private QSTileHost mHost; + private MetricsLogger mMetricsLogger; + + @Before + public void setup() throws Exception { + String spec = "spec"; + mTestableLooper = TestableLooper.get(this); + mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper()); + mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class); + mHost = mock(QSTileHost.class); + when(mHost.indexOf(spec)).thenReturn(POSITION); + mTestableLooper.runWithLooper(() -> { + mTile = new TileImpl(mHost); + mTile.setTileSpec(spec); + }); + } + + @Test + public void testClick_Metrics() { + mTile.click(); + verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_CLICK))); + } + + @Test + public void testSecondaryClick_Metrics() { + mTile.secondaryClick(); + verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_SECONDARY_CLICK))); + } + + @Test + public void testLongClick_Metrics() { + mTile.longClick(); + verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_LONG_PRESS))); + } + + @Test + public void testPopulate() { + LogMaker maker = mock(LogMaker.class); + when(maker.setSubtype(anyInt())).thenReturn(maker); + mTile.getState().value = true; + mTile.populate(maker); + verify(maker).addTaggedData(eq(FIELD_QS_VALUE), eq(1)); + verify(maker).addTaggedData(eq(FIELD_QS_POSITION), eq(POSITION)); + } + + private class TileLogMatcher implements ArgumentMatcher<LogMaker> { + + private final int mCategory; + public String mInvalid; + + public TileLogMatcher(int category) { + mCategory = category; + } + + @Override + public boolean matches(LogMaker arg) { + if (arg.getCategory() != mCategory) { + mInvalid = "Expected category " + mCategory + " but was " + arg.getCategory(); + return false; + } + if (arg.getType() != TYPE_ACTION) { + mInvalid = "Expected type " + TYPE_ACTION + " but was " + arg.getType(); + return false; + } + if (arg.getSubtype() != mTile.getMetricsCategory()) { + mInvalid = "Expected subtype " + mTile.getMetricsCategory() + " but was " + + arg.getSubtype(); + return false; + } + return true; + } + + @Override + public String toString() { + return mInvalid; + } + } + + private static class TileImpl extends QSTileImpl<QSTile.BooleanState> { + protected TileImpl(QSHost host) { + super(host); + } + + @Override + public BooleanState newTileState() { + return new BooleanState(); + } + + @Override + protected void handleClick() { + + } + + @Override + protected void handleUpdateState(BooleanState state, Object arg) { + + } + + @Override + public int getMetricsCategory() { + return 42; + } + + @Override + public Intent getLongClickIntent() { + return null; + } + + @Override + protected void setListening(boolean listening) { + + } + + @Override + public CharSequence getTileLabel() { + return null; + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index f48af7557593..bf6b3946d101 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -62,9 +62,9 @@ public class StatusBarTest extends SysuiTestCase { mKeyguardIndicationController = mock(KeyguardIndicationController.class); mStackScroller = mock(NotificationStackScrollLayout.class); mMetricsLogger = new FakeMetricsLogger(); + mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger); mStatusBar = new TestableStatusBar(mStatusBarKeyguardViewManager, mUnlockMethodCache, mKeyguardIndicationController, mStackScroller); - mStatusBar.setMetricsLogger(mMetricsLogger); doAnswer(invocation -> { OnDismissAction onDismissAction = (OnDismissAction) invocation.getArguments()[0]; diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 783aae7121ad..da441f5eaff3 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -3656,7 +3656,7 @@ message MetricsEvent { ACTION_SETTINGS_MASTER_SWITCH_BLUETOOTH_TOGGLE = 870; // The name of the activity being launched in an app transition event. - APP_TRANSITION_ACTIVITY_NAME = 871; + FIELD_CLASS_NAME = 871; // ACTION: Settings > App detail > Uninstall ACTION_SETTINGS_UNINSTALL_APP = 872; @@ -3874,6 +3874,24 @@ message MetricsEvent { // OPEN: Settings -> System -> Reset options RESET_DASHBOARD = 924; + // ACTION: QS -> Tile clicked + ACTION_QS_CLICK = 925; + + // ACTION: QS -> Secondary click + ACTION_QS_SECONDARY_CLICK = 926; + + // FIELD: Position info in QS clicks + FIELD_QS_POSITION = 927; + + // FIELD: The value of a QS tile when clicked (if applicable) + FIELD_QS_VALUE = 928; + + // ACTION: QS -> Detail panel -> more settings + ACTION_QS_MORE_SETTINGS = 929; + + // ACTION: QS -> Click date + ACTION_QS_DATE = 930; + // ---- End O Constants, all O constants go above this line ---- // Add new aosp constants above this line. diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java index 04a09fe4305e..5edfb0651fe7 100644 --- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java @@ -10,8 +10,8 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.ActivityManagerInternal.APP_TRANSITION_TIMEOUT; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_ACTIVITY_NAME; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CALLING_PACKAGE_NAME; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CLASS_NAME; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DELAY_MS; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_IS_EPHEMERAL; @@ -313,7 +313,7 @@ class ActivityMetricsLogger { final LogMaker builder = new LogMaker(APP_TRANSITION); builder.setPackageName(info.launchedActivity.packageName); builder.setType(type); - builder.addTaggedData(APP_TRANSITION_ACTIVITY_NAME, info.launchedActivity.info.name); + builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivity.info.name); if (info.launchedActivity.launchedFromPackage != null) { builder.addTaggedData(APP_TRANSITION_CALLING_PACKAGE_NAME, info.launchedActivity.launchedFromPackage); |