diff options
36 files changed, 650 insertions, 86 deletions
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java index f6f8f53c07f2..d43aaf07c6be 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/DetailAdapter.java @@ -19,6 +19,7 @@ import android.content.Intent; import android.view.View; import android.view.ViewGroup; +import com.android.internal.logging.UiEventLogger; import com.android.systemui.plugins.annotations.ProvidesInterface; @ProvidesInterface(version = DetailAdapter.VERSION) @@ -44,4 +45,18 @@ public interface DetailAdapter { default boolean hasHeader() { return true; } + + default UiEventLogger.UiEventEnum openDetailEvent() { + return INVALID; + } + + default UiEventLogger.UiEventEnum closeDetailEvent() { + return INVALID; + } + + default UiEventLogger.UiEventEnum moreSettingsEvent() { + return INVALID; + } + + UiEventLogger.UiEventEnum INVALID = () -> 0; } diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java index e586c38a286a..aeedc16ffbd4 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java @@ -20,6 +20,7 @@ import android.graphics.drawable.Drawable; import android.metrics.LogMaker; import android.service.quicksettings.Tile; +import com.android.internal.logging.InstanceId; import com.android.systemui.plugins.annotations.DependsOn; import com.android.systemui.plugins.annotations.ProvidesInterface; import com.android.systemui.plugins.qs.QSTile.Callback; @@ -81,6 +82,18 @@ public interface QSTile { return logMaker; } + /** + * Return a string to be used to identify the tile in UiEvents. + */ + default String getMetricsSpec() { + return getClass().getSimpleName(); + } + + /** + * Return an {@link InstanceId} to be used to identify the tile in UiEvents. + */ + InstanceId getInstanceId(); + @ProvidesInterface(version = Callback.VERSION) public interface Callback { public static final int VERSION = 1; diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java index 3a4b273e1c98..23bcb29923d8 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java @@ -33,6 +33,8 @@ import android.view.LayoutInflater; import android.view.WindowManager; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEventLogger; +import com.android.internal.logging.UiEventLoggerImpl; import com.android.internal.util.NotificationMessagingUtil; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.ViewMediatorCallback; @@ -218,4 +220,11 @@ public class DependencyProvider { public Choreographer providesChoreographer() { return Choreographer.getInstance(); } + + /** Provides an instance of {@link com.android.internal.logging.UiEventLogger} */ + @Singleton + @Provides + static UiEventLogger provideUiEventLogger() { + return new UiEventLoggerImpl(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt index 448531a132df..c5ae3ab2c9fb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt @@ -20,10 +20,14 @@ import android.content.Context import android.content.res.Configuration import android.view.View import android.view.ViewGroup +import com.android.internal.logging.UiEventLogger import com.android.systemui.R import com.android.systemui.qs.TileLayout.exactly -class DoubleLineTileLayout(context: Context) : ViewGroup(context), QSPanel.QSTileLayout { +class DoubleLineTileLayout( + context: Context, + private val uiEventLogger: UiEventLogger +) : ViewGroup(context), QSPanel.QSTileLayout { companion object { private const val NUM_LINES = 2 @@ -86,6 +90,13 @@ class DoubleLineTileLayout(context: Context) : ViewGroup(context), QSPanel.QSTil for (record in mRecords) { record.tile.setListening(this, listening) } + if (listening) { + for (i in 0 until numVisibleTiles) { + val tile = mRecords[i].tile + uiEventLogger.logWithInstanceId( + QSEvent.QQS_TILE_VISIBLE, 0, tile.metricsSpec, tile.instanceId) + } + } } override fun getNumVisibleTiles() = tilesToShow diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java index cd737217b84a..b157f4b3c5ed 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java @@ -22,7 +22,9 @@ import android.widget.Scroller; import androidx.viewpager.widget.PagerAdapter; import androidx.viewpager.widget.ViewPager; +import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; +import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.qs.QSPanel.QSTileLayout; import com.android.systemui.qs.QSPanel.TileRecord; @@ -63,7 +65,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { private int mLayoutDirection; private int mHorizontalClipBound; private final Rect mClippingRect; - private int mLastMaxHeight = -1; + private final UiEventLogger mUiEventLogger = QSEvents.INSTANCE.getQsUiEventsLogger(); public PagedTileLayout(Context context, AttributeSet attrs) { super(context, attrs); @@ -75,6 +77,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { mLayoutDirection = getLayoutDirection(); mClippingRect = new Rect(); } + private int mLastMaxHeight = -1; public void saveInstanceState(Bundle outState) { outState.putInt(CURRENT_PAGE, getCurrentItem()); @@ -126,6 +129,15 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { return page; } + // This will dump to the ui log all the tiles that are visible in this page + private void logVisibleTiles(TilePage page) { + for (int i = 0; i < page.mRecords.size(); i++) { + QSTile t = page.mRecords.get(i).tile; + mUiEventLogger.logWithInstanceId(QSEvent.QS_TILE_VISIBLE, 0, t.getMetricsSpec(), + t.getInstanceId()); + } + } + @Override public void setListening(boolean listening) { if (mListening == listening) return; @@ -218,7 +230,11 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); int currentItem = getCurrentPageNumber(); for (int i = 0; i < mPages.size(); i++) { - mPages.get(i).setSelected(i == currentItem ? selected : false); + TilePage page = mPages.get(i); + page.setSelected(i == currentItem ? selected : false); + if (page.isSelected()) { + logVisibleTiles(page); + } } setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); } @@ -419,6 +435,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { mPageListener.onPageChanged(isLayoutRtl() ? position == mPages.size() - 1 : position == 0); } + } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java index 17aaff1f7383..ee3b499edfb7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java @@ -39,6 +39,7 @@ import android.widget.Switch; import android.widget.TextView; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEventLogger; import com.android.systemui.Dependency; import com.android.systemui.FontSizeUtils; import com.android.systemui.R; @@ -53,6 +54,7 @@ public class QSDetail extends LinearLayout { private static final long FADE_DURATION = 300; private final SparseArray<View> mDetailViews = new SparseArray<>(); + private final UiEventLogger mUiEventLogger = QSEvents.INSTANCE.getQsUiEventsLogger(); private ViewGroup mDetailContent; protected TextView mDetailSettingsButton; @@ -205,6 +207,7 @@ public class QSDetail extends LinearLayout { mDetailContent.addView(detailView); mDetailViews.put(viewCacheIndex, detailView); Dependency.get(MetricsLogger.class).visible(adapter.getMetricsCategory()); + mUiEventLogger.log(adapter.openDetailEvent()); announceForAccessibility(mContext.getString( R.string.accessibility_quick_settings_detail, adapter.getTitle())); @@ -214,6 +217,7 @@ public class QSDetail extends LinearLayout { } else { if (mDetailAdapter != null) { Dependency.get(MetricsLogger.class).hidden(mDetailAdapter.getMetricsCategory()); + mUiEventLogger.log(mDetailAdapter.closeDetailEvent()); } mClosingDetail = true; mDetailAdapter = null; @@ -249,6 +253,7 @@ public class QSDetail extends LinearLayout { mDetailSettingsButton.setOnClickListener(v -> { Dependency.get(MetricsLogger.class).action(ACTION_QS_MORE_SETTINGS, adapter.getMetricsCategory()); + mUiEventLogger.log(adapter.moreSettingsEvent()); Dependency.get(ActivityStarter.class) .postStartActivityDismissingKeyguard(settingsIntent, 0); }); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt b/packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt new file mode 100644 index 000000000000..54e8a2be0d2a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2020 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 com.android.internal.logging.UiEvent +import com.android.internal.logging.UiEventLogger +import com.android.internal.logging.UiEventLoggerImpl +import com.android.internal.logging.testing.UiEventLoggerFake + +object QSEvents { + + var qsUiEventsLogger: UiEventLogger = UiEventLoggerImpl() + private set + + fun setLoggerForTesting(): UiEventLoggerFake { + return UiEventLoggerFake().also { + qsUiEventsLogger = it + } + } + + fun resetLogger() { + qsUiEventsLogger = UiEventLoggerImpl() + } +} + +enum class QSEvent(private val _id: Int) : UiEventLogger.UiEventEnum { + @UiEvent(doc = "Tile clicked. It has an instance id and a spec (or packageName)") + QS_ACTION_CLICK(387), + + @UiEvent(doc = "Tile secondary button clicked. " + + "It has an instance id and a spec (or packageName)") + QS_ACTION_SECONDARY_CLICK(388), + + @UiEvent(doc = "Tile long clicked. It has an instance id and a spec (or packageName)") + QS_ACTION_LONG_PRESS(389), + + @UiEvent(doc = "Quick Settings panel expanded") + QS_PANEL_EXPANDED(390), + + @UiEvent(doc = "Quick Settings panel collapsed") + QS_PANEL_COLLAPSED(391), + + @UiEvent(doc = "Tile visible in Quick Settings panel. The tile may be in a different page. " + + "It has an instance id and a spec (or packageName)") + QS_TILE_VISIBLE(392), + + @UiEvent(doc = "Quick Quick Settings panel expanded") + QQS_PANEL_EXPANDED(393), + + @UiEvent(doc = "Quick Quick Settings panel collapsed") + QQS_PANEL_COLLAPSED(394), + + @UiEvent(doc = "Tile visible in Quick Quick Settings panel. " + + "It has an instance id and a spec (or packageName)") + QQS_TILE_VISIBLE(395); + + override fun getId() = _id +} + +enum class QSEditEvent(private val _id: Int) : UiEventLogger.UiEventEnum { + + @UiEvent(doc = "Tile removed from current tiles") + QS_EDIT_REMOVE(210), + + @UiEvent(doc = "Tile added to current tiles") + QS_EDIT_ADD(211), + + @UiEvent(doc = "Tile moved") + QS_EDIT_MOVE(212), + + @UiEvent(doc = "QS customizer open") + QS_EDIT_OPEN(213), + + @UiEvent(doc = "QS customizer closed") + QS_EDIT_CLOSED(214), + + @UiEvent(doc = "QS tiles reset") + QS_EDIT_RESET(215); + + override fun getId() = _id +} + +enum class QSDndEvent(private val _id: Int) : UiEventLogger.UiEventEnum { + @UiEvent(doc = "TODO(beverlyt)") + QS_DND_CONDITION_SELECT(420), + + @UiEvent(doc = "TODO(beverlyt)") + QS_DND_TIME_UP(422), + + @UiEvent(doc = "TODO(beverlyt)") + QS_DND_TIME_DOWN(423); + + override fun getId() = _id +} + +enum class QSUserSwitcherEvent(private val _id: Int) : UiEventLogger.UiEventEnum { + @UiEvent(doc = "The current user has been switched in the detail panel") + QS_USER_SWITCH(424), + + @UiEvent(doc = "User switcher QS detail panel open") + QS_USER_DETAIL_OPEN(425), + + @UiEvent(doc = "User switcher QS detail panel closed") + QS_USER_DETAIL_CLOSE(426), + + @UiEvent(doc = "User switcher QS detail panel more settings pressed") + QS_USER_MORE_SETTINGS(427); + + override fun getId() = _id +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java index ece1ce8bb4d0..1e8c4d86da36 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java @@ -16,6 +16,8 @@ package com.android.systemui.qs; import android.content.Context; +import com.android.internal.logging.InstanceId; +import com.android.internal.logging.UiEventLogger; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.qs.external.TileServices; import com.android.systemui.qs.logging.QSLogger; @@ -30,6 +32,7 @@ public interface QSHost { Context getContext(); Context getUserContext(); QSLogger getQSLogger(); + UiEventLogger getUiEventLogger(); Collection<QSTile> getTiles(); void addCallback(Callback callback); void removeCallback(Callback callback); @@ -39,6 +42,8 @@ public interface QSHost { int indexOf(String tileSpec); + InstanceId getNewInstanceId(); + 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 121e2aa94954..a3004bdc004d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -52,6 +52,7 @@ import android.widget.HorizontalScrollView; import android.widget.LinearLayout; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.statusbar.NotificationVisibility; import com.android.settingslib.Utils; @@ -129,6 +130,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne private BrightnessController mBrightnessController; private final DumpManager mDumpManager; private final QSLogger mQSLogger; + protected final UiEventLogger mUiEventLogger; protected QSTileHost mHost; protected QSSecurityFooter mFooter; @@ -176,7 +178,8 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne @Background DelayableExecutor backgroundExecutor, @Nullable LocalBluetoothManager localBluetoothManager, ActivityStarter activityStarter, - NotificationEntryManager entryManager + NotificationEntryManager entryManager, + UiEventLogger uiEventLogger ) { super(context, attrs); mContext = context; @@ -188,6 +191,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne mBroadcastDispatcher = broadcastDispatcher; mActivityStarter = activityStarter; mNotificationEntryManager = entryManager; + mUiEventLogger = uiEventLogger; setOrientation(VERTICAL); @@ -678,8 +682,10 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne } mMetricsLogger.visibility(MetricsEvent.QS_PANEL, mExpanded); if (!mExpanded) { + mUiEventLogger.log(closePanelEvent()); closeDetail(); } else { + mUiEventLogger.log(openPanelEvent()); logTiles(); } } @@ -786,6 +792,18 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne return mHost.createTileView(tile, collapsedView); } + protected QSEvent openPanelEvent() { + return QSEvent.QS_PANEL_EXPANDED; + } + + protected QSEvent closePanelEvent() { + return QSEvent.QS_PANEL_COLLAPSED; + } + + protected QSEvent tileVisibleEvent() { + return QSEvent.QS_TILE_VISIBLE; + } + protected boolean shouldShowDetail() { return mExpanded; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index 9e8eb3a28781..8835e5db50c0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -31,6 +31,9 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; +import com.android.internal.logging.InstanceId; +import com.android.internal.logging.InstanceIdSequence; +import com.android.internal.logging.UiEventLogger; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -73,6 +76,7 @@ import javax.inject.Singleton; public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, Dumpable { private static final String TAG = "QSTileHost"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private static final int MAX_QS_INSTANCE_ID = 1 << 20; public static final String TILES_SETTING = Secure.QS_TILES; @@ -85,6 +89,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D private final DumpManager mDumpManager; private final BroadcastDispatcher mBroadcastDispatcher; private final QSLogger mQSLogger; + private final UiEventLogger mUiEventLogger; + private final InstanceIdSequence mInstanceIdSequence; private final List<Callback> mCallbacks = new ArrayList<>(); private AutoTileManager mAutoTiles; @@ -106,7 +112,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D DumpManager dumpManager, BroadcastDispatcher broadcastDispatcher, Optional<StatusBar> statusBarOptional, - QSLogger qsLogger) { + QSLogger qsLogger, + UiEventLogger uiEventLogger) { mIconController = iconController; mContext = context; mUserContext = context; @@ -114,8 +121,10 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D mPluginManager = pluginManager; mDumpManager = dumpManager; mQSLogger = qsLogger; + mUiEventLogger = uiEventLogger; mBroadcastDispatcher = broadcastDispatcher; + mInstanceIdSequence = new InstanceIdSequence(MAX_QS_INSTANCE_ID); mServices = new TileServices(this, bgLooper, mBroadcastDispatcher); mStatusBarOptional = statusBarOptional; @@ -137,6 +146,11 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D return mIconController; } + @Override + public InstanceId getNewInstanceId() { + return mInstanceIdSequence.newInstanceId(); + } + public void destroy() { mTiles.values().forEach(tile -> tile.destroy()); mAutoTiles.destroy(); @@ -170,6 +184,11 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D } @Override + public UiEventLogger getUiEventLogger() { + return mUiEventLogger; + } + + @Override public void addCallback(Callback callback) { mCallbacks.add(callback); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index 38dea657242d..6683a1ce4f4f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -27,6 +27,7 @@ import android.view.Gravity; import android.view.View; import android.widget.LinearLayout; +import com.android.internal.logging.UiEventLogger; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.systemui.Dependency; import com.android.systemui.R; @@ -88,11 +89,12 @@ public class QuickQSPanel extends QSPanel { @Background DelayableExecutor backgroundExecutor, @Nullable LocalBluetoothManager localBluetoothManager, ActivityStarter activityStarter, - NotificationEntryManager entryManager + NotificationEntryManager entryManager, + UiEventLogger uiEventLogger ) { super(context, attrs, dumpManager, broadcastDispatcher, qsLogger, foregroundExecutor, backgroundExecutor, localBluetoothManager, activityStarter, - entryManager); + entryManager, uiEventLogger); if (mFooter != null) { removeView(mFooter.getView()); } @@ -118,9 +120,9 @@ public class QuickQSPanel extends QSPanel { lp2.setMarginStart(0); mHorizontalLinearLayout.addView(mMediaPlayer.getView(), lp2); - mTileLayout = new DoubleLineTileLayout(context); + mTileLayout = new DoubleLineTileLayout(context, mUiEventLogger); mMediaTileLayout = mTileLayout; - mRegularTileLayout = new HeaderTileLayout(context); + mRegularTileLayout = new HeaderTileLayout(context, mUiEventLogger); LayoutParams lp = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1); lp.setMarginEnd(0); lp.setMarginStart(marginSize); @@ -135,7 +137,7 @@ public class QuickQSPanel extends QSPanel { super.setPadding(0, 0, 0, 0); } else { sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns); - mTileLayout = new HeaderTileLayout(context); + mTileLayout = new HeaderTileLayout(context, mUiEventLogger); mTileLayout.setListening(mListening); addView((View) mTileLayout, 0 /* Between brightness and footer */); super.setPadding(0, 0, 0, 0); @@ -312,13 +314,30 @@ public class QuickQSPanel extends QSPanel { super.setVisibility(visibility); } + @Override + protected QSEvent openPanelEvent() { + return QSEvent.QQS_PANEL_EXPANDED; + } + + @Override + protected QSEvent closePanelEvent() { + return QSEvent.QQS_PANEL_COLLAPSED; + } + + @Override + protected QSEvent tileVisibleEvent() { + return QSEvent.QQS_TILE_VISIBLE; + } + private static class HeaderTileLayout extends TileLayout { - private boolean mListening; + private final UiEventLogger mUiEventLogger; + private Rect mClippingBounds = new Rect(); - public HeaderTileLayout(Context context) { + public HeaderTileLayout(Context context, UiEventLogger uiEventLogger) { super(context); + mUiEventLogger = uiEventLogger; setClipChildren(false); setClipToPadding(false); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, @@ -443,5 +462,18 @@ public class QuickQSPanel extends QSPanel { } return getPaddingStart() + column * (mCellWidth + mCellMarginHorizontal); } + + @Override + public void setListening(boolean listening) { + boolean startedListening = !mListening && listening; + super.setListening(listening); + if (startedListening) { + for (int i = 0; i < getNumVisibleTiles(); i++) { + QSTile tile = mRecords.get(i).tile; + mUiEventLogger.logWithInstanceId(QSEvent.QQS_TILE_VISIBLE, 0, + tile.getMetricsSpec(), tile.getInstanceId()); + } + } + } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java index 9f59277c918a..098431658e6a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java @@ -31,7 +31,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout { protected final ArrayList<TileRecord> mRecords = new ArrayList<>(); private int mCellMarginTop; - private boolean mListening; + protected boolean mListening; protected int mMaxAllowedRows = 3; // Prototyping with less rows diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java index bfac85bd4c10..3e2f9dec5807 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java @@ -44,6 +44,7 @@ import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.plugins.qs.QS; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.qs.QSDetailClipper; +import com.android.systemui.qs.QSEditEvent; import com.android.systemui.qs.QSTileHost; import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer; @@ -93,7 +94,8 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene LightBarController lightBarController, KeyguardStateController keyguardStateController, ScreenLifecycle screenLifecycle, - TileQueryHelper tileQueryHelper) { + TileQueryHelper tileQueryHelper, + UiEventLogger uiEventLogger) { super(new ContextThemeWrapper(context, R.style.edit_theme), attrs); LayoutInflater.from(getContext()).inflate(R.layout.qs_customize_panel_content, this); @@ -115,7 +117,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene mToolbar.setTitle(R.string.qs_edit); mRecyclerView = findViewById(android.R.id.list); mTransparentView = findViewById(R.id.customizer_transparent_view); - mTileAdapter = new TileAdapter(getContext()); + mTileAdapter = new TileAdapter(getContext(), uiEventLogger); mTileQueryHelper = tileQueryHelper; mTileQueryHelper.setListener(mTileAdapter); mRecyclerView.setAdapter(mTileAdapter); diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSEditEvent.kt b/packages/SystemUI/src/com/android/systemui/qs/customize/QSEditEvent.kt deleted file mode 100644 index ff8ddec8397a..000000000000 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSEditEvent.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2020 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.customize - -import com.android.internal.logging.UiEvent -import com.android.internal.logging.UiEventLogger - -enum class QSEditEvent(private val _id: Int) : UiEventLogger.UiEventEnum { - - @UiEvent(doc = "Tile removed from current tiles") - QS_EDIT_REMOVE(210), - @UiEvent(doc = "Tile added to current tiles") - QS_EDIT_ADD(211), - @UiEvent(doc = "Tile moved") - QS_EDIT_MOVE(212), - @UiEvent(doc = "QS customizer open") - QS_EDIT_OPEN(213), - @UiEvent(doc = "QS customizer closed") - QS_EDIT_CLOSED(214), - @UiEvent(doc = "QS tiles reset") - QS_EDIT_RESET(215); - - override fun getId() = _id -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java index 58de95d7ed6d..e738cec4962a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java @@ -41,8 +41,8 @@ import androidx.recyclerview.widget.RecyclerView.State; import androidx.recyclerview.widget.RecyclerView.ViewHolder; import com.android.internal.logging.UiEventLogger; -import com.android.internal.logging.UiEventLoggerImpl; import com.android.systemui.R; +import com.android.systemui.qs.QSEditEvent; import com.android.systemui.qs.QSTileHost; import com.android.systemui.qs.customize.TileAdapter.Holder; import com.android.systemui.qs.customize.TileQueryHelper.TileInfo; @@ -92,10 +92,11 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta private int mAccessibilityFromIndex; private CharSequence mAccessibilityFromLabel; private QSTileHost mHost; - private UiEventLogger mUiEventLogger = new UiEventLoggerImpl(); + private final UiEventLogger mUiEventLogger; - public TileAdapter(Context context) { + public TileAdapter(Context context, UiEventLogger uiEventLogger) { mContext = context; + mUiEventLogger = uiEventLogger; mAccessibilityManager = context.getSystemService(AccessibilityManager.class); mItemTouchHelper = new ItemTouchHelper(mCallbacks); mDecoration = new TileItemDecoration(context); 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 08c8f86c1125..30e0a766de37 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java @@ -371,6 +371,11 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener return MetricsEvent.QS_CUSTOM; } + @Override + public final String getMetricsSpec() { + return mComponent.getPackageName(); + } + public void startUnlockAndRun() { Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> { try { 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 60f6647743d2..7e5f2e1961e1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java @@ -48,7 +48,9 @@ import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleRegistry; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.logging.InstanceId; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEventLogger; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.Utils; @@ -62,6 +64,7 @@ import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTile.State; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.PagedTileLayout.TilePage; +import com.android.systemui.qs.QSEvent; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QuickStatusBarHeader; import com.android.systemui.qs.logging.QSLogger; @@ -97,12 +100,14 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); private final StatusBarStateController mStatusBarStateController = Dependency.get(StatusBarStateController.class); + private final UiEventLogger mUiEventLogger; private final QSLogger mQSLogger; private final ArrayList<Callback> mCallbacks = new ArrayList<>(); private final Object mStaleListener = new Object(); protected TState mState; private TState mTmpState; + private final InstanceId mInstanceId; private boolean mAnnounceNextStateChange; private String mTileSpec; @@ -156,10 +161,12 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy protected QSTileImpl(QSHost host) { mHost = host; mContext = host.getContext(); + mInstanceId = host.getNewInstanceId(); mState = newTileState(); mTmpState = newTileState(); mQSSettingsPanelOption = QSSettingsControllerKt.getQSSettingsPanelOption(); mQSLogger = host.getQSLogger(); + mUiEventLogger = host.getUiEventLogger(); } protected final void resetStates() { @@ -173,6 +180,11 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy return mLifecycle; } + @Override + public InstanceId getInstanceId() { + return mInstanceId; + } + /** * Adds or removes a listening client for the tile. If the tile has one or more * listening client it will go into the listening state. @@ -247,6 +259,8 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy mMetricsLogger.write(populate(new LogMaker(ACTION_QS_CLICK).setType(TYPE_ACTION) .addTaggedData(FIELD_STATUS_BAR_STATE, mStatusBarStateController.getState()))); + mUiEventLogger.logWithInstanceId(QSEvent.QS_ACTION_CLICK, 0, getMetricsSpec(), + getInstanceId()); mQSLogger.logTileClick(mTileSpec, mStatusBarStateController.getState(), mState.state); mHandler.sendEmptyMessage(H.CLICK); } @@ -255,6 +269,8 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy mMetricsLogger.write(populate(new LogMaker(ACTION_QS_SECONDARY_CLICK).setType(TYPE_ACTION) .addTaggedData(FIELD_STATUS_BAR_STATE, mStatusBarStateController.getState()))); + mUiEventLogger.logWithInstanceId(QSEvent.QS_ACTION_SECONDARY_CLICK, 0, getMetricsSpec(), + getInstanceId()); mQSLogger.logTileSecondaryClick(mTileSpec, mStatusBarStateController.getState(), mState.state); mHandler.sendEmptyMessage(H.SECONDARY_CLICK); @@ -264,6 +280,8 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy mMetricsLogger.write(populate(new LogMaker(ACTION_QS_LONG_PRESS).setType(TYPE_ACTION) .addTaggedData(FIELD_STATUS_BAR_STATE, mStatusBarStateController.getState()))); + mUiEventLogger.logWithInstanceId(QSEvent.QS_ACTION_LONG_PRESS, 0, getMetricsSpec(), + getInstanceId()); mQSLogger.logTileLongClick(mTileSpec, mStatusBarStateController.getState(), mState.state); mHandler.sendEmptyMessage(H.LONG_CLICK); @@ -483,6 +501,11 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy } } + @Override + public String getMetricsSpec() { + return mTileSpec; + } + /** * Provides a default label for the tile. * @return default label for the tile. diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java index 447f48b5db94..89ce125ae985 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java @@ -26,10 +26,12 @@ import android.view.View; import android.view.ViewGroup; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.RestrictedLockUtils; import com.android.systemui.R; import com.android.systemui.qs.PseudoGridView; +import com.android.systemui.qs.QSUserSwitcherEvent; import com.android.systemui.statusbar.policy.UserSwitcherController; /** @@ -48,8 +50,9 @@ public class UserDetailView extends PseudoGridView { R.layout.qs_user_detail, parent, attach); } - public void createAndSetAdapter(UserSwitcherController controller) { - mAdapter = new Adapter(mContext, controller); + public void createAndSetAdapter(UserSwitcherController controller, + UiEventLogger uiEventLogger) { + mAdapter = new Adapter(mContext, controller, uiEventLogger); ViewGroupAdapterBridge.link(this, mAdapter); } @@ -63,11 +66,14 @@ public class UserDetailView extends PseudoGridView { private final Context mContext; protected UserSwitcherController mController; private View mCurrentUserView; + private final UiEventLogger mUiEventLogger; - public Adapter(Context context, UserSwitcherController controller) { + public Adapter(Context context, UserSwitcherController controller, + UiEventLogger uiEventLogger) { super(controller); mContext = context; mController = controller; + mUiEventLogger = uiEventLogger; } @Override @@ -127,6 +133,7 @@ public class UserDetailView extends PseudoGridView { mController.startActivity(intent); } else if (tag.isSwitchToEnabled) { MetricsLogger.action(mContext, MetricsEvent.QS_SWITCH_USER); + mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_SWITCH); if (!tag.isAddUser && !tag.isRestricted && !tag.isDisabledByAdmin) { if (mCurrentUserView != null) { mCurrentUserView.setActivated(false); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index e81e5cae5bfc..229aa6d98e0a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -24,6 +24,7 @@ import android.util.Log; import android.view.animation.Interpolator; import com.android.internal.annotations.GuardedBy; +import com.android.internal.logging.UiEventLogger; import com.android.systemui.DejankUtils; import com.android.systemui.Dumpable; import com.android.systemui.Interpolators; @@ -69,6 +70,7 @@ public class StatusBarStateControllerImpl implements SysuiStatusBarStateControll }; private final ArrayList<RankedListener> mListeners = new ArrayList<>(); + private final UiEventLogger mUiEventLogger; private int mState; private int mLastState; private boolean mLeaveOpenOnKeyguardHide; @@ -119,7 +121,8 @@ public class StatusBarStateControllerImpl implements SysuiStatusBarStateControll private Interpolator mDozeInterpolator = Interpolators.FAST_OUT_SLOW_IN; @Inject - public StatusBarStateControllerImpl() { + public StatusBarStateControllerImpl(UiEventLogger uiEventLogger) { + mUiEventLogger = uiEventLogger; for (int i = 0; i < HISTORY_SIZE; i++) { mHistoricalRecords[i] = new HistoricalState(); } @@ -155,6 +158,7 @@ public class StatusBarStateControllerImpl implements SysuiStatusBarStateControll } mLastState = mState; mState = state; + mUiEventLogger.log(StatusBarStateEvent.fromState(mState)); for (RankedListener rl : new ArrayList<>(mListeners)) { rl.mListener.onStateChanged(mState); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateEvent.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateEvent.java new file mode 100644 index 000000000000..8330169980d4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateEvent.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 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.statusbar; + +import com.android.internal.logging.UiEvent; +import com.android.internal.logging.UiEventLogger; + +/** + * Events for changes in the {@link StatusBarState}. + */ +public enum StatusBarStateEvent implements UiEventLogger.UiEventEnum { + + @UiEvent(doc = "StatusBarState changed to unknown state") + STATUS_BAR_STATE_UNKNOWN(428), + + @UiEvent(doc = "StatusBarState changed to SHADE state") + STATUS_BAR_STATE_SHADE(429), + + @UiEvent(doc = "StatusBarState changed to KEYGUARD state") + STATUS_BAR_STATE_KEYGUARD(430), + + @UiEvent(doc = "StatusBarState changed to SHADE_LOCKED state") + STATUS_BAR_STATE_SHADE_LOCKED(431), + + @UiEvent(doc = "StatusBarState changed to FULLSCREEN_USER_SWITCHER state") + STATUS_BAR_STATE_FULLSCREEN_USER_SWITCHER(432); + + private int mId; + StatusBarStateEvent(int id) { + mId = id; + } + + @Override + public int getId() { + return mId; + } + + /** + * Return the event associated with the state. + */ + public static StatusBarStateEvent fromState(int state) { + switch(state) { + case StatusBarState.SHADE: + return STATUS_BAR_STATE_SHADE; + case StatusBarState.KEYGUARD: + return STATUS_BAR_STATE_KEYGUARD; + case StatusBarState.SHADE_LOCKED: + return STATUS_BAR_STATE_SHADE_LOCKED; + case StatusBarState.FULLSCREEN_USER_SWITCHER: + return STATUS_BAR_STATE_FULLSCREEN_USER_SWITCHER; + default: + return STATUS_BAR_STATE_UNKNOWN; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index 78ee5f25b111..1dbfa32cdf41 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -24,8 +24,6 @@ import android.os.Handler; import android.view.accessibility.AccessibilityManager; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.UiEventLogger; -import com.android.internal.logging.UiEventLoggerImpl; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.UiBackground; @@ -161,13 +159,6 @@ public interface NotificationsModule { return new NotificationPanelLoggerImpl(); } - /** Provides an instance of {@link com.android.internal.logging.UiEventLogger} */ - @Singleton - @Provides - static UiEventLogger provideUiEventLogger() { - return new UiEventLoggerImpl(); - } - /** Provides an instance of {@link NotificationBlockingHelperManager} */ @Singleton @Provides diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index bb0b5e00ff67..412962cc797a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -48,6 +48,7 @@ import android.view.ViewGroup; import android.widget.BaseAdapter; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.UserIcons; import com.android.settingslib.RestrictedLockUtilsInternal; @@ -61,6 +62,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.DetailAdapter; +import com.android.systemui.qs.QSUserSwitcherEvent; import com.android.systemui.qs.tiles.UserDetailView; import com.android.systemui.statusbar.phone.SystemUIDialog; @@ -108,13 +110,15 @@ public class UserSwitcherController implements Dumpable { private int mSecondaryUser = UserHandle.USER_NULL; private Intent mSecondaryUserServiceIntent; private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2); + private final UiEventLogger mUiEventLogger; @Inject public UserSwitcherController(Context context, KeyguardStateController keyguardStateController, @Main Handler handler, ActivityStarter activityStarter, - BroadcastDispatcher broadcastDispatcher) { + BroadcastDispatcher broadcastDispatcher, UiEventLogger uiEventLogger) { mContext = context; mBroadcastDispatcher = broadcastDispatcher; + mUiEventLogger = uiEventLogger; if (!UserManager.isGuestUserEphemeral()) { mGuestResumeSessionReceiver.register(mBroadcastDispatcher); } @@ -801,7 +805,7 @@ public class UserSwitcherController implements Dumpable { UserDetailView v; if (!(convertView instanceof UserDetailView)) { v = UserDetailView.inflate(context, parent, false); - v.createAndSetAdapter(UserSwitcherController.this); + v.createAndSetAdapter(UserSwitcherController.this, mUiEventLogger); } else { v = (UserDetailView) convertView; } @@ -827,6 +831,21 @@ public class UserSwitcherController implements Dumpable { public int getMetricsCategory() { return MetricsEvent.QS_USERDETAIL; } + + @Override + public UiEventLogger.UiEventEnum openDetailEvent() { + return QSUserSwitcherEvent.QS_USER_DETAIL_OPEN; + } + + @Override + public UiEventLogger.UiEventEnum closeDetailEvent() { + return QSUserSwitcherEvent.QS_USER_DETAIL_CLOSE; + } + + @Override + public UiEventLogger.UiEventEnum moreSettingsEvent() { + return QSUserSwitcherEvent.QS_USER_MORE_SETTINGS; + } }; private final KeyguardStateController.Callback mCallback = diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java index 7bb987ca7cf0..0cd4fb9578ff 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java +++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java @@ -56,9 +56,12 @@ import android.widget.TextView; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.Prefs; import com.android.systemui.R; +import com.android.systemui.qs.QSDndEvent; +import com.android.systemui.qs.QSEvents; import com.android.systemui.statusbar.policy.ZenModeController; import java.io.FileDescriptor; @@ -103,6 +106,7 @@ public class ZenModePanel extends FrameLayout { private final TransitionHelper mTransitionHelper = new TransitionHelper(); private final Uri mForeverId; private final ConfigurableTexts mConfigurableTexts; + private final UiEventLogger mUiEventLogger = QSEvents.INSTANCE.getQsUiEventsLogger(); private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this)); @@ -662,6 +666,7 @@ public class ZenModePanel extends FrameLayout { tag.rb.setChecked(true); if (DEBUG) Log.d(mTag, "onCheckedChanged " + conditionId); MetricsLogger.action(mContext, MetricsEvent.QS_DND_CONDITION_SELECT); + mUiEventLogger.log(QSDndEvent.QS_DND_CONDITION_SELECT); select(tag.condition); announceConditionSelection(tag); } @@ -767,6 +772,7 @@ public class ZenModePanel extends FrameLayout { private void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) { MetricsLogger.action(mContext, MetricsEvent.QS_DND_TIME, up); + mUiEventLogger.log(up ? QSDndEvent.QS_DND_TIME_UP : QSDndEvent.QS_DND_TIME_DOWN); Condition newCondition = null; final int N = MINUTE_BUCKETS.length; if (mBucketIndex == -1) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java index 5b78067ef81a..ae7387996322 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java @@ -27,6 +27,7 @@ import android.util.DisplayMetrics; import androidx.test.filters.SmallTest; +import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.brightline.BrightLineFalsingManager; @@ -65,7 +66,8 @@ public class FalsingManagerProxyTest extends SysuiTestCase { private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); private DockManager mDockManager = new DockManagerFake(); - private StatusBarStateController mStatusBarStateController = new StatusBarStateControllerImpl(); + private StatusBarStateController mStatusBarStateController = + new StatusBarStateControllerImpl(new UiEventLoggerFake()); @Before public void setup() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java index 8b5cc9abb777..b9cb499420ee 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java @@ -25,6 +25,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.DisplayMetrics; +import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.dock.DockManager; @@ -67,7 +68,7 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { FalsingDataProvider falsingDataProvider = new FalsingDataProvider(dm); DeviceConfigProxy deviceConfigProxy = new DeviceConfigProxyFake(); DockManager dockManager = new DockManagerFake(); - mStatusBarStateController = new StatusBarStateControllerImpl(); + mStatusBarStateController = new StatusBarStateControllerImpl(new UiEventLoggerFake()); mStatusBarStateController.setState(StatusBarState.KEYGUARD); mFalsingManager = new BrightLineFalsingManager(falsingDataProvider, mKeyguardUpdateMonitor, mProximitySensor, deviceConfigProxy, dockManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java index 8879e83b4d0e..353efeeb21f6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java @@ -16,6 +16,7 @@ package com.android.systemui.qs; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_MORE_SETTINGS; +import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; @@ -33,11 +34,13 @@ import android.view.View; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.testing.UiEventLoggerFake; 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; @@ -54,10 +57,13 @@ public class QSDetailTest extends SysuiTestCase { private ActivityStarter mActivityStarter; private DetailAdapter mMockDetailAdapter; private TestableLooper mTestableLooper; + private UiEventLoggerFake mUiEventLogger; @Before public void setup() throws Exception { mTestableLooper = TestableLooper.get(this); + mUiEventLogger = QSEvents.INSTANCE.setLoggerForTesting(); + mTestableLooper.runWithLooper(() -> { mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class); mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class); @@ -70,6 +76,19 @@ public class QSDetailTest extends SysuiTestCase { when(mMockDetailAdapter.createDetailView(any(), any(), any())) .thenReturn(mock(View.class)); }); + + // Only detail in use is the user detail + when(mMockDetailAdapter.openDetailEvent()) + .thenReturn(QSUserSwitcherEvent.QS_USER_DETAIL_OPEN); + when(mMockDetailAdapter.closeDetailEvent()) + .thenReturn(QSUserSwitcherEvent.QS_USER_DETAIL_CLOSE); + when(mMockDetailAdapter.moreSettingsEvent()) + .thenReturn(QSUserSwitcherEvent.QS_USER_MORE_SETTINGS); + } + + @After + public void tearDown() { + QSEvents.INSTANCE.resetLogger(); } @Test @@ -79,9 +98,16 @@ public class QSDetailTest extends SysuiTestCase { mQsDetail.handleShowingDetail(mMockDetailAdapter, 0, 0, false); verify(mMetricsLogger).visible(eq(mMockDetailAdapter.getMetricsCategory())); + assertEquals(1, mUiEventLogger.numLogs()); + assertEquals(QSUserSwitcherEvent.QS_USER_DETAIL_OPEN.getId(), mUiEventLogger.eventId(0)); + mUiEventLogger.getLogs().clear(); + mQsDetail.handleShowingDetail(null, 0, 0, false); verify(mMetricsLogger).hidden(eq(mMockDetailAdapter.getMetricsCategory())); + assertEquals(1, mUiEventLogger.numLogs()); + assertEquals(QSUserSwitcherEvent.QS_USER_DETAIL_CLOSE.getId(), mUiEventLogger.eventId(0)); + ViewUtils.detachView(mQsDetail); mTestableLooper.processAllMessages(); } @@ -92,10 +118,13 @@ public class QSDetailTest extends SysuiTestCase { mTestableLooper.processAllMessages(); mQsDetail.handleShowingDetail(mMockDetailAdapter, 0, 0, false); - mQsDetail.findViewById(android.R.id.button2).performClick(); + mUiEventLogger.getLogs().clear(); + mQsDetail.requireViewById(android.R.id.button2).performClick(); int metricsCategory = mMockDetailAdapter.getMetricsCategory(); verify(mMetricsLogger).action(eq(ACTION_QS_MORE_SETTINGS), eq(metricsCategory)); + assertEquals(1, mUiEventLogger.numLogs()); + assertEquals(QSUserSwitcherEvent.QS_USER_MORE_SETTINGS.getId(), mUiEventLogger.eventId(0)); verify(mActivityStarter).postStartActivityDismissingKeyguard(any(), anyInt()); @@ -105,7 +134,9 @@ public class QSDetailTest extends SysuiTestCase { @Test public void testNullAdapterClick() { - mQsDetail.setupDetailFooter(mock(DetailAdapter.class)); - mQsDetail.findViewById(android.R.id.button2).performClick(); + DetailAdapter mock = mock(DetailAdapter.class); + when(mock.moreSettingsEvent()).thenReturn(DetailAdapter.INVALID); + mQsDetail.setupDetailFooter(mock); + mQsDetail.requireViewById(android.R.id.button2).performClick(); } } 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 1f494a69f953..d338cbf51fb5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -34,6 +34,7 @@ import androidx.test.filters.SmallTest; import androidx.test.filters.Suppress; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEventLogger; import com.android.keyguard.CarrierText; import com.android.systemui.Dependency; import com.android.systemui.R; @@ -106,7 +107,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { mock(PluginManager.class), mock(TunerService.class), () -> mock(AutoTileManager.class), mock(DumpManager.class), mock(BroadcastDispatcher.class), Optional.of(mock(StatusBar.class)), - mock(QSLogger.class)); + mock(QSLogger.class), mock(UiEventLogger.class)); qs.setHost(host); qs.setListening(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java index 392adf99e511..9d35e53e7421 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java @@ -35,6 +35,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -94,17 +95,19 @@ public class QSPanelTest extends SysuiTestCase { private ActivityStarter mActivityStarter; @Mock private NotificationEntryManager mEntryManager; + private UiEventLoggerFake mUiEventLogger; @Before public void setup() throws Exception { MockitoAnnotations.initMocks(this); mTestableLooper = TestableLooper.get(this); + mUiEventLogger = new UiEventLoggerFake(); mTestableLooper.runWithLooper(() -> { mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class); mQsPanel = new QSPanel(mContext, null, mDumpManager, mBroadcastDispatcher, mQSLogger, mForegroundExecutor, mBackgroundExecutor, - mLocalBluetoothManager, mActivityStarter, mEntryManager); + mLocalBluetoothManager, mActivityStarter, mEntryManager, mUiEventLogger); // Provides a parent with non-zero size for QSPanel mParentView = new FrameLayout(mContext); mParentView.addView(mQsPanel); @@ -124,9 +127,17 @@ public class QSPanelTest extends SysuiTestCase { mQsPanel.setExpanded(true); verify(mMetricsLogger).visibility(eq(MetricsEvent.QS_PANEL), eq(true)); verify(mQSLogger).logPanelExpanded(true, mQsPanel.getDumpableTag()); + assertEquals(1, mUiEventLogger.numLogs()); + assertEquals(QSEvent.QS_PANEL_EXPANDED.getId(), mUiEventLogger.eventId(0)); + mUiEventLogger.getLogs().clear(); + mQsPanel.setExpanded(false); verify(mMetricsLogger).visibility(eq(MetricsEvent.QS_PANEL), eq(false)); verify(mQSLogger).logPanelExpanded(false, mQsPanel.getDumpableTag()); + assertEquals(1, mUiEventLogger.numLogs()); + assertEquals(QSEvent.QS_PANEL_COLLAPSED.getId(), mUiEventLogger.eventId(0)); + mUiEventLogger.getLogs().clear(); + } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java index 95c3e5aee870..966fa88653bf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java @@ -41,6 +41,7 @@ import android.testing.TestableLooper.RunWithLooper; import androidx.test.filters.SmallTest; +import com.android.internal.logging.UiEventLogger; import com.android.internal.util.CollectionUtils; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; @@ -50,7 +51,6 @@ import com.android.systemui.plugins.qs.QSFactory; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.qs.external.CustomTile; import com.android.systemui.qs.logging.QSLogger; -import com.android.systemui.qs.tileimpl.QSFactoryImpl; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.phone.AutoTileManager; @@ -105,6 +105,8 @@ public class QSTileHostTest extends SysuiTestCase { private QSLogger mQSLogger; @Mock private CustomTile mCustomTile; + @Mock + private UiEventLogger mUiEventLogger; private Handler mHandler; private TestableLooper mLooper; @@ -117,7 +119,7 @@ public class QSTileHostTest extends SysuiTestCase { mHandler = new Handler(mLooper.getLooper()); mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler, mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager, - mBroadcastDispatcher, mStatusBar, mQSLogger); + mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger); setUpTileFactory(); // Override this config so there are no unexpected tiles @@ -298,10 +300,11 @@ public class QSTileHostTest extends SysuiTestCase { QSFactory defaultFactory, Handler mainHandler, Looper bgLooper, PluginManager pluginManager, TunerService tunerService, Provider<AutoTileManager> autoTiles, DumpManager dumpManager, - BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger) { + BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger, + UiEventLogger uiEventLogger) { super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager, tunerService, autoTiles, dumpManager, broadcastDispatcher, - Optional.of(statusBar), qsLogger); + Optional.of(statusBar), qsLogger, uiEventLogger); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java index 25bac7ae4117..204de929e331 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java @@ -24,6 +24,7 @@ import android.testing.TestableLooper.RunWithLooper; import androidx.test.filters.SmallTest; +import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.systemui.SysuiTestCase; import com.android.systemui.qs.QSTileHost; @@ -42,7 +43,8 @@ public class TileAdapterTest extends SysuiTestCase { @Before public void setup() throws Exception { - TestableLooper.get(this).runWithLooper(() -> mTileAdapter = new TileAdapter(mContext)); + TestableLooper.get(this).runWithLooper(() -> mTileAdapter = + new TileAdapter(mContext, new UiEventLoggerFake())); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java index 884e4c0f5205..2fc3d72c2672 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java @@ -30,6 +30,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; +import com.android.internal.logging.UiEventLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; @@ -81,6 +82,8 @@ public class TileServicesTest extends SysuiTestCase { private StatusBar mStatusBar; @Mock private QSLogger mQSLogger; + @Mock + private UiEventLogger mUiEventLogger; @Before public void setUp() throws Exception { @@ -98,7 +101,8 @@ public class TileServicesTest extends SysuiTestCase { mDumpManager, mBroadcastDispatcher, Optional.of(mStatusBar), - mQSLogger); + mQSLogger, + mUiEventLogger); mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher); } 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 index 4fada336fb94..1c0d451e064a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java @@ -46,12 +46,16 @@ import android.testing.TestableLooper.RunWithLooper; import androidx.test.filters.SmallTest; +import com.android.internal.logging.InstanceId; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEventLogger; +import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.qs.QSEvent; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QSTileHost; import com.android.systemui.qs.logging.QSLogger; @@ -83,6 +87,8 @@ public class QSTileImplTest extends SysuiTestCase { private QSTileHost mHost; private MetricsLogger mMetricsLogger; private StatusBarStateController mStatusBarStateController; + private UiEventLoggerFake mUiEventLoggerFake; + private InstanceId mInstanceId = InstanceId.fakeInstanceId(5); @Captor private ArgumentCaptor<LogMaker> mLogCaptor; @@ -94,12 +100,15 @@ public class QSTileImplTest extends SysuiTestCase { mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper()); mDependency.injectMockDependency(ActivityStarter.class); mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class); + mUiEventLoggerFake = new UiEventLoggerFake(); mStatusBarStateController = mDependency.injectMockDependency(StatusBarStateController.class); mHost = mock(QSTileHost.class); when(mHost.indexOf(SPEC)).thenReturn(POSITION); when(mHost.getContext()).thenReturn(mContext.getBaseContext()); when(mHost.getQSLogger()).thenReturn(mQsLogger); + when(mHost.getUiEventLogger()).thenReturn(mUiEventLoggerFake); + when(mHost.getNewInstanceId()).thenReturn(mInstanceId); mTile = spy(new TileImpl(mHost)); mTile.mHandler = mTile.new H(mTestableLooper.getLooper()); @@ -110,6 +119,9 @@ public class QSTileImplTest extends SysuiTestCase { public void testClick_Metrics() { mTile.click(); verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_CLICK))); + assertEquals(1, mUiEventLoggerFake.numLogs()); + UiEventLoggerFake.FakeUiEvent event = mUiEventLoggerFake.get(0); + assertEvent(QSEvent.QS_ACTION_CLICK, event); } @Test @@ -133,6 +145,9 @@ public class QSTileImplTest extends SysuiTestCase { public void testSecondaryClick_Metrics() { mTile.secondaryClick(); verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_SECONDARY_CLICK))); + assertEquals(1, mUiEventLoggerFake.numLogs()); + UiEventLoggerFake.FakeUiEvent event = mUiEventLoggerFake.get(0); + assertEvent(QSEvent.QS_ACTION_SECONDARY_CLICK, event); } @Test @@ -156,6 +171,9 @@ public class QSTileImplTest extends SysuiTestCase { public void testLongClick_Metrics() { mTile.longClick(); verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_LONG_PRESS))); + assertEquals(1, mUiEventLoggerFake.numLogs()); + UiEventLoggerFake.FakeUiEvent event = mUiEventLoggerFake.get(0); + assertEvent(QSEvent.QS_ACTION_LONG_PRESS, event); } @@ -249,6 +267,13 @@ public class QSTileImplTest extends SysuiTestCase { verify(mQsLogger).logTileChangeListening(SPEC, false); } + private void assertEvent(UiEventLogger.UiEventEnum eventType, + UiEventLoggerFake.FakeUiEvent fakeEvent) { + assertEquals(eventType.getId(), fakeEvent.eventId); + assertEquals(SPEC, fakeEvent.packageName); + assertEquals(mInstanceId, fakeEvent.instanceId); + } + private class TileLogMatcher implements ArgumentMatcher<LogMaker> { private final int mCategory; diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt index b51e716591fe..6d6a4d8f6b7d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt @@ -24,8 +24,11 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.test.filters.SmallTest +import com.android.internal.logging.testing.UiEventLoggerFake import com.android.systemui.SysuiTestCase +import com.android.systemui.qs.QSUserSwitcherEvent import com.android.systemui.statusbar.policy.UserSwitcherController +import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -50,15 +53,17 @@ class UserDetailViewAdapterTest : SysuiTestCase() { @Mock private lateinit var mPicture: Bitmap @Mock private lateinit var mLayoutInflater: LayoutInflater private lateinit var adapter: UserDetailView.Adapter + private lateinit var uiEventLogger: UiEventLoggerFake @Before fun setUp() { MockitoAnnotations.initMocks(this) + uiEventLogger = UiEventLoggerFake() mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, mLayoutInflater) `when`(mLayoutInflater.inflate(anyInt(), any(ViewGroup::class.java), anyBoolean())) .thenReturn(mInflatedUserDetailItemView) - adapter = UserDetailView.Adapter(mContext, mUserSwitcherController) + adapter = UserDetailView.Adapter(mContext, mUserSwitcherController, uiEventLogger) } private fun clickableTest( @@ -77,6 +82,17 @@ class UserDetailViewAdapterTest : SysuiTestCase() { } @Test + fun testUserSwitchLog() { + val user = createUserRecord(false /* current */, false /* guest */) + val v = adapter.createUserDetailItemView(View(mContext), mParent, user) + `when`(v.tag).thenReturn(user) + adapter.onClick(v) + + assertEquals(1, uiEventLogger.numLogs()) + assertEquals(QSUserSwitcherEvent.QS_USER_SWITCH.id, uiEventLogger.eventId(0)) + } + + @Test fun testGuestIsClickable_differentViews_notCurrent() { clickableTest(false, true, mOtherView, true) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt new file mode 100644 index 000000000000..fca6bc50f6e2 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 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.statusbar + +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import androidx.test.filters.SmallTest +import com.android.internal.logging.testing.UiEventLoggerFake +import com.android.systemui.SysuiTestCase +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +class StatusBarStateControllerImplTest : SysuiTestCase() { + + private lateinit var controller: StatusBarStateControllerImpl + private lateinit var uiEventLogger: UiEventLoggerFake + + @Before + fun setUp() { + uiEventLogger = UiEventLoggerFake() + controller = StatusBarStateControllerImpl(uiEventLogger) + } + + @Test + fun testChangeState_logged() { + TestableLooper.get(this).runWithLooper { + controller.state = StatusBarState.FULLSCREEN_USER_SWITCHER + controller.state = StatusBarState.KEYGUARD + controller.state = StatusBarState.SHADE + controller.state = StatusBarState.SHADE_LOCKED + } + + val logs = uiEventLogger.logs + assertEquals(4, logs.size) + val ids = logs.map(UiEventLoggerFake.FakeUiEvent::eventId) + assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_FULLSCREEN_USER_SWITCHER.id, ids[0]) + assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_KEYGUARD.id, ids[1]) + assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_SHADE.id, ids[2]) + assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_SHADE_LOCKED.id, ids[3]) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt new file mode 100644 index 000000000000..b5b2f1fc0484 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2020 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.statusbar + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class StatusBarStateEventTest : SysuiTestCase() { + + @Test + fun testFromState() { + val events = listOf( + StatusBarStateEvent.STATUS_BAR_STATE_SHADE, + StatusBarStateEvent.STATUS_BAR_STATE_SHADE_LOCKED, + StatusBarStateEvent.STATUS_BAR_STATE_KEYGUARD, + StatusBarStateEvent.STATUS_BAR_STATE_FULLSCREEN_USER_SWITCHER, + StatusBarStateEvent.STATUS_BAR_STATE_UNKNOWN + ) + val states = listOf( + StatusBarState.SHADE, + StatusBarState.SHADE_LOCKED, + StatusBarState.KEYGUARD, + StatusBarState.FULLSCREEN_USER_SWITCHER, + -1 + ) + events.zip(states).forEach { (event, state) -> + assertEquals(event, StatusBarStateEvent.fromState(state)) + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index 4b09aa687073..57ef05544e7e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -47,6 +47,7 @@ import android.view.accessibility.AccessibilityManager; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.internal.util.LatencyTracker; import com.android.keyguard.KeyguardClockSwitch; import com.android.keyguard.KeyguardUpdateMonitor; @@ -207,7 +208,7 @@ public class NotificationPanelViewTest extends SysuiTestCase { NotificationWakeUpCoordinator coordinator = new NotificationWakeUpCoordinator( mock(HeadsUpManagerPhone.class), - new StatusBarStateControllerImpl(), + new StatusBarStateControllerImpl(new UiEventLoggerFake()), mKeyguardBypassController, mDozeParameters); PulseExpansionHandler expansionHandler = new PulseExpansionHandler( |