diff options
8 files changed, 162 insertions, 13 deletions
diff --git a/core/java/com/android/internal/statusbar/NotificationVisibility.java b/core/java/com/android/internal/statusbar/NotificationVisibility.java index a7203e7e17d2..24bb789c3cc5 100644 --- a/core/java/com/android/internal/statusbar/NotificationVisibility.java +++ b/core/java/com/android/internal/statusbar/NotificationVisibility.java @@ -21,6 +21,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.util.Log; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; + import java.util.ArrayDeque; import java.util.Collection; @@ -33,18 +35,53 @@ public class NotificationVisibility implements Parcelable { public int rank; public int count; public boolean visible = true; + /** The visible location of the notification, could be e.g. notification shade or HUN. */ + public NotificationLocation location; /*package*/ int id; + /** + * The UI location of the notification. + * + * There is a one-to-one mapping between this enum and + * MetricsProto.MetricsEvent.NotificationLocation. + */ + public enum NotificationLocation { + LOCATION_UNKNOWN(MetricsEvent.LOCATION_UNKNOWN), + LOCATION_FIRST_HEADS_UP(MetricsEvent.LOCATION_FIRST_HEADS_UP), // visible heads-up + LOCATION_HIDDEN_TOP(MetricsEvent.LOCATION_HIDDEN_TOP), // hidden/scrolled away on the top + LOCATION_MAIN_AREA(MetricsEvent.LOCATION_MAIN_AREA), // visible in the shade + // in the bottom stack, and peeking + LOCATION_BOTTOM_STACK_PEEKING(MetricsEvent.LOCATION_BOTTOM_STACK_PEEKING), + // in the bottom stack, and hidden + LOCATION_BOTTOM_STACK_HIDDEN(MetricsEvent.LOCATION_BOTTOM_STACK_HIDDEN), + LOCATION_GONE(MetricsEvent.LOCATION_GONE); // the view isn't laid out at all + + private final int mMetricsEventNotificationLocation; + + NotificationLocation(int metricsEventNotificationLocation) { + mMetricsEventNotificationLocation = metricsEventNotificationLocation; + } + + /** + * Returns the field from MetricsEvent.NotificationLocation that corresponds to this object. + */ + public int toMetricsEventEnum() { + return mMetricsEventNotificationLocation; + } + } + private NotificationVisibility() { id = sNexrId++; } - private NotificationVisibility(String key, int rank, int count, boolean visibile) { + private NotificationVisibility(String key, int rank, int count, boolean visible, + NotificationLocation location) { this(); this.key = key; this.rank = rank; this.count = count; - this.visible = visibile; + this.visible = visible; + this.location = location; } @Override @@ -54,12 +91,13 @@ public class NotificationVisibility implements Parcelable { + " rank=" + rank + " count=" + count + (visible?" visible":"") + + " location=" + location.name() + " )"; } @Override public NotificationVisibility clone() { - return obtain(this.key, this.rank, this.count, this.visible); + return obtain(this.key, this.rank, this.count, this.visible, this.location); } @Override @@ -89,6 +127,7 @@ public class NotificationVisibility implements Parcelable { out.writeInt(this.rank); out.writeInt(this.count); out.writeInt(this.visible ? 1 : 0); + out.writeString(this.location.name()); } private void readFromParcel(Parcel in) { @@ -96,18 +135,28 @@ public class NotificationVisibility implements Parcelable { this.rank = in.readInt(); this.count = in.readInt(); this.visible = in.readInt() != 0; + this.location = NotificationLocation.valueOf(in.readString()); } /** - * Return a new NotificationVisibility instance from the global pool. Allows us to - * avoid allocating new objects in many cases. + * Create a new NotificationVisibility object. */ public static NotificationVisibility obtain(String key, int rank, int count, boolean visible) { + return obtain(key, rank, count, visible, + NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN); + } + + /** + * Create a new NotificationVisibility object. + */ + public static NotificationVisibility obtain(String key, int rank, int count, boolean visible, + NotificationLocation location) { NotificationVisibility vo = obtain(); vo.key = key; vo.rank = rank; vo.count = count; vo.visible = visible; + vo.location = location; return vo; } diff --git a/core/tests/coretests/src/com/android/internal/statusbar/NotificationVisibilityTest.java b/core/tests/coretests/src/com/android/internal/statusbar/NotificationVisibilityTest.java new file mode 100644 index 000000000000..b740eccfb794 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/statusbar/NotificationVisibilityTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2019 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.internal.statusbar; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.lang.reflect.Field; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public final class NotificationVisibilityTest { + + @Test + public void testNotificationLocation_sameValuesAsMetricsProto() throws Exception { + for (NotificationVisibility.NotificationLocation location : + NotificationVisibility.NotificationLocation.values()) { + Field locationField = MetricsEvent.class.getField(location.name()); + int metricsValue = locationField.getInt(null); + assertThat(metricsValue, is(location.toMetricsEventEnum())); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index d5f4d0461ba4..d2ce31d75648 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -49,6 +49,7 @@ import com.android.systemui.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardMonitor; @@ -130,8 +131,11 @@ public class NotificationLockscreenUserManagerImpl implements final int count = getEntryManager().getNotificationData().getActiveNotifications().size(); final int rank = getEntryManager().getNotificationData().getRank(notificationKey); + NotificationVisibility.NotificationLocation location = + NotificationLogger.getNotificationLocation( + getEntryManager().getNotificationData().get(notificationKey)); final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey, - rank, count, true); + rank, count, true, location); try { mBarService.onNotificationClick(notificationKey, nv); } catch (RemoteException e) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index 7d6231f27885..31d16211f521 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -54,6 +54,7 @@ import com.android.systemui.Dumpable; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; 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.phone.ShadeController; import com.android.systemui.statusbar.policy.RemoteInputView; @@ -181,7 +182,11 @@ public class NotificationRemoteInputManager implements Dumpable { final int rank = mEntryManager.getNotificationData().getRank(key); final Notification.Action action = statusBarNotification.getNotification().actions[actionIndex]; - final NotificationVisibility nv = NotificationVisibility.obtain(key, rank, count, true); + NotificationVisibility.NotificationLocation location = + NotificationLogger.getNotificationLocation( + mEntryManager.getNotificationData().get(key)); + final NotificationVisibility nv = + NotificationVisibility.obtain(key, rank, count, true, location); try { mBarService.onNotificationActionClick(key, buttonIndex, action, nv, false); } catch (RemoteException e) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java index 573c1f8ee509..a2abcd2f9c8f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java @@ -23,6 +23,7 @@ import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.logging.NotificationLogger; import java.util.Set; @@ -74,8 +75,10 @@ public class SmartReplyController { boolean generatedByAssistant) { final int count = mEntryManager.getNotificationData().getActiveNotifications().size(); final int rank = mEntryManager.getNotificationData().getRank(entry.key); - final NotificationVisibility nv = - NotificationVisibility.obtain(entry.key, rank, count, true); + NotificationVisibility.NotificationLocation location = + NotificationLogger.getNotificationLocation(entry); + final NotificationVisibility nv = NotificationVisibility.obtain( + entry.key, rank, count, true, location); try { mBarService.onNotificationActionClick( entry.key, actionIndex, action, nv, generatedByAssistant); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index 989e781ab5ba..ef5e936f9532 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -36,6 +36,7 @@ import com.android.systemui.statusbar.NotificationUpdateHandler; import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationInflater; import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; @@ -160,8 +161,10 @@ public class NotificationEntryManager implements public void performRemoveNotification(StatusBarNotification n) { final int rank = mNotificationData.getRank(n.getKey()); final int count = mNotificationData.getActiveNotifications().size(); + NotificationVisibility.NotificationLocation location = + NotificationLogger.getNotificationLocation(getNotificationData().get(n.getKey())); final NotificationVisibility nv = NotificationVisibility.obtain(n.getKey(), rank, count, - true); + true, location); removeNotificationInternal( n.getKey(), null, nv, false /* forceRemove */, true /* removedByUser */); } 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 76d394d197eb..9b1a2aad2cc7 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 @@ -32,7 +32,6 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; -import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import com.android.systemui.UiOffloadThread; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.StatusBarStateController; @@ -40,6 +39,8 @@ import com.android.systemui.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -128,7 +129,8 @@ public class NotificationLogger implements StateListener { NotificationEntry entry = activeNotifications.get(i); String key = entry.notification.getKey(); boolean isVisible = mListContainer.isInVisibleLocation(entry); - NotificationVisibility visObj = NotificationVisibility.obtain(key, i, N, isVisible); + NotificationVisibility visObj = NotificationVisibility.obtain(key, i, N, isVisible, + getNotificationLocation(entry)); boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(visObj); if (isVisible) { // Build new set of visible notifications. @@ -160,6 +162,40 @@ public class NotificationLogger implements StateListener { } }; + /** + * Returns the location of the notification referenced by the given {@link NotificationEntry}. + */ + public static NotificationVisibility.NotificationLocation getNotificationLocation( + NotificationEntry entry) { + ExpandableNotificationRow row = entry.getRow(); + ExpandableViewState childViewState = row.getViewState(); + + if (childViewState == null) { + return NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN; + } + return convertNotificationLocation(childViewState.location); + } + + private static NotificationVisibility.NotificationLocation convertNotificationLocation( + int location) { + switch (location) { + case ExpandableViewState.LOCATION_FIRST_HUN: + return NotificationVisibility.NotificationLocation.LOCATION_FIRST_HEADS_UP; + case ExpandableViewState.LOCATION_HIDDEN_TOP: + return NotificationVisibility.NotificationLocation.LOCATION_HIDDEN_TOP; + case ExpandableViewState.LOCATION_MAIN_AREA: + return NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA; + case ExpandableViewState.LOCATION_BOTTOM_STACK_PEEKING: + return NotificationVisibility.NotificationLocation.LOCATION_BOTTOM_STACK_PEEKING; + case ExpandableViewState.LOCATION_BOTTOM_STACK_HIDDEN: + return NotificationVisibility.NotificationLocation.LOCATION_BOTTOM_STACK_HIDDEN; + case ExpandableViewState.LOCATION_GONE: + return NotificationVisibility.NotificationLocation.LOCATION_GONE; + default: + return NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN; + } + } + @Inject public NotificationLogger(NotificationListener notificationListener, UiOffloadThread uiOffloadThread, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index 4f61009095c7..86326beb8b00 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -64,6 +64,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; 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.policy.HeadsUpUtil; import com.android.systemui.statusbar.policy.KeyguardMonitor; @@ -304,8 +305,11 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit final int count = mEntryManager.getNotificationData().getActiveNotifications().size(); final int rank = mEntryManager.getNotificationData().getRank(notificationKey); + NotificationVisibility.NotificationLocation location = + NotificationLogger.getNotificationLocation( + mEntryManager.getNotificationData().get(notificationKey)); final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey, - rank, count, true); + rank, count, true, location); try { mBarService.onNotificationClick(notificationKey, nv); } catch (RemoteException ex) { |