summaryrefslogtreecommitdiffstats
path: root/src/com/android
diff options
context:
space:
mode:
authorTony Wickham <twickham@google.com>2017-03-24 11:31:12 -0700
committerTony Wickham <twickham@google.com>2017-03-24 14:18:53 -0700
commit2f5bb169154d25bc8c164f057117fb056ad2de96 (patch)
tree04bd51eef88d60dadf5913306ac0c5aa120267a0 /src/com/android
parented68728b1f22bc849e0567f2be3aeaf6798440ca (diff)
downloadandroid_packages_apps_Trebuchet-2f5bb169154d25bc8c164f057117fb056ad2de96.tar.gz
android_packages_apps_Trebuchet-2f5bb169154d25bc8c164f057117fb056ad2de96.tar.bz2
android_packages_apps_Trebuchet-2f5bb169154d25bc8c164f057117fb056ad2de96.zip
De-dupe shortcuts with the same id as the main notification.
- Pass NotificationKeyData, which includes the shortcut id, instead of just the notification key from NotificationListener - Remove the shortcut with the same shortcut id as the first notification, if it has one, in PopupPopulator#sortAndFilterShorcuts() - Add some unit tests Bug: 36571718 Change-Id: I308941b34c525b34686583476e3f82ccb8b7e2d8
Diffstat (limited to 'src/com/android')
-rw-r--r--src/com/android/launcher3/badge/BadgeInfo.java9
-rw-r--r--src/com/android/launcher3/notification/NotificationInfo.java2
-rw-r--r--src/com/android/launcher3/notification/NotificationKeyData.java60
-rw-r--r--src/com/android/launcher3/notification/NotificationListener.java25
-rw-r--r--src/com/android/launcher3/popup/PopupContainerWithArrow.java14
-rw-r--r--src/com/android/launcher3/popup/PopupDataProvider.java24
-rw-r--r--src/com/android/launcher3/popup/PopupPopulator.java36
7 files changed, 130 insertions, 40 deletions
diff --git a/src/com/android/launcher3/badge/BadgeInfo.java b/src/com/android/launcher3/badge/BadgeInfo.java
index 532396cdd..d7aa4e8b3 100644
--- a/src/com/android/launcher3/badge/BadgeInfo.java
+++ b/src/com/android/launcher3/badge/BadgeInfo.java
@@ -25,6 +25,7 @@ import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import com.android.launcher3.notification.NotificationInfo;
+import com.android.launcher3.notification.NotificationKeyData;
import com.android.launcher3.util.PackageUserKey;
import java.util.ArrayList;
@@ -42,7 +43,7 @@ public class BadgeInfo {
* The keys of the notifications that this badge represents. These keys can later be
* used to retrieve {@link NotificationInfo}'s.
*/
- private List<String> mNotificationKeys;
+ private List<NotificationKeyData> mNotificationKeys;
/** This will only be initialized if the badge should display the notification icon. */
private NotificationInfo mNotificationInfo;
@@ -61,7 +62,7 @@ public class BadgeInfo {
/**
* Returns whether the notification was added (false if it already existed).
*/
- public boolean addNotificationKeyIfNotExists(String notificationKey) {
+ public boolean addNotificationKeyIfNotExists(NotificationKeyData notificationKey) {
if (mNotificationKeys.contains(notificationKey)) {
return false;
}
@@ -71,11 +72,11 @@ public class BadgeInfo {
/**
* Returns whether the notification was removed (false if it didn't exist).
*/
- public boolean removeNotificationKey(String notificationKey) {
+ public boolean removeNotificationKey(NotificationKeyData notificationKey) {
return mNotificationKeys.remove(notificationKey);
}
- public List<String> getNotificationKeys() {
+ public List<NotificationKeyData> getNotificationKeys() {
return mNotificationKeys;
}
diff --git a/src/com/android/launcher3/notification/NotificationInfo.java b/src/com/android/launcher3/notification/NotificationInfo.java
index ba7675c5d..f6779b331 100644
--- a/src/com/android/launcher3/notification/NotificationInfo.java
+++ b/src/com/android/launcher3/notification/NotificationInfo.java
@@ -38,7 +38,7 @@ import com.android.launcher3.util.PackageUserKey;
* only be created when we need to show the notification contents on the UI; until then, a
* {@link com.android.launcher3.badge.BadgeInfo} with only the notification key should
* be passed around, and then this can be constructed using the StatusBarNotification from
- * {@link NotificationListener#getNotificationsForKeys(String[])}.
+ * {@link NotificationListener#getNotificationsForKeys(java.util.List)}.
*/
public class NotificationInfo implements View.OnClickListener {
diff --git a/src/com/android/launcher3/notification/NotificationKeyData.java b/src/com/android/launcher3/notification/NotificationKeyData.java
new file mode 100644
index 000000000..b3ff8dadd
--- /dev/null
+++ b/src/com/android/launcher3/notification/NotificationKeyData.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.notification;
+
+import android.service.notification.StatusBarNotification;
+import android.support.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The key data associated with the notification, used to determine what to include
+ * in badges and dummy popup views before they are populated.
+ *
+ * @see NotificationInfo for the full data used when populating the dummy views.
+ */
+public class NotificationKeyData {
+ public final String notificationKey;
+ public final String shortcutId;
+
+ private NotificationKeyData(String notificationKey, String shortcutId) {
+ this.notificationKey = notificationKey;
+ this.shortcutId = shortcutId;
+ }
+
+ public static NotificationKeyData fromNotification(StatusBarNotification sbn) {
+ return new NotificationKeyData(sbn.getKey(), sbn.getNotification().getShortcutId());
+ }
+
+ public static List<String> extractKeysOnly(@NonNull List<NotificationKeyData> notificationKeys) {
+ List<String> keysOnly = new ArrayList<>(notificationKeys.size());
+ for (NotificationKeyData notificationKeyData : notificationKeys) {
+ keysOnly.add(notificationKeyData.notificationKey);
+ }
+ return keysOnly;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof NotificationKeyData)) {
+ return false;
+ }
+ // Only compare the keys.
+ return ((NotificationKeyData) obj).notificationKey.equals(notificationKey);
+ }
+}
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index 16cb5fbb0..75a1b8ab5 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -94,8 +94,8 @@ public class NotificationListener extends NotificationListenerService {
break;
case MSG_NOTIFICATION_REMOVED:
if (sNotificationsChangedListener != null) {
- Pair<PackageUserKey, String> pair
- = (Pair<PackageUserKey, String>) message.obj;
+ Pair<PackageUserKey, NotificationKeyData> pair
+ = (Pair<PackageUserKey, NotificationKeyData>) message.obj;
sNotificationsChangedListener.onNotificationRemoved(pair.first, pair.second);
}
break;
@@ -165,12 +165,12 @@ public class NotificationListener extends NotificationListenerService {
*/
private class NotificationPostedMsg {
PackageUserKey packageUserKey;
- String notificationKey;
+ NotificationKeyData notificationKey;
boolean shouldBeFilteredOut;
NotificationPostedMsg(StatusBarNotification sbn) {
packageUserKey = PackageUserKey.fromNotification(sbn);
- notificationKey = sbn.getKey();
+ notificationKey = NotificationKeyData.fromNotification(sbn);
shouldBeFilteredOut = shouldBeFilteredOut(sbn);
}
}
@@ -178,16 +178,18 @@ public class NotificationListener extends NotificationListenerService {
@Override
public void onNotificationRemoved(final StatusBarNotification sbn) {
super.onNotificationRemoved(sbn);
- Pair<PackageUserKey, String> packageUserKeyAndNotificationKey
- = new Pair<>(PackageUserKey.fromNotification(sbn), sbn.getKey());
+ Pair<PackageUserKey, NotificationKeyData> packageUserKeyAndNotificationKey
+ = new Pair<>(PackageUserKey.fromNotification(sbn),
+ NotificationKeyData.fromNotification(sbn));
mWorkerHandler.obtainMessage(MSG_NOTIFICATION_REMOVED, packageUserKeyAndNotificationKey)
.sendToTarget();
}
/** This makes a potentially expensive binder call and should be run on a background thread. */
- public List<StatusBarNotification> getNotificationsForKeys(String[] keys) {
+ public List<StatusBarNotification> getNotificationsForKeys(List<NotificationKeyData> keys) {
StatusBarNotification[] notifications = NotificationListener.this
- .getActiveNotifications(keys);
+ .getActiveNotifications(NotificationKeyData.extractKeysOnly(keys)
+ .toArray(new String[keys.size()]));
return notifications == null ? Collections.EMPTY_LIST : Arrays.asList(notifications);
}
@@ -238,9 +240,10 @@ public class NotificationListener extends NotificationListenerService {
}
public interface NotificationsChangedListener {
- void onNotificationPosted(PackageUserKey postedPackageUserKey, String notificationKey,
- boolean shouldBeFilteredOut);
- void onNotificationRemoved(PackageUserKey removedPackageUserKey, String notificationKey);
+ void onNotificationPosted(PackageUserKey postedPackageUserKey,
+ NotificationKeyData notificationKey, boolean shouldBeFilteredOut);
+ void onNotificationRemoved(PackageUserKey removedPackageUserKey,
+ NotificationKeyData notificationKey);
void onNotificationFullRefresh(List<StatusBarNotification> activeNotifications);
}
}
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 1eac07608..b2018b92b 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -65,6 +65,7 @@ import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.graphics.TriangleShape;
import com.android.launcher3.notification.NotificationItemView;
+import com.android.launcher3.notification.NotificationKeyData;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.shortcuts.ShortcutsItemView;
import com.android.launcher3.util.PackageUserKey;
@@ -138,9 +139,9 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
}
ItemInfo itemInfo = (ItemInfo) icon.getTag();
List<String> shortcutIds = launcher.getPopupDataProvider().getShortcutIdsForItem(itemInfo);
- String[] notificationKeys = launcher.getPopupDataProvider()
+ List<NotificationKeyData> notificationKeys = launcher.getPopupDataProvider()
.getNotificationKeysForItem(itemInfo);
- if (shortcutIds.size() > 0 || notificationKeys.length > 0) {
+ if (shortcutIds.size() > 0 || notificationKeys.size() > 0) {
final PopupContainerWithArrow container =
(PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
R.layout.popup_container, launcher.getDragLayer(), false);
@@ -153,7 +154,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
}
public void populateAndShow(final BubbleTextView originalIcon, final List<String> shortcutIds,
- final String[] notificationKeys) {
+ final List<NotificationKeyData> notificationKeys) {
final Resources resources = getResources();
final int arrowWidth = resources.getDimensionPixelSize(R.dimen.deep_shortcuts_arrow_width);
final int arrowHeight = resources.getDimensionPixelSize(R.dimen.deep_shortcuts_arrow_height);
@@ -165,7 +166,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
// Add dummy views first, and populate with real info when ready.
PopupPopulator.Item[] itemsToPopulate = PopupPopulator
.getItemsToPopulate(shortcutIds, notificationKeys);
- addDummyViews(originalIcon, itemsToPopulate, notificationKeys.length > 1);
+ addDummyViews(originalIcon, itemsToPopulate, notificationKeys.size() > 1);
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
orientAboutIcon(originalIcon, arrowHeight + arrowVerticalOffset);
@@ -176,7 +177,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
mNotificationItemView = null;
mShortcutsItemView = null;
itemsToPopulate = PopupPopulator.reverseItems(itemsToPopulate);
- addDummyViews(originalIcon, itemsToPopulate, notificationKeys.length > 1);
+ addDummyViews(originalIcon, itemsToPopulate, notificationKeys.size() > 1);
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
orientAboutIcon(originalIcon, arrowHeight + arrowVerticalOffset);
@@ -606,7 +607,8 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
removeNotification.start();
return;
}
- mNotificationItemView.trimNotifications(badgeInfo.getNotificationKeys());
+ mNotificationItemView.trimNotifications(NotificationKeyData.extractKeysOnly(
+ badgeInfo.getNotificationKeys()));
}
private ObjectAnimator createArrowScaleAnim(float scale) {
diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java
index f0ccb1bb6..43b2b5299 100644
--- a/src/com/android/launcher3/popup/PopupDataProvider.java
+++ b/src/com/android/launcher3/popup/PopupDataProvider.java
@@ -18,6 +18,7 @@ package com.android.launcher3.popup;
import android.content.ComponentName;
import android.service.notification.StatusBarNotification;
+import android.support.annotation.NonNull;
import android.util.Log;
import com.android.launcher3.ItemInfo;
@@ -25,6 +26,7 @@ import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.notification.NotificationInfo;
+import com.android.launcher3.notification.NotificationKeyData;
import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.util.ComponentKey;
@@ -58,8 +60,8 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan
}
@Override
- public void onNotificationPosted(PackageUserKey postedPackageUserKey, String notificationKey,
- boolean shouldBeFilteredOut) {
+ public void onNotificationPosted(PackageUserKey postedPackageUserKey,
+ NotificationKeyData notificationKey, boolean shouldBeFilteredOut) {
BadgeInfo badgeInfo = mPackageUserToBadgeInfos.get(postedPackageUserKey);
boolean notificationWasAddedOrRemoved; // As opposed to updated.
if (badgeInfo == null) {
@@ -84,7 +86,8 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan
}
@Override
- public void onNotificationRemoved(PackageUserKey removedPackageUserKey, String notificationKey) {
+ public void onNotificationRemoved(PackageUserKey removedPackageUserKey,
+ NotificationKeyData notificationKey) {
BadgeInfo oldBadgeInfo = mPackageUserToBadgeInfos.get(removedPackageUserKey);
if (oldBadgeInfo != null && oldBadgeInfo.removeNotificationKey(notificationKey)) {
if (oldBadgeInfo.getNotificationCount() == 0) {
@@ -112,7 +115,8 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan
badgeInfo = new BadgeInfo(packageUserKey);
mPackageUserToBadgeInfos.put(packageUserKey, badgeInfo);
}
- badgeInfo.addNotificationKeyIfNotExists(notification.getKey());
+ badgeInfo.addNotificationKeyIfNotExists(NotificationKeyData
+ .fromNotification(notification));
}
// Add and remove from updatedBadges so it contains the PackageUserKeys of updated badges.
@@ -177,8 +181,9 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan
NotificationInfo notificationInfo = null;
NotificationListener notificationListener = NotificationListener.getInstanceIfConnected();
if (notificationListener != null && badgeInfo.getNotificationKeys().size() == 1) {
+ String onlyNotificationKey = badgeInfo.getNotificationKeys().get(0).notificationKey;
StatusBarNotification[] activeNotifications = notificationListener
- .getActiveNotifications(new String[] {badgeInfo.getNotificationKeys().get(0)});
+ .getActiveNotifications(new String[] {onlyNotificationKey});
if (activeNotifications.length == 1) {
notificationInfo = new NotificationInfo(mLauncher, activeNotifications[0]);
if (!notificationInfo.shouldShowIconInBadge()) {
@@ -216,15 +221,14 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan
return mPackageUserToBadgeInfos.get(PackageUserKey.fromItemInfo(info));
}
- public String[] getNotificationKeysForItem(ItemInfo info) {
+ public @NonNull List<NotificationKeyData> getNotificationKeysForItem(ItemInfo info) {
BadgeInfo badgeInfo = getBadgeInfoForItem(info);
- if (badgeInfo == null) { return new String[0]; }
- List<String> notificationKeys = badgeInfo.getNotificationKeys();
- return notificationKeys.toArray(new String[notificationKeys.size()]);
+ return badgeInfo == null ? Collections.EMPTY_LIST : badgeInfo.getNotificationKeys();
}
/** This makes a potentially expensive binder call and should be run on a background thread. */
- public List<StatusBarNotification> getStatusBarNotificationsForKeys(String[] notificationKeys) {
+ public @NonNull List<StatusBarNotification> getStatusBarNotificationsForKeys(
+ List<NotificationKeyData> notificationKeys) {
NotificationListener notificationListener = NotificationListener.getInstanceIfConnected();
return notificationListener == null ? Collections.EMPTY_LIST
: notificationListener.getNotificationsForKeys(notificationKeys);
diff --git a/src/com/android/launcher3/popup/PopupPopulator.java b/src/com/android/launcher3/popup/PopupPopulator.java
index 39c2db2d5..9b2141f12 100644
--- a/src/com/android/launcher3/popup/PopupPopulator.java
+++ b/src/com/android/launcher3/popup/PopupPopulator.java
@@ -20,15 +20,18 @@ import android.content.ComponentName;
import android.os.Handler;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.notification.NotificationInfo;
import com.android.launcher3.notification.NotificationItemView;
-import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.notification.NotificationKeyData;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
@@ -36,6 +39,7 @@ import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.Iterator;
import java.util.List;
/**
@@ -58,8 +62,9 @@ public class PopupPopulator {
}
}
- public static Item[] getItemsToPopulate(List<String> shortcutIds, String[] notificationKeys) {
- boolean hasNotifications = notificationKeys.length > 0;
+ public static @NonNull Item[] getItemsToPopulate(@NonNull List<String> shortcutIds,
+ @NonNull List<NotificationKeyData> notificationKeys) {
+ boolean hasNotifications = notificationKeys.size() > 0;
int numNotificationItems = hasNotifications ? 1 : 0;
int numItems = Math.min(MAX_ITEMS, shortcutIds.size() + numNotificationItems);
Item[] items = new Item[numItems];
@@ -105,10 +110,22 @@ public class PopupPopulator {
* We want the filter to include both static and dynamic shortcuts, so we always
* include NUM_DYNAMIC dynamic shortcuts, if at least that many are present.
*
+ * @param shortcutIdToRemoveFirst An id that should be filtered out first, if any.
* @return a subset of shortcuts, in sorted order, with size <= MAX_ITEMS.
*/
public static List<ShortcutInfoCompat> sortAndFilterShortcuts(
- List<ShortcutInfoCompat> shortcuts) {
+ List<ShortcutInfoCompat> shortcuts, @Nullable String shortcutIdToRemoveFirst) {
+ // Remove up to one specific shortcut before sorting and doing somewhat fancy filtering.
+ if (shortcutIdToRemoveFirst != null) {
+ Iterator<ShortcutInfoCompat> shortcutIterator = shortcuts.iterator();
+ while (shortcutIterator.hasNext()) {
+ if (shortcutIterator.next().getId().equals(shortcutIdToRemoveFirst)) {
+ shortcutIterator.remove();
+ break;
+ }
+ }
+ }
+
Collections.sort(shortcuts, SHORTCUT_RANK_COMPARATOR);
if (shortcuts.size() <= MAX_ITEMS) {
return shortcuts;
@@ -145,7 +162,8 @@ public class PopupPopulator {
public static Runnable createUpdateRunnable(final Launcher launcher, ItemInfo originalInfo,
final Handler uiHandler, final PopupContainerWithArrow container,
final List<String> shortcutIds, final List<DeepShortcutView> shortcutViews,
- final String[] notificationKeys, final NotificationItemView notificationView) {
+ final List<NotificationKeyData> notificationKeys,
+ final NotificationItemView notificationView) {
final ComponentName activity = originalInfo.getTargetComponent();
final UserHandle user = originalInfo.user;
return new Runnable() {
@@ -162,9 +180,11 @@ public class PopupPopulator {
uiHandler.post(new UpdateNotificationChild(notificationView, infos));
}
- final List<ShortcutInfoCompat> shortcuts = PopupPopulator.sortAndFilterShortcuts(
- DeepShortcutManager.getInstance(launcher).queryForShortcutsContainer(
- activity, shortcutIds, user));
+ List<ShortcutInfoCompat> shortcuts = DeepShortcutManager.getInstance(launcher)
+ .queryForShortcutsContainer(activity, shortcutIds, user);
+ String shortcutIdToDeDupe = notificationKeys.isEmpty() ? null
+ : notificationKeys.get(0).shortcutId;
+ shortcuts = PopupPopulator.sortAndFilterShortcuts(shortcuts, shortcutIdToDeDupe);
for (int i = 0; i < shortcuts.size() && i < shortcutViews.size(); i++) {
final ShortcutInfoCompat shortcut = shortcuts.get(i);
ShortcutInfo si = new ShortcutInfo(shortcut, launcher);