summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Selim Cinek <cinek@google.com> 2017-05-08 21:11:31 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2017-05-08 21:11:37 +0000
commit03fbdbe6ffc769f864f62a5cd87183b9b299fe30 (patch)
treea772f4a28e60e9aef746f6aa463f21d2ae024d66
parentf0de5cdd9ab79126efcfe56788fc9756e1d8de1d (diff)
parentac5f02749a595d39711beb4a1defb01949eb548a (diff)
Merge changes from topic 'background_inflation' into oc-dev
* changes: Fixed the contrast for low-priority notifications Moving Row inflation to the background too Moving the inflation to the background
-rw-r--r--core/java/android/app/Notification.java42
-rw-r--r--core/java/com/android/internal/util/NotificationColorUtil.java49
-rw-r--r--packages/SystemUI/Android.mk1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/Abortable.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java510
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/RowInflaterTask.java65
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java90
-rw-r--r--packages/SystemUI/tests/Android.mk1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java12
13 files changed, 635 insertions, 204 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 2e56bcf8a3de..0041879453a8 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2675,6 +2675,7 @@ public class Notification implements Parcelable
private int mActionBarColor = COLOR_INVALID;
private int mBackgroundColor = COLOR_INVALID;
private int mForegroundColor = COLOR_INVALID;
+ private int mBackgroundColorHint = COLOR_INVALID;
/**
* Constructs a new Builder with the defaults:
@@ -3839,6 +3840,13 @@ public class Notification implements Parcelable
backgroundColor);
mSecondaryTextColor = NotificationColorUtil.resolveSecondaryColor(mContext,
backgroundColor);
+ if (backgroundColor != COLOR_DEFAULT
+ && (mBackgroundColorHint != COLOR_INVALID || isColorized())) {
+ mPrimaryTextColor = NotificationColorUtil.findAlphaToMeetContrast(
+ mPrimaryTextColor, backgroundColor, 4.5);
+ mSecondaryTextColor = NotificationColorUtil.findAlphaToMeetContrast(
+ mSecondaryTextColor, backgroundColor, 4.5);
+ }
} else {
double backLum = NotificationColorUtil.calculateLuminance(backgroundColor);
double textLum = NotificationColorUtil.calculateLuminance(mForegroundColor);
@@ -4662,10 +4670,26 @@ public class Notification implements Parcelable
if (mCachedContrastColorIsFor == mN.color && mCachedContrastColor != COLOR_INVALID) {
return mCachedContrastColor;
}
- final int contrasted = NotificationColorUtil.resolveContrastColor(mContext, mN.color);
+ int color;
+ int background = mBackgroundColorHint;
+ if (mBackgroundColorHint == COLOR_INVALID) {
+ background = mContext.getColor(
+ com.android.internal.R.color.notification_material_background_color);
+ }
+ if (mN.color == COLOR_DEFAULT) {
+ ensureColors();
+ color = mSecondaryTextColor;
+ } else {
+ color = NotificationColorUtil.resolveContrastColor(mContext, mN.color,
+ background);
+ }
+ if (Color.alpha(color) < 255) {
+ // alpha doesn't go well for color filters, so let's blend it manually
+ color = NotificationColorUtil.compositeColors(color, background);
+ }
mCachedContrastColorIsFor = mN.color;
- return mCachedContrastColor = contrasted;
+ return mCachedContrastColor = color;
}
int resolveAmbientColor() {
@@ -4882,7 +4906,8 @@ public class Notification implements Parcelable
if (isColorized()) {
return mBackgroundColor != COLOR_INVALID ? mBackgroundColor : mN.color;
} else {
- return COLOR_DEFAULT;
+ return mBackgroundColorHint != COLOR_INVALID ? mBackgroundColorHint
+ : COLOR_DEFAULT;
}
}
@@ -4913,6 +4938,17 @@ public class Notification implements Parcelable
mTextColorsAreForBackground = COLOR_INVALID;
ensureColors();
}
+
+ /**
+ * Sets the background color for this notification to be a different one then the default.
+ * This is mainly used to calculate contrast and won't necessarily be applied to the
+ * background.
+ *
+ * @hide
+ */
+ public void setBackgroundColorHint(int backgroundColor) {
+ mBackgroundColorHint = backgroundColor;
+ }
}
/**
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index 2c97f8bd5971..cd41f9e9f902 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -286,6 +286,38 @@ public class NotificationColorUtil {
}
/**
+ * Finds a suitable alpha such that there's enough contrast.
+ *
+ * @param color the color to start searching from.
+ * @param backgroundColor the color to ensure contrast against.
+ * @param minRatio the minimum contrast ratio required.
+ * @return the same color as {@param color} with potentially modified alpha to meet contrast
+ */
+ public static int findAlphaToMeetContrast(int color, int backgroundColor, double minRatio) {
+ int fg = color;
+ int bg = backgroundColor;
+ if (ColorUtilsFromCompat.calculateContrast(fg, bg) >= minRatio) {
+ return color;
+ }
+ int startAlpha = Color.alpha(color);
+ int r = Color.red(color);
+ int g = Color.green(color);
+ int b = Color.blue(color);
+
+ int low = startAlpha, high = 255;
+ for (int i = 0; i < 15 && high - low > 0; i++) {
+ final int alpha = (low + high) / 2;
+ fg = Color.argb(alpha, r, g, b);
+ if (ColorUtilsFromCompat.calculateContrast(fg, bg) > minRatio) {
+ high = alpha;
+ } else {
+ low = alpha;
+ }
+ }
+ return Color.argb(high, r, g, b);
+ }
+
+ /**
* Finds a suitable color such that there's enough contrast.
*
* @param color the color to start searching from.
@@ -373,19 +405,19 @@ public class NotificationColorUtil {
* color for the Notification's action and header text.
*
* @param notificationColor the color of the notification or {@link Notification#COLOR_DEFAULT}
+ * @param backgroundColor the background color to ensure the contrast against.
* @return a color of the same hue with enough contrast against the backgrounds.
*/
- public static int resolveContrastColor(Context context, int notificationColor) {
+ public static int resolveContrastColor(Context context, int notificationColor,
+ int backgroundColor) {
final int resolvedColor = resolveColor(context, notificationColor);
final int actionBg = context.getColor(
com.android.internal.R.color.notification_action_list);
- final int notiBg = context.getColor(
- com.android.internal.R.color.notification_material_background_color);
int color = resolvedColor;
color = NotificationColorUtil.ensureLargeTextContrast(color, actionBg);
- color = NotificationColorUtil.ensureTextContrast(color, notiBg);
+ color = NotificationColorUtil.ensureTextContrast(color, backgroundColor);
if (color != resolvedColor) {
if (DEBUG){
@@ -394,7 +426,7 @@ public class NotificationColorUtil {
+ " and %s (over background) by changing #%s to %s",
context.getPackageName(),
NotificationColorUtil.contrastChange(resolvedColor, color, actionBg),
- NotificationColorUtil.contrastChange(resolvedColor, color, notiBg),
+ NotificationColorUtil.contrastChange(resolvedColor, color, backgroundColor),
Integer.toHexString(resolvedColor), Integer.toHexString(color)));
}
}
@@ -502,6 +534,13 @@ public class NotificationColorUtil {
}
/**
+ * Composite two potentially translucent colors over each other and returns the result.
+ */
+ public static int compositeColors(int foreground, int background) {
+ return ColorUtilsFromCompat.compositeColors(foreground, background);
+ }
+
+ /**
* Framework copy of functions needed from android.support.v4.graphics.ColorUtils.
*/
private static class ColorUtilsFromCompat {
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 5ee0c64c9591..2fd7e87a683e 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -31,6 +31,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-unde
LOCAL_STATIC_ANDROID_LIBRARIES := \
SystemUIPluginLib \
+ android-support-v4 \
android-support-v7-recyclerview \
android-support-v7-preference \
android-support-v7-appcompat \
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/Abortable.java b/packages/SystemUI/src/com/android/systemui/statusbar/Abortable.java
new file mode 100644
index 000000000000..d5ec4f67e82d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/Abortable.java
@@ -0,0 +1,24 @@
+/*
+ * 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.systemui.statusbar;
+
+/**
+ * An interface that allows aborting existing operations.
+ */
+public interface Abortable {
+ void abort();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index d7eab9772677..b91561e01290 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -891,7 +891,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
* @return the calculated background color
*/
private int calculateBgColor(boolean withTint, boolean withOverRide) {
- if (mDark) {
+ if (withTint && mDark) {
return getContext().getColor(R.color.notification_material_background_dark_color);
}
if (withOverRide && mOverrideTint != NO_COLOR) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 8c1b334fe570..93687478fc86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -355,7 +355,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
NotificationColorUtil.getInstance(mContext));
int color = StatusBarIconView.NO_COLOR;
if (colorize) {
- color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded());
+ color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded(),
+ getBackgroundColorWithoutTint());
}
expandedIcon.setStaticDrawableColor(color);
}
@@ -859,7 +860,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private void updateNotificationColor() {
mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
- getStatusBarNotification().getNotification().color);
+ getStatusBarNotification().getNotification().color,
+ getBackgroundColorWithoutTint());
}
public HybridNotificationView getSingleLineView() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 540c39150188..f8bad053c3ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -33,7 +33,6 @@ import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.view.View;
import android.widget.ImageView;
import android.widget.RemoteViews;
@@ -43,7 +42,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.statusbar.notification.InflationException;
-import com.android.systemui.statusbar.notification.NotificationInflater;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -86,7 +84,7 @@ public class NotificationData {
public List<SnoozeCriterion> snoozeCriteria;
private int mCachedContrastColor = COLOR_INVALID;
private int mCachedContrastColorIsFor = COLOR_INVALID;
- private ArraySet<AsyncTask> mRunningTasks = new ArraySet();
+ private Abortable mRunningTask = null;
public Entry(StatusBarNotification n) {
this.key = n.getKey();
@@ -203,13 +201,15 @@ public class NotificationData {
}
}
- public int getContrastedColor(Context context, boolean ambient) {
- int rawColor = ambient ? Notification.COLOR_DEFAULT :
+ public int getContrastedColor(Context context, boolean isLowPriority,
+ int backgroundColor) {
+ int rawColor = isLowPriority ? Notification.COLOR_DEFAULT :
notification.getNotification().color;
if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) {
return mCachedContrastColor;
}
- final int contrasted = NotificationColorUtil.resolveContrastColor(context, rawColor);
+ final int contrasted = NotificationColorUtil.resolveContrastColor(context, rawColor,
+ backgroundColor);
mCachedContrastColorIsFor = rawColor;
mCachedContrastColor = contrasted;
return mCachedContrastColor;
@@ -218,24 +218,26 @@ public class NotificationData {
/**
* Abort all existing inflation tasks
*/
- public void abortInflation() {
- for (AsyncTask task : mRunningTasks) {
- task.cancel(true /* mayInterruptIfRunning */);
+ public void abortTask() {
+ if (mRunningTask != null) {
+ mRunningTask.abort();
+ mRunningTask = null;
}
- mRunningTasks.clear();
}
- public void addInflationTask(AsyncTask asyncInflationTask) {
- mRunningTasks.add(asyncInflationTask);
+ public void setInflationTask(Abortable abortableTask) {
+ // abort any existing inflation
+ abortTask();
+ mRunningTask = abortableTask;
}
- public void onInflationTaskFinished(AsyncTask asyncInflationTask) {
- mRunningTasks.remove(asyncInflationTask);
+ public void onInflationTaskFinished() {
+ mRunningTask = null;
}
@VisibleForTesting
- public ArraySet<AsyncTask> getRunningTasks() {
- return mRunningTasks;
+ public Abortable getRunningTask() {
+ return mRunningTask;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
index 4305bdef6fef..dc538dac6856 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
@@ -35,6 +35,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Handler;
+import android.os.Looper;
import android.util.Log;
import android.service.notification.StatusBarNotification;
import android.view.LayoutInflater;
@@ -107,7 +108,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl
mHorizSpaceForIcon = res.getDimensionPixelSize(R.dimen.notification_menu_icon_size);
mVertSpaceForIcons = res.getDimensionPixelSize(R.dimen.notification_min_height);
mIconPadding = res.getDimensionPixelSize(R.dimen.notification_menu_icon_padding);
- mHandler = new Handler();
+ mHandler = new Handler(Looper.getMainLooper());
mMenuItems = new ArrayList<>();
mSnoozeItem = createSnoozeItem(context);
mInfoItem = createInfoItem(context);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
index 7cfc767f89b7..f1c26cd2daa8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
@@ -16,19 +16,26 @@
package com.android.systemui.statusbar.notification;
+import android.annotation.Nullable;
import android.app.Notification;
import android.content.Context;
import android.os.AsyncTask;
+import android.os.CancellationSignal;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.Abortable;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationContentView;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.util.Assert;
+
+import java.util.HashMap;
/**
* A utility that inflates the right kind of contentView based on the state
@@ -116,126 +123,303 @@ public class NotificationInflater {
@VisibleForTesting
void inflateNotificationViews(int reInflateFlags) {
StatusBarNotification sbn = mRow.getEntry().notification;
- new AsyncInflationTask(mRow.getContext(), sbn, reInflateFlags).execute();
+ new AsyncInflationTask(sbn, reInflateFlags, mRow, mIsLowPriority,
+ mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient,
+ mCallback, mRemoteViewClickHandler).execute();
}
@VisibleForTesting
- void inflateNotificationViews(int reInflateFlags,
+ InflationProgress inflateNotificationViews(int reInflateFlags,
Notification.Builder builder, Context packageContext) {
- NotificationData.Entry entry = mRow.getEntry();
- NotificationContentView privateLayout = mRow.getPrivateLayout();
- NotificationContentView publicLayout = mRow.getPublicLayout();
+ InflationProgress result = createRemoteViews(reInflateFlags, builder, mIsLowPriority,
+ mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight,
+ mRedactAmbient, packageContext);
+ apply(result, reInflateFlags, mRow, mRedactAmbient, mRemoteViewClickHandler, null);
+ return result;
+ }
- boolean isLowPriority = mIsLowPriority && !mIsChildInGroup;
+ private static InflationProgress createRemoteViews(int reInflateFlags,
+ Notification.Builder builder, boolean isLowPriority, boolean isChildInGroup,
+ boolean usesIncreasedHeight, boolean usesIncreasedHeadsUpHeight, boolean redactAmbient,
+ Context packageContext) {
+ InflationProgress result = new InflationProgress();
+ isLowPriority = isLowPriority && !isChildInGroup;
if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) {
- final RemoteViews newContentView = createContentView(builder,
- isLowPriority, mUsesIncreasedHeight);
- if (!compareRemoteViews(newContentView,
- entry.cachedContentView)) {
- View contentViewLocal = newContentView.apply(
- packageContext,
- privateLayout,
- mRemoteViewClickHandler);
- contentViewLocal.setIsRootNamespace(true);
- privateLayout.setContractedChild(contentViewLocal);
- } else {
- newContentView.reapply(packageContext,
- privateLayout.getContractedChild(),
- mRemoteViewClickHandler);
- }
- entry.cachedContentView = newContentView;
+ result.newContentView = createContentView(builder, isLowPriority, usesIncreasedHeight);
}
if ((reInflateFlags & FLAG_REINFLATE_EXPANDED_VIEW) != 0) {
- final RemoteViews newBigContentView = createBigContentView(
- builder, isLowPriority);
- if (newBigContentView != null) {
- if (!compareRemoteViews(newBigContentView, entry.cachedBigContentView)) {
- View bigContentViewLocal = newBigContentView.apply(
- packageContext,
- privateLayout,
- mRemoteViewClickHandler);
- bigContentViewLocal.setIsRootNamespace(true);
- privateLayout.setExpandedChild(bigContentViewLocal);
- } else {
- newBigContentView.reapply(packageContext,
- privateLayout.getExpandedChild(),
- mRemoteViewClickHandler);
- }
- } else if (entry.cachedBigContentView != null) {
- privateLayout.setExpandedChild(null);
- }
- entry.cachedBigContentView = newBigContentView;
- mRow.setExpandable(newBigContentView != null);
+ result.newExpandedView = createExpandedView(builder, isLowPriority);
}
if ((reInflateFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) {
- final RemoteViews newHeadsUpContentView =
- builder.createHeadsUpContentView(mUsesIncreasedHeadsUpHeight);
- if (newHeadsUpContentView != null) {
- if (!compareRemoteViews(newHeadsUpContentView,
- entry.cachedHeadsUpContentView)) {
- View headsUpContentViewLocal = newHeadsUpContentView.apply(
- packageContext,
- privateLayout,
- mRemoteViewClickHandler);
- headsUpContentViewLocal.setIsRootNamespace(true);
- privateLayout.setHeadsUpChild(headsUpContentViewLocal);
- } else {
- newHeadsUpContentView.reapply(packageContext,
- privateLayout.getHeadsUpChild(),
- mRemoteViewClickHandler);
- }
- } else if (entry.cachedHeadsUpContentView != null) {
- privateLayout.setHeadsUpChild(null);
- }
- entry.cachedHeadsUpContentView = newHeadsUpContentView;
+ result.newHeadsUpView = builder.createHeadsUpContentView(usesIncreasedHeadsUpHeight);
}
if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) {
- final RemoteViews newPublicNotification
- = builder.makePublicContentView();
- if (!compareRemoteViews(newPublicNotification, entry.cachedPublicContentView)) {
- View publicContentView = newPublicNotification.apply(
- packageContext,
- publicLayout,
- mRemoteViewClickHandler);
- publicContentView.setIsRootNamespace(true);
- publicLayout.setContractedChild(publicContentView);
- } else {
- newPublicNotification.reapply(packageContext,
- publicLayout.getContractedChild(),
- mRemoteViewClickHandler);
- }
- entry.cachedPublicContentView = newPublicNotification;
+ result.newPublicView = builder.makePublicContentView();
}
if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) {
- final RemoteViews newAmbientNotification = mRedactAmbient
- ? builder.makePublicAmbientNotification()
+ result.newAmbientView = redactAmbient ? builder.makePublicAmbientNotification()
: builder.makeAmbientNotification();
- NotificationContentView newParent = mRedactAmbient ? publicLayout : privateLayout;
- NotificationContentView otherParent = !mRedactAmbient ? publicLayout : privateLayout;
-
- if (newParent.getAmbientChild() == null ||
- !compareRemoteViews(newAmbientNotification, entry.cachedAmbientContentView)) {
- View ambientContentView = newAmbientNotification.apply(
- packageContext,
- newParent,
- mRemoteViewClickHandler);
- ambientContentView.setIsRootNamespace(true);
- newParent.setAmbientChild(ambientContentView);
- otherParent.setAmbientChild(null);
- } else {
- newAmbientNotification.reapply(packageContext,
- newParent.getAmbientChild(),
- mRemoteViewClickHandler);
+ }
+ result.packageContext = packageContext;
+ return result;
+ }
+
+ public static CancellationSignal apply(InflationProgress result, int reInflateFlags,
+ ExpandableNotificationRow row, boolean redactAmbient,
+ RemoteViews.OnClickHandler remoteViewClickHandler,
+ @Nullable InflationCallback callback) {
+ NotificationData.Entry entry = row.getEntry();
+ NotificationContentView privateLayout = row.getPrivateLayout();
+ NotificationContentView publicLayout = row.getPublicLayout();
+ final HashMap<Integer, CancellationSignal> runningInflations = new HashMap<>();
+
+ int flag = FLAG_REINFLATE_CONTENT_VIEW;
+ if ((reInflateFlags & flag) != 0) {
+ boolean isNewView = !compareRemoteViews(result.newContentView, entry.cachedContentView);
+ ApplyCallback applyCallback = new ApplyCallback() {
+ @Override
+ public void setResultView(View v) {
+ result.inflatedContentView = v;
+ }
+
+ @Override
+ public RemoteViews getRemoteView() {
+ return result.newContentView;
+ }
+ };
+ applyRemoteView(result, reInflateFlags, flag, row, redactAmbient,
+ isNewView, remoteViewClickHandler, callback, entry, privateLayout,
+ privateLayout.getContractedChild(),
+ runningInflations, applyCallback);
+ }
+
+ flag = FLAG_REINFLATE_EXPANDED_VIEW;
+ if ((reInflateFlags & flag) != 0) {
+ if (result.newExpandedView != null) {
+ boolean isNewView = !compareRemoteViews(result.newExpandedView,
+ entry.cachedBigContentView);
+ ApplyCallback applyCallback = new ApplyCallback() {
+ @Override
+ public void setResultView(View v) {
+ result.inflatedExpandedView = v;
+ }
+
+ @Override
+ public RemoteViews getRemoteView() {
+ return result.newExpandedView;
+ }
+ };
+ applyRemoteView(result, reInflateFlags, flag, row,
+ redactAmbient, isNewView, remoteViewClickHandler, callback, entry,
+ privateLayout, privateLayout.getExpandedChild(), runningInflations,
+ applyCallback);
}
- entry.cachedAmbientContentView = newAmbientNotification;
}
+
+ flag = FLAG_REINFLATE_HEADS_UP_VIEW;
+ if ((reInflateFlags & flag) != 0) {
+ if (result.newHeadsUpView != null) {
+ boolean isNewView = !compareRemoteViews(result.newHeadsUpView,
+ entry.cachedHeadsUpContentView);
+ ApplyCallback applyCallback = new ApplyCallback() {
+ @Override
+ public void setResultView(View v) {
+ result.inflatedHeadsUpView = v;
+ }
+
+ @Override
+ public RemoteViews getRemoteView() {
+ return result.newHeadsUpView;
+ }
+ };
+ applyRemoteView(result, reInflateFlags, flag, row,
+ redactAmbient, isNewView, remoteViewClickHandler, callback, entry,
+ privateLayout, privateLayout.getHeadsUpChild(), runningInflations,
+ applyCallback);
+ }
+ }
+
+ flag = FLAG_REINFLATE_PUBLIC_VIEW;
+ if ((reInflateFlags & flag) != 0) {
+ boolean isNewView = !compareRemoteViews(result.newPublicView,
+ entry.cachedPublicContentView);
+ ApplyCallback applyCallback = new ApplyCallback() {
+ @Override
+ public void setResultView(View v) {
+ result.inflatedPublicView = v;
+ }
+
+ @Override
+ public RemoteViews getRemoteView() {
+ return result.newPublicView;
+ }
+ };
+ applyRemoteView(result, reInflateFlags, flag, row,
+ redactAmbient, isNewView, remoteViewClickHandler, callback, entry,
+ publicLayout, publicLayout.getContractedChild(), runningInflations,
+ applyCallback);
+ }
+
+ flag = FLAG_REINFLATE_AMBIENT_VIEW;
+ if ((reInflateFlags & flag) != 0) {
+ NotificationContentView newParent = redactAmbient ? publicLayout : privateLayout;
+ boolean isNewView = !canReapplyAmbient(row, redactAmbient) ||
+ !compareRemoteViews(result.newAmbientView, entry.cachedAmbientContentView);
+ ApplyCallback applyCallback = new ApplyCallback() {
+ @Override
+ public void setResultView(View v) {
+ result.inflatedAmbientView = v;
+ }
+
+ @Override
+ public RemoteViews getRemoteView() {
+ return result.newAmbientView;
+ }
+ };
+ applyRemoteView(result, reInflateFlags, flag, row,
+ redactAmbient, isNewView, remoteViewClickHandler, callback, entry,
+ newParent, newParent.getAmbientChild(), runningInflations,
+ applyCallback);
+ }
+
+ // Let's try to finish, maybe nobody is even inflating anything
+ finishIfDone(result, reInflateFlags, runningInflations, callback, row,
+ redactAmbient);
+ CancellationSignal cancellationSignal = new CancellationSignal();
+ cancellationSignal.setOnCancelListener(
+ () -> runningInflations.values().forEach(CancellationSignal::cancel));
+ return cancellationSignal;
+ }
+
+ private static void applyRemoteView(final InflationProgress result,
+ final int reInflateFlags, int inflationId,
+ final ExpandableNotificationRow row,
+ final boolean redactAmbient, boolean isNewView,
+ RemoteViews.OnClickHandler remoteViewClickHandler,
+ @Nullable final InflationCallback callback, NotificationData.Entry entry,
+ NotificationContentView parentLayout, View existingView,
+ final HashMap<Integer, CancellationSignal> runningInflations,
+ ApplyCallback applyCallback) {
+ RemoteViews.OnViewAppliedListener listener
+ = new RemoteViews.OnViewAppliedListener() {
+
+ @Override
+ public void onViewApplied(View v) {
+ if (isNewView) {
+ v.setIsRootNamespace(true);
+ applyCallback.setResultView(v);
+ }
+ runningInflations.remove(inflationId);
+ finishIfDone(result, reInflateFlags, runningInflations, callback, row,
+ redactAmbient);
+ }
+
+ @Override
+ public void onError(Exception e) {
+ runningInflations.remove(inflationId);
+ handleInflationError(runningInflations, e, entry.notification, callback);
+ }
+ };
+ CancellationSignal cancellationSignal;
+ RemoteViews newContentView = applyCallback.getRemoteView();
+ if (isNewView) {
+ cancellationSignal = newContentView.applyAsync(
+ result.packageContext,
+ parentLayout,
+ null /* executor */,
+ listener,
+ remoteViewClickHandler);
+ } else {
+ cancellationSignal = newContentView.reapplyAsync(
+ result.packageContext,
+ existingView,
+ null /* executor */,
+ listener,
+ remoteViewClickHandler);
+ }
+ runningInflations.put(inflationId, cancellationSignal);
}
- private RemoteViews createBigContentView(Notification.Builder builder,
+ private static void handleInflationError(HashMap<Integer, CancellationSignal> runningInflations,
+ Exception e, StatusBarNotification notification, @Nullable InflationCallback callback) {
+ Assert.isMainThread();
+ runningInflations.values().forEach(CancellationSignal::cancel);
+ if (callback != null) {
+ callback.handleInflationException(notification, e);
+ }
+ }
+
+ /**
+ * Finish the inflation of the views
+ *
+ * @return true if the inflation was finished
+ */
+ private static boolean finishIfDone(InflationProgress result, int reInflateFlags,
+ HashMap<Integer, CancellationSignal> runningInflations,
+ @Nullable InflationCallback endListener, ExpandableNotificationRow row,
+ boolean redactAmbient) {
+ Assert.isMainThread();
+ NotificationData.Entry entry = row.getEntry();
+ NotificationContentView privateLayout = row.getPrivateLayout();
+ NotificationContentView publicLayout = row.getPublicLayout();
+ if (runningInflations.isEmpty()) {
+ if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) {
+ if (result.inflatedContentView != null) {
+ privateLayout.setContractedChild(result.inflatedContentView);
+ }
+ entry.cachedContentView = result.newContentView;
+ }
+
+ if ((reInflateFlags & FLAG_REINFLATE_EXPANDED_VIEW) != 0) {
+ if (result.inflatedExpandedView != null) {
+ privateLayout.setExpandedChild(result.inflatedExpandedView);
+ } else if (result.newExpandedView == null) {
+ privateLayout.setExpandedChild(null);
+ }
+ entry.cachedBigContentView = result.newExpandedView;
+ row.setExpandable(result.newExpandedView != null);
+ }
+
+ if ((reInflateFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) {
+ if (result.inflatedHeadsUpView != null) {
+ privateLayout.setHeadsUpChild(result.inflatedHeadsUpView);
+ } else if (result.newHeadsUpView == null) {
+ privateLayout.setHeadsUpChild(null);
+ }
+ entry.cachedHeadsUpContentView = result.newHeadsUpView;
+ }
+
+ if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) {
+ if (result.inflatedPublicView != null) {
+ publicLayout.setContractedChild(result.inflatedPublicView);
+ }
+ entry.cachedPublicContentView = result.newPublicView;
+ }
+
+ if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) {
+ if (result.inflatedAmbientView != null) {
+ NotificationContentView newParent = redactAmbient
+ ? publicLayout : privateLayout;
+ NotificationContentView otherParent = !redactAmbient
+ ? publicLayout : privateLayout;
+ newParent.setAmbientChild(result.inflatedAmbientView);
+ otherParent.setAmbientChild(null);
+ }
+ entry.cachedAmbientContentView = result.newAmbientView;
+ }
+ if (endListener != null) {
+ endListener.onAsyncInflationFinished(row.getEntry());
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private static RemoteViews createExpandedView(Notification.Builder builder,
boolean isLowPriority) {
RemoteViews bigContentView = builder.createBigContentView();
if (bigContentView != null) {
@@ -249,7 +433,7 @@ public class NotificationInflater {
return null;
}
- private RemoteViews createContentView(Notification.Builder builder,
+ private static RemoteViews createContentView(Notification.Builder builder,
boolean isLowPriority, boolean useLarge) {
if (isLowPriority) {
return builder.makeLowPriorityContentView(false /* useRegularSubtext */);
@@ -258,7 +442,7 @@ public class NotificationInflater {
}
// Returns true if the RemoteViews are the same.
- private boolean compareRemoteViews(final RemoteViews a, final RemoteViews b) {
+ private static boolean compareRemoteViews(final RemoteViews a, final RemoteViews b) {
return (a == null && b == null) ||
(a != null && b != null
&& b.getPackage() != null
@@ -272,7 +456,7 @@ public class NotificationInflater {
}
public interface InflationCallback {
- void handleInflationException(StatusBarNotification notification, InflationException e);
+ void handleInflationException(StatusBarNotification notification, Exception e);
void onAsyncInflationFinished(NotificationData.Entry entry);
}
@@ -286,37 +470,73 @@ public class NotificationInflater {
inflateNotificationViews();
}
- private class AsyncInflationTask extends AsyncTask<Void, Void, Notification.Builder> {
+ private static boolean canReapplyAmbient(ExpandableNotificationRow row, boolean redactAmbient) {
+ NotificationContentView ambientView = redactAmbient ? row.getPublicLayout()
+ : row.getPrivateLayout(); ;
+ return ambientView.getAmbientChild() != null;
+ }
+
+ public static class AsyncInflationTask extends AsyncTask<Void, Void, InflationProgress>
+ implements InflationCallback, Abortable {
private final StatusBarNotification mSbn;
private final Context mContext;
private final int mReInflateFlags;
- private Context mPackageContext = null;
+ private final boolean mIsLowPriority;
+ private final boolean mIsChildInGroup;
+ private final boolean mUsesIncreasedHeight;
+ private final InflationCallback mCallback;
+ private final boolean mUsesIncreasedHeadsUpHeight;
+ private final boolean mRedactAmbient;
+ private ExpandableNotificationRow mRow;
private Exception mError;
-
- private AsyncInflationTask(Context context, StatusBarNotification notification,
- int reInflateFlags) {
+ private RemoteViews.OnClickHandler mRemoteViewClickHandler;
+ private CancellationSignal mCancellationSignal;
+
+ private AsyncInflationTask(StatusBarNotification notification,
+ int reInflateFlags, ExpandableNotificationRow row, boolean isLowPriority,
+ boolean isChildInGroup, boolean usesIncreasedHeight,
+ boolean usesIncreasedHeadsUpHeight, boolean redactAmbient,
+ InflationCallback callback,
+ RemoteViews.OnClickHandler remoteViewClickHandler) {
+ mRow = row;
+ NotificationData.Entry entry = row.getEntry();
+ entry.setInflationTask(this);
mSbn = notification;
- mContext = context;
mReInflateFlags = reInflateFlags;
- mRow.getEntry().addInflationTask(this);
+ mContext = mRow.getContext();
+ mIsLowPriority = isLowPriority;
+ mIsChildInGroup = isChildInGroup;
+ mUsesIncreasedHeight = usesIncreasedHeight;
+ mUsesIncreasedHeadsUpHeight = usesIncreasedHeadsUpHeight;
+ mRedactAmbient = redactAmbient;
+ mRemoteViewClickHandler = remoteViewClickHandler;
+ mCallback = callback;
}
@Override
- protected Notification.Builder doInBackground(Void... params) {
+ protected InflationProgress doInBackground(Void... params) {
try {
final Notification.Builder recoveredBuilder
= Notification.Builder.recoverBuilder(mContext,
mSbn.getNotification());
- mPackageContext = mSbn.getPackageContext(mContext);
+ Context packageContext = mSbn.getPackageContext(mContext);
Notification notification = mSbn.getNotification();
+ if (mIsLowPriority) {
+ int backgroundColor = mContext.getColor(
+ R.color.notification_material_background_low_priority_color);
+ recoveredBuilder.setBackgroundColorHint(backgroundColor);
+ }
if (notification.isMediaNotification()) {
MediaNotificationProcessor processor = new MediaNotificationProcessor(mContext,
- mPackageContext);
+ packageContext);
processor.setIsLowPriority(mIsLowPriority);
processor.processNotification(notification, recoveredBuilder);
}
- return recoveredBuilder;
+ return createRemoteViews(mReInflateFlags,
+ recoveredBuilder, mIsLowPriority, mIsChildInGroup,
+ mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient,
+ packageContext);
} catch (Exception e) {
mError = e;
return null;
@@ -324,34 +544,64 @@ public class NotificationInflater {
}
@Override
- protected void onPostExecute(Notification.Builder builder) {
- mRow.getEntry().onInflationTaskFinished(this);
+ protected void onPostExecute(InflationProgress result) {
if (mError == null) {
- finishInflation(mReInflateFlags, builder, mPackageContext);
+ mCancellationSignal = apply(result, mReInflateFlags, mRow, mRedactAmbient,
+ mRemoteViewClickHandler, this);
} else {
handleError(mError);
}
}
- }
- private void finishInflation(int reinflationFlags, Notification.Builder builder,
- Context context) {
- try {
- inflateNotificationViews(reinflationFlags, builder, context);
- } catch (RuntimeException e){
+ private void handleError(Exception e) {
+ mRow.getEntry().onInflationTaskFinished();
+ StatusBarNotification sbn = mRow.getStatusBarNotification();
+ final String ident = sbn.getPackageName() + "/0x"
+ + Integer.toHexString(sbn.getId());
+ Log.e(StatusBar.TAG, "couldn't inflate view for notification " + ident, e);
+ mCallback.handleInflationException(sbn,
+ new InflationException("Couldn't inflate contentViews" + e));
+ }
+
+ @Override
+ public void abort() {
+ cancel(true /* mayInterruptIfRunning */);
+ if (mCancellationSignal != null) {
+ mCancellationSignal.cancel();
+ }
+ }
+
+ @Override
+ public void handleInflationException(StatusBarNotification notification, Exception e) {
handleError(e);
- return;
}
- mRow.onNotificationUpdated();
- mCallback.onAsyncInflationFinished(mRow.getEntry());
+
+ @Override
+ public void onAsyncInflationFinished(NotificationData.Entry entry) {
+ mRow.getEntry().onInflationTaskFinished();
+ mRow.onNotificationUpdated();
+ mCallback.onAsyncInflationFinished(mRow.getEntry());
+ }
+ }
+
+ private static class InflationProgress {
+ private RemoteViews newContentView;
+ private RemoteViews newHeadsUpView;
+ private RemoteViews newExpandedView;
+ private RemoteViews newAmbientView;
+ private RemoteViews newPublicView;
+
+ private Context packageContext;
+
+ private View inflatedContentView;
+ private View inflatedHeadsUpView;
+ private View inflatedExpandedView;
+ private View inflatedAmbientView;
+ private View inflatedPublicView;
}
- private void handleError(Exception e) {
- StatusBarNotification sbn = mRow.getStatusBarNotification();
- final String ident = sbn.getPackageName() + "/0x"
- + Integer.toHexString(sbn.getId());
- Log.e(StatusBar.TAG, "couldn't inflate view for notification " + ident, e);
- mCallback.handleInflationException(sbn,
- new InflationException("Couldn't inflate contentViews" + e));
+ private abstract static class ApplyCallback {
+ public abstract void setResultView(View v);
+ public abstract RemoteViews getRemoteView();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/RowInflaterTask.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/RowInflaterTask.java
new file mode 100644
index 000000000000..1bfc0cc6a6df
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/RowInflaterTask.java
@@ -0,0 +1,65 @@
+/*
+ * 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.systemui.statusbar.notification;
+
+import android.content.Context;
+import android.support.v4.view.AsyncLayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.Abortable;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.NotificationData;
+
+/**
+ * An inflater task that asynchronously inflates a ExpandableNotificationRow
+ */
+public class RowInflaterTask implements Abortable, AsyncLayoutInflater.OnInflateFinishedListener {
+ private RowInflationFinishedListener mListener;
+ private NotificationData.Entry mEntry;
+ private boolean mCancelled;
+
+ /**
+ * Inflates a new notificationView. This should not be called twice on this object
+ */
+ public void inflate(Context context, ViewGroup parent, NotificationData.Entry entry,
+ RowInflationFinishedListener listener) {
+ mListener = listener;
+ AsyncLayoutInflater inflater = new AsyncLayoutInflater(context);
+ mEntry = entry;
+ entry.setInflationTask(this);
+ inflater.inflate(R.layout.status_bar_notification_row, parent, this);
+ }
+
+ @Override
+ public void abort() {
+ mCancelled = true;
+ }
+
+ @Override
+ public void onInflateFinished(View view, int resid, ViewGroup parent) {
+ if (!mCancelled) {
+ mEntry.onInflationTaskFinished();
+ mListener.onInflationFinished((ExpandableNotificationRow) view);
+ }
+ }
+
+ public interface RowInflationFinishedListener {
+ void onInflationFinished(ExpandableNotificationRow row);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index badbcb3da845..4610bc8fe54a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -172,6 +172,7 @@ import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.InflationException;
+import com.android.systemui.statusbar.notification.RowInflaterTask;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
@@ -1588,12 +1589,12 @@ public class StatusBar extends SystemUI implements DemoMode,
private void abortExistingInflation(String key) {
if (mPendingNotifications.containsKey(key)) {
Entry entry = mPendingNotifications.get(key);
- entry.abortInflation();
+ entry.abortTask();
mPendingNotifications.remove(key);
}
Entry addedEntry = mNotificationData.get(key);
if (addedEntry != null) {
- addedEntry.abortInflation();
+ addedEntry.abortTask();
}
}
@@ -1610,7 +1611,7 @@ public class StatusBar extends SystemUI implements DemoMode,
}
@Override
- public void handleInflationException(StatusBarNotification notification, InflationException e) {
+ public void handleInflationException(StatusBarNotification notification, Exception e) {
handleNotificationError(notification, e.getMessage());
}
@@ -6172,50 +6173,57 @@ public class StatusBar extends SystemUI implements DemoMode,
entry.notification.getUser().getIdentifier());
final StatusBarNotification sbn = entry.notification;
- ExpandableNotificationRow row;
if (entry.row != null) {
- row = entry.row;
entry.reset();
+ updateNotification(entry, pmUser, sbn, entry.row);
} else {
- // create the row view
- LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row,
- parent, false);
- row.setExpansionLogger(this, entry.notification.getKey());
- row.setGroupManager(mGroupManager);
- row.setHeadsUpManager(mHeadsUpManager);
- row.setRemoteInputController(mRemoteInputController);
- row.setOnExpandClickListener(this);
- row.setRemoteViewClickHandler(mOnClickHandler);
- row.setInflationCallback(this);
-
- // Get the app name.
- // Note that Notification.Builder#bindHeaderAppName has similar logic
- // but since this field is used in the guts, it must be accurate.
- // Therefore we will only show the application label, or, failing that, the
- // package name. No substitutions.
- final String pkg = sbn.getPackageName();
- String appname = pkg;
- try {
- final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
- PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_DISABLED_COMPONENTS);
- if (info != null) {
- appname = String.valueOf(pmUser.getApplicationLabel(info));
- }
- } catch (NameNotFoundException e) {
- // Do nothing
- }
- row.setAppName(appname);
- row.setOnDismissRunnable(() ->
- performRemoveNotification(row.getStatusBarNotification()));
- row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
- if (ENABLE_REMOTE_INPUT) {
- row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+ new RowInflaterTask().inflate(mContext, parent, entry,
+ row -> {
+ bindRow(entry, pmUser, sbn, row);
+ updateNotification(entry, pmUser, sbn, row);
+ });
+ }
+
+ }
+
+ private void bindRow(Entry entry, PackageManager pmUser,
+ StatusBarNotification sbn, ExpandableNotificationRow row) {
+ row.setExpansionLogger(this, entry.notification.getKey());
+ row.setGroupManager(mGroupManager);
+ row.setHeadsUpManager(mHeadsUpManager);
+ row.setRemoteInputController(mRemoteInputController);
+ row.setOnExpandClickListener(this);
+ row.setRemoteViewClickHandler(mOnClickHandler);
+ row.setInflationCallback(this);
+
+ // Get the app name.
+ // Note that Notification.Builder#bindHeaderAppName has similar logic
+ // but since this field is used in the guts, it must be accurate.
+ // Therefore we will only show the application label, or, failing that, the
+ // package name. No substitutions.
+ final String pkg = sbn.getPackageName();
+ String appname = pkg;
+ try {
+ final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS);
+ if (info != null) {
+ appname = String.valueOf(pmUser.getApplicationLabel(info));
}
+ } catch (NameNotFoundException e) {
+ // Do nothing
+ }
+ row.setAppName(appname);
+ row.setOnDismissRunnable(() ->
+ performRemoveNotification(row.getStatusBarNotification()));
+ row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+ if (ENABLE_REMOTE_INPUT) {
+ row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
}
+ }
+ private void updateNotification(Entry entry, PackageManager pmUser,
+ StatusBarNotification sbn, ExpandableNotificationRow row) {
row.setNeedsRedaction(needsRedaction(entry));
boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey());
row.setIsLowPriority(isLowPriority);
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 5e8b3f905258..5e71dd4684c5 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -38,6 +38,7 @@ LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
LOCAL_STATIC_ANDROID_LIBRARIES := \
SystemUIPluginLib \
+ android-support-v4 \
android-support-v7-recyclerview \
android-support-v7-preference \
android-support-v7-appcompat \
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java
index fbb25e5484ba..15381b7e9425 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java
@@ -26,6 +26,7 @@ import android.app.Notification;
import android.content.Context;
import android.service.notification.StatusBarNotification;
import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.widget.RemoteViews;
@@ -41,7 +42,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.concurrent.CountDownLatch;
-import java.util.function.Function;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -67,7 +67,7 @@ public class NotificationInflaterTest {
mNotificationInflater.setInflationCallback(new NotificationInflater.InflationCallback() {
@Override
public void handleInflationException(StatusBarNotification notification,
- InflationException e) {
+ Exception e) {
}
@Override
@@ -77,6 +77,7 @@ public class NotificationInflaterTest {
}
@Test
+ @UiThreadTest
public void testIncreasedHeadsUpBeingUsed() {
mNotificationInflater.setUsesIncreasedHeadsUpHeight(true);
Notification.Builder builder = spy(mBuilder);
@@ -85,6 +86,7 @@ public class NotificationInflaterTest {
}
@Test
+ @UiThreadTest
public void testIncreasedHeightBeingUsed() {
mNotificationInflater.setUsesIncreasedHeight(true);
Notification.Builder builder = spy(mBuilder);
@@ -124,10 +126,10 @@ public class NotificationInflaterTest {
@Test
public void testAsyncTaskRemoved() throws Exception {
- mRow.getEntry().abortInflation();
+ mRow.getEntry().abortTask();
runThenWaitForInflation(() -> mNotificationInflater.inflateNotificationViews(),
mNotificationInflater);
- Assert.assertTrue(mRow.getEntry().getRunningTasks().size() == 0);
+ Assert.assertNull(mRow.getEntry().getRunningTask() );
}
public static void runThenWaitForInflation(Runnable block,
@@ -143,7 +145,7 @@ public class NotificationInflaterTest {
inflater.setInflationCallback(new NotificationInflater.InflationCallback() {
@Override
public void handleInflationException(StatusBarNotification notification,
- InflationException e) {
+ Exception e) {
if (!expectingException) {
exceptionHolder.setException(e);
}