Improve the latency of NotificationChannelSlice

Get the notification data in parallel to reduce the latency.

Fixes: 123065955
Test: visual, robotests

Change-Id: I434ec68197af214f540ba39ae9155ee7625a2742
This commit is contained in:
Yanting Yang
2019-04-17 00:28:18 +08:00
parent 4d03377901
commit 316c763316
4 changed files with 164 additions and 29 deletions

View File

@@ -66,7 +66,12 @@ import com.android.settingslib.applications.ApplicationsState;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
public class NotificationChannelSlice implements CustomSliceable {
@@ -98,6 +103,7 @@ public class NotificationChannelSlice implements CustomSliceable {
private static final String PACKAGE_NAME = "package_name";
private static final String PACKAGE_UID = "package_uid";
private static final String CHANNEL_ID = "channel_id";
private static final long TASK_TIMEOUT_MS = 100;
/**
* Sort notification channel with weekly average sent count by descending.
@@ -129,6 +135,7 @@ public class NotificationChannelSlice implements CustomSliceable {
};
protected final Context mContext;
private final ExecutorService mExecutorService;
@VisibleForTesting
NotificationBackend mNotificationBackend;
private NotificationBackend.AppRow mAppRow;
@@ -138,6 +145,7 @@ public class NotificationChannelSlice implements CustomSliceable {
public NotificationChannelSlice(Context context) {
mContext = context;
mNotificationBackend = new NotificationBackend();
mExecutorService = Executors.newCachedThreadPool();
}
@Override
@@ -151,10 +159,7 @@ public class NotificationChannelSlice implements CustomSliceable {
* 2. Multiple channels.
* 3. Sent at least ~10 notifications.
*/
// TODO(b/123065955): Review latency of NotificationChannelSlice
final List<PackageInfo> multiChannelPackages = getMultiChannelPackages(
getRecentlyInstalledPackages());
mPackageName = getMaxSentNotificationsPackage(multiChannelPackages);
mPackageName = getEligibleNotificationsPackage(getRecentlyInstalledPackages());
if (mPackageName == null) {
// Return a header with IsError flag, if package is not found.
return listBuilder.setHeader(getNoSuggestedAppHeader())
@@ -306,25 +311,6 @@ public class NotificationChannelSlice implements CustomSliceable {
return PendingIntent.getBroadcast(mContext, intent.hashCode(), intent, 0);
}
private List<PackageInfo> getMultiChannelPackages(List<PackageInfo> packageInfoList) {
final List<PackageInfo> multiChannelPackages = new ArrayList<>();
if (packageInfoList.isEmpty()) {
return multiChannelPackages;
}
for (PackageInfo packageInfo : packageInfoList) {
final int channelCount = mNotificationBackend.getChannelCount(packageInfo.packageName,
getApplicationUid(packageInfo.packageName));
if (channelCount > 1) {
multiChannelPackages.add(packageInfo);
}
}
// TODO(b/119831690): Filter the packages which doesn't have any configurable channel.
return multiChannelPackages;
}
private List<PackageInfo> getRecentlyInstalledPackages() {
final long startTime = System.currentTimeMillis() - DURATION_START_DAYS;
final long endTime = System.currentTimeMillis() - DURATION_END_DAYS;
@@ -383,19 +369,33 @@ public class NotificationChannelSlice implements CustomSliceable {
.collect(Collectors.toList());
}
private String getMaxSentNotificationsPackage(List<PackageInfo> packageInfoList) {
private String getEligibleNotificationsPackage(List<PackageInfo> packageInfoList) {
if (packageInfoList.isEmpty()) {
return null;
}
// Create tasks to get notification data for multi-channel packages.
final List<Future<NotificationBackend.AppRow>> appRowTasks = new ArrayList<>();
for (PackageInfo packageInfo : packageInfoList) {
final NotificationMultiChannelAppRow future = new NotificationMultiChannelAppRow(
mContext, mNotificationBackend, packageInfo);
appRowTasks.add(mExecutorService.submit(future));
}
// Get the package which has sent at least ~10 notifications and not turn off channels.
int maxSentCount = 0;
String maxSentCountPackage = null;
for (PackageInfo packageInfo : packageInfoList) {
final NotificationBackend.AppRow appRow = mNotificationBackend.loadAppRow(mContext,
mContext.getPackageManager(), packageInfo);
for (Future<NotificationBackend.AppRow> appRowTask : appRowTasks) {
NotificationBackend.AppRow appRow = null;
try {
appRow = appRowTask.get(TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
} catch (ExecutionException | InterruptedException | TimeoutException e) {
Log.w(TAG, "Failed to get notification data.", e);
}
// Ignore packages which are banned notifications or block all displayable channels.
if (appRow.banned || isAllChannelsBlocked(getDisplayableChannels(appRow))) {
if (appRow == null || appRow.banned || isAllChannelsBlocked(
getDisplayableChannels(appRow))) {
continue;
}
@@ -403,7 +403,7 @@ public class NotificationChannelSlice implements CustomSliceable {
final int sentCount = appRow.sentByApp.sentCount;
if (sentCount >= MIN_NOTIFICATION_SENT_COUNT && sentCount > maxSentCount) {
maxSentCount = sentCount;
maxSentCountPackage = packageInfo.packageName;
maxSentCountPackage = appRow.pkg;
mAppRow = appRow;
}
}