Merge changes from topic 'background_inflation' into oc-dev am: 03fbdbe6ff
am: cc360f9b69
Change-Id: I456f81ff6300792e8639733d0115d878683d1694
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -285,6 +285,38 @@ public class NotificationColorUtil {
|
||||
return ColorUtilsFromCompat.LABToColor(low, a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
@@ -501,6 +533,13 @@ public class NotificationColorUtil {
|
||||
return ColorUtilsFromCompat.calculateContrast(foregroundColor, backgroundColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -362,7 +362,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);
|
||||
}
|
||||
@@ -875,7 +876,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
|
||||
private void updateNotificationColor() {
|
||||
mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
|
||||
getStatusBarNotification().getNotification().color);
|
||||
getStatusBarNotification().getNotification().color,
|
||||
getBackgroundColorWithoutTint());
|
||||
}
|
||||
|
||||
public HybridNotificationView getSingleLineView() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -108,7 +109,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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
result.packageContext = packageContext;
|
||||
return result;
|
||||
}
|
||||
|
||||
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);
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
||||
private RemoteViews createBigContentView(Notification.Builder builder,
|
||||
/**
|
||||
* 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 RemoteViews.OnClickHandler mRemoteViewClickHandler;
|
||||
private CancellationSignal mCancellationSignal;
|
||||
|
||||
private AsyncInflationTask(Context context, StatusBarNotification notification,
|
||||
int reInflateFlags) {
|
||||
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){
|
||||
handleError(e);
|
||||
return;
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAsyncInflationFinished(NotificationData.Entry entry) {
|
||||
mRow.getEntry().onInflationTaskFinished();
|
||||
mRow.onNotificationUpdated();
|
||||
mCallback.onAsyncInflationFinished(mRow.getEntry());
|
||||
}
|
||||
mRow.onNotificationUpdated();
|
||||
mCallback.onAsyncInflationFinished(mRow.getEntry());
|
||||
}
|
||||
|
||||
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 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 abstract static class ApplyCallback {
|
||||
public abstract void setResultView(View v);
|
||||
public abstract RemoteViews getRemoteView();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -207,6 +207,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;
|
||||
@@ -1598,12 +1599,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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1620,7 +1621,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());
|
||||
}
|
||||
|
||||
@@ -6234,50 +6235,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);
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user