Merge "fix getIfaceStats and getTotalStats bug"
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index d160b73..1e915f8 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -17,18 +17,18 @@
package com.android.commands.media;
-import android.app.ActivityManager;
+import android.app.ActivityThread;
import android.content.Context;
import android.media.MediaMetadata;
-import android.media.session.ControllerCallbackLink;
-import android.media.session.ISessionController;
import android.media.session.ISessionManager;
+import android.media.session.MediaController;
import android.media.session.MediaController.PlaybackInfo;
import android.media.session.MediaSession.QueueItem;
+import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
import android.os.Bundle;
import android.os.HandlerThread;
-import android.os.IBinder;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -48,6 +48,8 @@
public class Media extends BaseCommand {
// This doesn't belongs to any package. Setting the package name to empty string.
private static final String PACKAGE_NAME = "";
+ private static ActivityThread sThread;
+ private static MediaSessionManager sMediaSessionManager;
private ISessionManager mSessionService;
/**
@@ -80,6 +82,13 @@
@Override
public void onRun() throws Exception {
+ if (sThread == null) {
+ Looper.prepareMainLooper();
+ sThread = ActivityThread.systemMain();
+ Context context = sThread.getSystemContext();
+ sMediaSessionManager =
+ (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
+ }
mSessionService = ISessionManager.Stub.asInterface(ServiceManager.checkService(
Context.MEDIA_SESSION_SERVICE));
if (mSessionService == null) {
@@ -117,12 +126,11 @@
showError("Error: must include a session id");
return;
}
+
boolean success = false;
try {
- List<IBinder> sessions = mSessionService
- .getSessions(null, ActivityManager.getCurrentUser());
- for (IBinder session : sessions) {
- ISessionController controller = ISessionController.Stub.asInterface(session);
+ List<MediaController> controllers = sMediaSessionManager.getActiveSessions(null);
+ for (MediaController controller : controllers) {
try {
if (controller != null && id.equals(controller.getTag())) {
ControllerMonitor monitor = new ControllerMonitor(controller);
@@ -178,14 +186,14 @@
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
}
- class ControllerCallbackStub extends ControllerCallbackLink.CallbackStub {
+ class ControllerCallback extends MediaController.Callback {
@Override
public void onSessionDestroyed() {
System.out.println("onSessionDestroyed. Enter q to quit.");
}
@Override
- public void onEvent(String event, Bundle extras) {
+ public void onSessionEvent(String event, Bundle extras) {
System.out.println("onSessionEvent event=" + event + ", extras=" + extras);
}
@@ -218,25 +226,25 @@
}
@Override
- public void onVolumeInfoChanged(PlaybackInfo info) {
- System.out.println("onVolumeInfoChanged " + info);
+ public void onAudioInfoChanged(PlaybackInfo info) {
+ System.out.println("onAudioInfoChanged " + info);
}
}
private class ControllerMonitor {
- private final ISessionController mController;
- private final ControllerCallbackLink mControllerCallbackLink;
+ private final MediaController mController;
+ private final ControllerCallback mControllerCallback;
- ControllerMonitor(ISessionController controller) {
+ ControllerMonitor(MediaController controller) {
mController = controller;
- mControllerCallbackLink = new ControllerCallbackLink(new ControllerCallbackStub());
+ mControllerCallback = new ControllerCallback();
}
void printUsageMessage() {
try {
System.out.println("V2Monitoring session " + mController.getTag()
+ "... available commands: play, pause, next, previous");
- } catch (RemoteException e) {
+ } catch (RuntimeException e) {
System.out.println("Error trying to monitor session!");
}
System.out.println("(q)uit: finish monitoring");
@@ -248,8 +256,8 @@
@Override
protected void onLooperPrepared() {
try {
- mController.registerCallbackListener(PACKAGE_NAME, mControllerCallbackLink);
- } catch (RemoteException e) {
+ mController.registerCallback(mControllerCallback);
+ } catch (RuntimeException e) {
System.out.println("Error registering monitor callback");
}
}
@@ -291,7 +299,7 @@
} finally {
cbThread.getLooper().quit();
try {
- mController.unregisterCallbackListener(mControllerCallbackLink);
+ mController.unregisterCallback(mControllerCallback);
} catch (Exception e) {
// ignoring
}
@@ -305,9 +313,9 @@
KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD);
try {
- mController.sendMediaButton(PACKAGE_NAME, null, false, down);
- mController.sendMediaButton(PACKAGE_NAME, null, false, up);
- } catch (RemoteException e) {
+ mController.dispatchMediaButtonEvent(down);
+ mController.dispatchMediaButtonEvent(up);
+ } catch (RuntimeException e) {
System.out.println("Failed to dispatch " + keyCode);
}
}
@@ -316,16 +324,13 @@
private void runListSessions() {
System.out.println("Sessions:");
try {
- List<IBinder> sessions = mSessionService
- .getSessions(null, ActivityManager.getCurrentUser());
- for (IBinder session : sessions) {
-
- ISessionController controller = ISessionController.Stub.asInterface(session);
+ List<MediaController> controllers = sMediaSessionManager.getActiveSessions(null);
+ for (MediaController controller : controllers) {
if (controller != null) {
try {
System.out.println(" tag=" + controller.getTag()
+ ", package=" + controller.getPackageName());
- } catch (RemoteException e) {
+ } catch (RuntimeException e) {
// ignore
}
}
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 63fd563..ad34ab3 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -173,7 +173,8 @@
}
/**
- * Implement this to know when a notification is expanded / collapsed.
+ * Implement this to know when a notification change (expanded / collapsed) is visible to user.
+ *
* @param key the notification key
* @param isUserAction whether the expanded change is caused by user action.
* @param isExpanded whether the notification is expanded.
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index 499d493..f346b00 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -344,7 +344,6 @@
if (entry != null) {
entry.setSeen();
mAgingHelper.onNotificationSeen(entry);
- mSmartActionsHelper.onNotificationSeen(entry);
}
}
} catch (Throwable e) {
diff --git a/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java b/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java
index acf1180..ce2c409 100644
--- a/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java
+++ b/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java
@@ -236,10 +236,6 @@
return mSeen;
}
- public boolean isExpanded() {
- return mExpanded;
- }
-
public boolean isShowActionEventLogged() {
return mIsShowActionEventLogged;
}
diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
index 95df5f2..0d528e7 100644
--- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
+++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
@@ -152,18 +152,26 @@
return replies;
}
- void onNotificationSeen(@NonNull NotificationEntry entry) {
- if (entry.isExpanded()) {
- maybeSendActionShownEvent(entry);
- }
- }
-
void onNotificationExpansionChanged(@NonNull NotificationEntry entry, boolean isUserAction,
boolean isExpanded) {
- // Notification can be expanded in the background, and thus the isUserAction check.
- if (isUserAction && isExpanded) {
- maybeSendActionShownEvent(entry);
+ if (!isExpanded) {
+ return;
}
+ String resultId = mNotificationKeyToResultIdCache.get(entry.getSbn().getKey());
+ if (resultId == null) {
+ return;
+ }
+ // Only report if this is the first time the user sees these suggestions.
+ if (entry.isShowActionEventLogged()) {
+ return;
+ }
+ entry.setShowActionEventLogged();
+ TextClassifierEvent textClassifierEvent =
+ createTextClassifierEventBuilder(TextClassifierEvent.TYPE_ACTIONS_SHOWN,
+ resultId)
+ .build();
+ // TODO: If possible, report which replies / actions are actually seen by user.
+ mTextClassifier.onTextClassifierEvent(textClassifierEvent);
}
void onNotificationDirectReplied(@NonNull String key) {
@@ -234,26 +242,6 @@
.setResultId(resultId);
}
- private void maybeSendActionShownEvent(@NonNull NotificationEntry entry) {
- if (mTextClassifier == null) {
- return;
- }
- String resultId = mNotificationKeyToResultIdCache.get(entry.getSbn().getKey());
- if (resultId == null) {
- return;
- }
- // Only report if this is the first time the user sees these suggestions.
- if (entry.isShowActionEventLogged()) {
- return;
- }
- entry.setShowActionEventLogged();
- TextClassifierEvent textClassifierEvent =
- createTextClassifierEventBuilder(TextClassifierEvent.TYPE_ACTIONS_SHOWN, resultId)
- .build();
- // TODO: If possible, report which replies / actions are actually seen by user.
- mTextClassifier.onTextClassifierEvent(textClassifierEvent);
- }
-
/**
* Returns whether a notification is eligible for action adjustments.
*
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java
index 7b7ce3d..707349b 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java
@@ -273,24 +273,22 @@
final String message = "Where are you?";
Notification notification = mNotificationBuilder.setContentText(message).build();
when(mNotificationEntry.getNotification()).thenReturn(notification);
- when(mNotificationEntry.isExpanded()).thenReturn(false);
mSmartActionsHelper.suggestReplies(mNotificationEntry);
- mSmartActionsHelper.onNotificationSeen(mNotificationEntry);
+ mSmartActionsHelper.onNotificationExpansionChanged(mNotificationEntry, false, false);
verify(mTextClassifier, never()).onTextClassifierEvent(
Mockito.any(TextClassifierEvent.class));
}
@Test
- public void testOnNotificationsSeen_expanded() {
+ public void testOnNotifications_expanded() {
final String message = "Where are you?";
Notification notification = mNotificationBuilder.setContentText(message).build();
when(mNotificationEntry.getNotification()).thenReturn(notification);
- when(mNotificationEntry.isExpanded()).thenReturn(true);
mSmartActionsHelper.suggestReplies(mNotificationEntry);
- mSmartActionsHelper.onNotificationSeen(mNotificationEntry);
+ mSmartActionsHelper.onNotificationExpansionChanged(mNotificationEntry, false, true);
ArgumentCaptor<TextClassifierEvent> argumentCaptor =
ArgumentCaptor.forClass(TextClassifierEvent.class);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
index cc302b1..0b8596f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
@@ -27,13 +27,10 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Build;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import android.view.ViewGroup;
-import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.NotificationMessagingUtil;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -43,6 +40,7 @@
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationUiAdjustment;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
@@ -71,7 +69,6 @@
Dependency.get(NotificationInterruptionStateProvider.class);
private final Context mContext;
- private final IStatusBarService mBarService;
private final NotificationMessagingUtil mMessagingUtil;
private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger =
this::logNotificationExpansion;
@@ -85,6 +82,7 @@
private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
private BindRowCallback mBindRowCallback;
private NotificationClicker mNotificationClicker;
+ private final NotificationLogger mNotificationLogger = Dependency.get(NotificationLogger.class);
@Inject
public NotificationRowBinder(Context context,
@@ -92,8 +90,6 @@
mContext = context;
mMessagingUtil = new NotificationMessagingUtil(context);
mAllowLongPress = allowLongPress;
- mBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService(Context.STATUS_BAR_SERVICE));
}
private NotificationRemoteInputManager getRemoteInputManager() {
@@ -274,13 +270,7 @@
}
private void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
- mUiOffloadThread.submit(() -> {
- try {
- mBarService.onNotificationExpansionChanged(key, userAction, expanded);
- } catch (RemoteException e) {
- // Ignore.
- }
- });
+ mNotificationLogger.onExpansionChanged(key, userAction, expanded);
}
/** Callback for when a row is bound to an entry. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 3eec38e..5ba9b4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -23,9 +23,12 @@
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
@@ -42,6 +45,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -66,6 +70,7 @@
private final UiOffloadThread mUiOffloadThread;
private final NotificationEntryManager mEntryManager;
private HeadsUpManager mHeadsUpManager;
+ private final ExpansionStateLogger mExpansionStateLogger;
protected Handler mHandler = new Handler();
protected IStatusBarService mBarService;
@@ -144,6 +149,9 @@
recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
mCurrentlyVisibleNotifications.addAll(mTmpCurrentlyVisibleNotifications);
+ mExpansionStateLogger.onVisibilityChanged(
+ mTmpCurrentlyVisibleNotifications, mTmpCurrentlyVisibleNotifications);
+
recycleAllVisibilityObjects(mTmpNoLongerVisibleNotifications);
mTmpCurrentlyVisibleNotifications.clear();
mTmpNewlyVisibleNotifications.clear();
@@ -155,12 +163,14 @@
public NotificationLogger(NotificationListener notificationListener,
UiOffloadThread uiOffloadThread,
NotificationEntryManager entryManager,
- StatusBarStateController statusBarStateController) {
+ StatusBarStateController statusBarStateController,
+ ExpansionStateLogger expansionStateLogger) {
mNotificationListener = notificationListener;
mUiOffloadThread = uiOffloadThread;
mEntryManager = entryManager;
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ mExpansionStateLogger = expansionStateLogger;
// Not expected to be destroyed, don't need to unsubscribe
statusBarStateController.addCallback(this);
@@ -173,6 +183,7 @@
if (removedByUser && visibility != null) {
logNotificationClear(entry.key, entry.notification, visibility);
}
+ mExpansionStateLogger.onEntryRemoved(entry.key);
}
@Override
@@ -319,8 +330,8 @@
}
}
- private NotificationVisibility[] cloneVisibilitiesAsArr(Collection<NotificationVisibility> c) {
-
+ private static NotificationVisibility[] cloneVisibilitiesAsArr(
+ Collection<NotificationVisibility> c) {
final NotificationVisibility[] array = new NotificationVisibility[c.size()];
int i = 0;
for(NotificationVisibility nv: c) {
@@ -348,9 +359,133 @@
}
/**
+ * Called when the notification is expanded / collapsed.
+ */
+ public void onExpansionChanged(String key, boolean isUserAction, boolean isExpanded) {
+ mExpansionStateLogger.onExpansionChanged(key, isUserAction, isExpanded);
+ }
+
+ /**
* A listener that is notified when some child locations might have changed.
*/
public interface OnChildLocationsChangedListener {
void onChildLocationsChanged();
}
+
+ /**
+ * Logs the expansion state change when the notification is visible.
+ */
+ public static class ExpansionStateLogger {
+ /** Notification key -> state, should be accessed in UI offload thread only. */
+ private final Map<String, State> mExpansionStates = new ArrayMap<>();
+
+ /**
+ * Notification key -> last logged expansion state, should be accessed in UI thread only.
+ */
+ private final Map<String, Boolean> mLoggedExpansionState = new ArrayMap<>();
+ private final UiOffloadThread mUiOffloadThread;
+ @VisibleForTesting
+ IStatusBarService mBarService;
+
+ @Inject
+ public ExpansionStateLogger(UiOffloadThread uiOffloadThread) {
+ mUiOffloadThread = uiOffloadThread;
+ mBarService =
+ IStatusBarService.Stub.asInterface(
+ ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ }
+
+ @VisibleForTesting
+ void onExpansionChanged(String key, boolean isUserAction, boolean isExpanded) {
+ State state = getState(key);
+ state.mIsUserAction = isUserAction;
+ state.mIsExpanded = isExpanded;
+ maybeNotifyOnNotificationExpansionChanged(key, state);
+ }
+
+ @VisibleForTesting
+ void onVisibilityChanged(
+ Collection<NotificationVisibility> newlyVisible,
+ Collection<NotificationVisibility> noLongerVisible) {
+ final NotificationVisibility[] newlyVisibleAr =
+ cloneVisibilitiesAsArr(newlyVisible);
+ final NotificationVisibility[] noLongerVisibleAr =
+ cloneVisibilitiesAsArr(noLongerVisible);
+
+ for (NotificationVisibility nv : newlyVisibleAr) {
+ State state = getState(nv.key);
+ state.mIsVisible = true;
+ maybeNotifyOnNotificationExpansionChanged(nv.key, state);
+ }
+ for (NotificationVisibility nv : noLongerVisibleAr) {
+ State state = getState(nv.key);
+ state.mIsVisible = false;
+ }
+ }
+
+ @VisibleForTesting
+ void onEntryRemoved(String key) {
+ mExpansionStates.remove(key);
+ mLoggedExpansionState.remove(key);
+ }
+
+ private State getState(String key) {
+ State state = mExpansionStates.get(key);
+ if (state == null) {
+ state = new State();
+ mExpansionStates.put(key, state);
+ }
+ return state;
+ }
+
+ private void maybeNotifyOnNotificationExpansionChanged(final String key, State state) {
+ if (!state.isFullySet()) {
+ return;
+ }
+ if (!state.mIsVisible) {
+ return;
+ }
+ Boolean loggedExpansionState = mLoggedExpansionState.get(key);
+ // Consider notification is initially collapsed, so only expanded is logged in the
+ // first time.
+ if (loggedExpansionState == null && !state.mIsExpanded) {
+ return;
+ }
+ if (loggedExpansionState != null
+ && state.mIsExpanded == loggedExpansionState) {
+ return;
+ }
+ mLoggedExpansionState.put(key, state.mIsExpanded);
+ final State stateToBeLogged = new State(state);
+ mUiOffloadThread.submit(() -> {
+ try {
+ mBarService.onNotificationExpansionChanged(
+ key, stateToBeLogged.mIsUserAction, stateToBeLogged.mIsExpanded);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to call onNotificationExpansionChanged: ", e);
+ }
+ });
+ }
+
+ private static class State {
+ @Nullable
+ Boolean mIsUserAction;
+ @Nullable
+ Boolean mIsExpanded;
+ @Nullable
+ Boolean mIsVisible;
+
+ private State() {}
+
+ private State(State state) {
+ this.mIsUserAction = state.mIsUserAction;
+ this.mIsExpanded = state.mIsExpanded;
+ this.mIsVisible = state.mIsVisible;
+ }
+
+ private boolean isFullySet() {
+ return mIsUserAction != null && mIsExpanded != null && mIsVisible != null;
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
new file mode 100644
index 0000000..4b03399
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
@@ -0,0 +1,145 @@
+/**
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.notification.logging;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.os.RemoteException;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.UiOffloadThread;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Collections;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class ExpansionStateLoggerTest extends SysuiTestCase {
+ private static final String NOTIFICATION_KEY = "notin_key";
+
+ private NotificationLogger.ExpansionStateLogger mLogger;
+ @Mock
+ private IStatusBarService mBarService;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mLogger = new NotificationLogger.ExpansionStateLogger(
+ Dependency.get(UiOffloadThread.class));
+ mLogger.mBarService = mBarService;
+ }
+
+ @Test
+ public void testVisible() throws RemoteException {
+ mLogger.onVisibilityChanged(
+ Collections.singletonList(createNotificationVisibility(NOTIFICATION_KEY, true)),
+ Collections.emptyList());
+ waitForUiOffloadThread();
+
+ verify(mBarService, Mockito.never()).onNotificationExpansionChanged(
+ eq(NOTIFICATION_KEY), anyBoolean(), anyBoolean());
+ }
+
+ @Test
+ public void testExpanded() throws RemoteException {
+ mLogger.onExpansionChanged(NOTIFICATION_KEY, false, true);
+ waitForUiOffloadThread();
+
+ verify(mBarService, Mockito.never()).onNotificationExpansionChanged(
+ eq(NOTIFICATION_KEY), anyBoolean(), anyBoolean());
+ }
+
+ @Test
+ public void testVisibleAndNotExpanded() throws RemoteException {
+ mLogger.onExpansionChanged(NOTIFICATION_KEY, true, false);
+ mLogger.onVisibilityChanged(
+ Collections.singletonList(createNotificationVisibility(NOTIFICATION_KEY, true)),
+ Collections.emptyList());
+ waitForUiOffloadThread();
+
+ verify(mBarService, Mockito.never()).onNotificationExpansionChanged(
+ eq(NOTIFICATION_KEY), anyBoolean(), anyBoolean());
+ }
+
+ @Test
+ public void testVisibleAndExpanded() throws RemoteException {
+ mLogger.onExpansionChanged(NOTIFICATION_KEY, true, true);
+ mLogger.onVisibilityChanged(
+ Collections.singletonList(createNotificationVisibility(NOTIFICATION_KEY, true)),
+ Collections.emptyList());
+ waitForUiOffloadThread();
+
+ verify(mBarService).onNotificationExpansionChanged(
+ NOTIFICATION_KEY, true, true);
+ }
+
+ @Test
+ public void testExpandedAndVisible_expandedBeforeVisible() throws RemoteException {
+ mLogger.onExpansionChanged(NOTIFICATION_KEY, false, true);
+ mLogger.onVisibilityChanged(
+ Collections.singletonList(createNotificationVisibility(NOTIFICATION_KEY, true)),
+ Collections.emptyList());
+ waitForUiOffloadThread();
+
+ verify(mBarService).onNotificationExpansionChanged(
+ NOTIFICATION_KEY, false, true);
+ }
+
+ @Test
+ public void testExpandedAndVisible_visibleBeforeExpanded() throws RemoteException {
+ mLogger.onVisibilityChanged(
+ Collections.singletonList(createNotificationVisibility(NOTIFICATION_KEY, true)),
+ Collections.emptyList());
+ mLogger.onExpansionChanged(NOTIFICATION_KEY, false, true);
+ waitForUiOffloadThread();
+
+ verify(mBarService).onNotificationExpansionChanged(
+ NOTIFICATION_KEY, false, true);
+ }
+
+ @Test
+ public void testExpandedAndVisible_logOnceOnly() throws RemoteException {
+ mLogger.onVisibilityChanged(
+ Collections.singletonList(createNotificationVisibility(NOTIFICATION_KEY, true)),
+ Collections.emptyList());
+ mLogger.onExpansionChanged(NOTIFICATION_KEY, false, true);
+ mLogger.onExpansionChanged(NOTIFICATION_KEY, false, true);
+ waitForUiOffloadThread();
+
+ verify(mBarService).onNotificationExpansionChanged(
+ NOTIFICATION_KEY, false, true);
+ }
+
+ private NotificationVisibility createNotificationVisibility(String key, boolean visibility) {
+ return NotificationVisibility.obtain(key, 0, 0, visibility);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index 6472589..db2706b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -72,6 +72,7 @@
@Mock private IStatusBarService mBarService;
@Mock private NotificationData mNotificationData;
@Mock private ExpandableNotificationRow mRow;
+ @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
// Dependency mocks:
@Mock private NotificationEntryManager mEntryManager;
@@ -98,7 +99,8 @@
mEntry.setRow(mRow);
mLogger = new TestableNotificationLogger(mListener, Dependency.get(UiOffloadThread.class),
- mEntryManager, mock(StatusBarStateController.class), mBarService);
+ mEntryManager, mock(StatusBarStateController.class), mBarService,
+ mExpansionStateLogger);
mLogger.setUpWithContainer(mListContainer);
verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture());
mNotificationEntryListener = mEntryListenerCaptor.getValue();
@@ -166,8 +168,10 @@
UiOffloadThread uiOffloadThread,
NotificationEntryManager entryManager,
StatusBarStateController statusBarStateController,
- IStatusBarService barService) {
- super(notificationListener, uiOffloadThread, entryManager, statusBarStateController);
+ IStatusBarService barService,
+ ExpansionStateLogger expansionStateLogger) {
+ super(notificationListener, uiOffloadThread, entryManager, statusBarStateController,
+ expansionStateLogger);
mBarService = barService;
// Make this on the current thread so we can wait for it during tests.
mHandler = Handler.createAsync(Looper.myLooper());
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 0d4046b..17611ff 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
@@ -159,6 +159,8 @@
private NotificationFilter mNotificationFilter;
@Mock
private NotificationAlertingManager mNotificationAlertingManager;
+ @Mock
+ private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
private TestableStatusBar mStatusBar;
private FakeMetricsLogger mMetricsLogger;
@@ -207,7 +209,8 @@
mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
mEntryManager = new TestableNotificationEntryManager(mContext);
mNotificationLogger = new NotificationLogger(mNotificationListener,
- Dependency.get(UiOffloadThread.class), mEntryManager, mStatusBarStateController);
+ Dependency.get(UiOffloadThread.class), mEntryManager, mStatusBarStateController,
+ mExpansionStateLogger);
mDependency.injectTestDependency(NotificationLogger.class, mNotificationLogger);
DozeLog.traceDozing(mContext, false /* dozing */);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 1798617..20c4da4 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -878,7 +878,6 @@
if (r.hasBeenVisiblyExpanded()) {
logSmartSuggestionsVisible(r);
}
- final long now = System.currentTimeMillis();
if (userAction) {
MetricsLogger.action(r.getItemLogMaker()
.setType(expanded ? MetricsEvent.TYPE_DETAIL
@@ -888,9 +887,6 @@
r.recordExpanded();
reportUserInteraction(r);
}
- EventLogTags.writeNotificationExpansion(key,
- userAction ? 1 : 0, expanded ? 1 : 0,
- r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
mAssistants.notifyAssistantExpansionChangedLocked(r.sbn, userAction, expanded);
}
}