diff options
6 files changed, 189 insertions, 45 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 028e3efc9fb8..dc4f3432b6bd 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -8243,6 +8243,7 @@ public class Notification implements Parcelable private void buildIntoRemoteViewContent(RemoteViews remoteViews, RemoteViews customContent, TemplateBindResult result) { + int childIndex = -1; if (customContent != null) { // Need to clone customContent before adding, because otherwise it can no longer be // parceled independently of remoteViews. @@ -8250,7 +8251,11 @@ public class Notification implements Parcelable remoteViews.removeAllViewsExceptId(R.id.notification_main_column, R.id.progress); remoteViews.addView(R.id.notification_main_column, customContent, 0 /* index */); remoteViews.addFlags(RemoteViews.FLAG_REAPPLY_DISALLOWED); + childIndex = 0; } + remoteViews.setIntTag(R.id.notification_main_column, + com.android.internal.R.id.notification_custom_view_index_tag, + childIndex); // also update the end margin if there is an image Resources resources = mBuilder.mContext.getResources(); int endMargin = resources.getDimensionPixelSize( diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index bbe3ff995ac3..ce7995a93f7f 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -193,4 +193,7 @@ <!-- A tag used to save the notification action object --> <item type="id" name="notification_action_index_tag" /> + + <!-- A tag used to save the index where the custom view is stored --> + <item type="id" name="notification_custom_view_index_tag" /> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 3f6362851f61..2ab89ef28f6f 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3593,6 +3593,7 @@ <java-symbol type="bool" name="config_useSmsAppService" /> <java-symbol type="id" name="transition_overlay_view_tag" /> + <java-symbol type="id" name="notification_custom_view_index_tag" /> <java-symbol type="dimen" name="rounded_corner_radius" /> <java-symbol type="dimen" name="rounded_corner_radius_top" /> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java index 4bdc1705c5ff..4c9c2f95b35c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java @@ -17,12 +17,7 @@ package com.android.systemui.statusbar.notification.row.wrapper; import android.content.Context; -import android.content.res.Configuration; import android.graphics.Color; -import android.graphics.ColorMatrix; -import android.graphics.ColorMatrixColorFilter; -import android.graphics.Paint; -import android.os.Build; import android.view.View; import com.android.internal.graphics.ColorUtils; @@ -49,43 +44,22 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper { } @Override - public void onReinflated() { - super.onReinflated(); - - Configuration configuration = mView.getResources().getConfiguration(); - boolean nightMode = (configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK) - == Configuration.UI_MODE_NIGHT_YES; - - float[] hsl = new float[] {0f, 0f, 0f}; - ColorUtils.colorToHSL(mBackgroundColor, hsl); - boolean backgroundIsDark = Color.alpha(mBackgroundColor) == 0 - || hsl[1] == 0 && hsl[2] < 0.5; - boolean backgroundHasColor = hsl[1] > 0; + public void onContentUpdated(ExpandableNotificationRow row) { + super.onContentUpdated(row); // Let's invert the notification colors when we're in night mode and // the notification background isn't colorized. - if (!backgroundIsDark && !backgroundHasColor && nightMode - && mRow.getEntry().targetSdk < Build.VERSION_CODES.Q) { - Paint paint = new Paint(); - ColorMatrix matrix = new ColorMatrix(); - ColorMatrix tmp = new ColorMatrix(); - // Inversion should happen on Y'UV space to conseve the colors and - // only affect the luminosity. - matrix.setRGB2YUV(); - tmp.set(new float[]{ - -1f, 0f, 0f, 0f, 255f, - 0f, 1f, 0f, 0f, 0f, - 0f, 0f, 1f, 0f, 0f, - 0f, 0f, 0f, 1f, 0f - }); - matrix.postConcat(tmp); - tmp.setYUV2RGB(); - matrix.postConcat(tmp); - paint.setColorFilter(new ColorMatrixColorFilter(matrix)); - mView.setLayerType(View.LAYER_TYPE_HARDWARE, paint); - - hsl[2] = 1f - hsl[2]; - mBackgroundColor = ColorUtils.HSLToColor(hsl); + if (needsInversion(mBackgroundColor, mView)) { + invertViewLuminosity(mView); + + // Also invert background color if necessary + // (Otherwise we'd end-up with white on white.) + float[] hsl = new float[] {0f, 0f, 0f}; + ColorUtils.colorToHSL(mBackgroundColor, hsl); + if (mBackgroundColor != Color.TRANSPARENT && hsl[2] > 0.5) { + hsl[2] = 1f - hsl[2]; + mBackgroundColor = ColorUtils.HSLToColor(hsl); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java new file mode 100644 index 000000000000..49a8d56e1e65 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.row.wrapper; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; + +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; + +/** + * Wraps a notification containing a decorated custom view. + */ +public class NotificationDecoratedCustomViewWrapper extends NotificationTemplateViewWrapper { + + private View mWrappedView = null; + + protected NotificationDecoratedCustomViewWrapper(Context ctx, View view, + ExpandableNotificationRow row) { + super(ctx, view, row); + } + + @Override + public void onContentUpdated(ExpandableNotificationRow row) { + ViewGroup container = mView.findViewById( + com.android.internal.R.id.notification_main_column); + Integer childIndex = (Integer) container.getTag( + com.android.internal.R.id.notification_custom_view_index_tag); + if (childIndex != null && childIndex != -1) { + mWrappedView = container.getChildAt(childIndex); + } + if (needsInversion(resolveBackgroundColor(), mWrappedView)) { + invertViewLuminosity(mWrappedView); + } + super.onContentUpdated(row); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java index 9258c9971451..4c06ff6f5e49 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java @@ -16,13 +16,22 @@ package com.android.systemui.statusbar.notification.row.wrapper; +import android.annotation.ColorInt; +import android.app.Notification; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Color; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.Paint; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.view.NotificationHeaderView; import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import com.android.internal.graphics.ColorUtils; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.TransformableView; import com.android.systemui.statusbar.notification.TransformState; @@ -50,6 +59,11 @@ public abstract class NotificationViewWrapper implements TransformableView { } else if ("messaging".equals(v.getTag())) { return new NotificationMessagingTemplateViewWrapper(ctx, v, row); } + Class<? extends Notification.Style> style = + row.getEntry().notification.getNotification().getNotificationStyle(); + if (Notification.DecoratedCustomViewStyle.class.equals(style)) { + return new NotificationDecoratedCustomViewWrapper(ctx, v, row); + } return new NotificationTemplateViewWrapper(ctx, v, row); } else if (v instanceof NotificationHeaderView) { return new NotificationHeaderViewWrapper(ctx, v, row); @@ -75,14 +89,110 @@ public abstract class NotificationViewWrapper implements TransformableView { if (shouldClearBackgroundOnReapply()) { mBackgroundColor = 0; } - Drawable background = mView.getBackground(); - if (background instanceof ColorDrawable) { - int backgroundColor = ((ColorDrawable) background).getColor(); - if (backgroundColor != Color.TRANSPARENT) { - mBackgroundColor = backgroundColor; - mView.setBackground(new ColorDrawable(Color.TRANSPARENT)); + int backgroundColor = getBackgroundColor(mView); + if (backgroundColor != Color.TRANSPARENT) { + mBackgroundColor = backgroundColor; + mView.setBackground(new ColorDrawable(Color.TRANSPARENT)); + } + } + + protected boolean needsInversion(int defaultBackgroundColor, View view) { + if (view == null) { + return false; + } + + Configuration configuration = mView.getResources().getConfiguration(); + boolean nightMode = (configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK) + == Configuration.UI_MODE_NIGHT_YES; + if (!nightMode) { + return false; + } + + int background = getBackgroundColor(view); + if (background == Color.TRANSPARENT) { + background = defaultBackgroundColor; + } + if (background == Color.TRANSPARENT) { + background = resolveBackgroundColor(); + } + + float[] hsl = new float[] {0f, 0f, 0f}; + ColorUtils.colorToHSL(background, hsl); + + // Notifications with colored backgrounds should not be inverted + if (hsl[1] != 0) { + return false; + } + + // Invert white or light gray backgrounds. + boolean isLightGrayOrWhite = hsl[1] == 0 && hsl[2] > 0.5; + if (isLightGrayOrWhite) { + return true; + } + + // Now let's check if there's unprotected text somewhere, and invert if we find it. + if (view instanceof ViewGroup) { + return childrenNeedInversion(background, (ViewGroup) view); + } else { + return false; + } + } + + private boolean childrenNeedInversion(@ColorInt int parentBackground, ViewGroup viewGroup) { + if (viewGroup == null) { + return false; + } + + for (int i = 0; i < viewGroup.getChildCount(); i++) { + View child = viewGroup.getChildAt(i); + int backgroundColor = getBackgroundColor(viewGroup); + if (backgroundColor == Color.TRANSPARENT) { + backgroundColor = parentBackground; } + if (child instanceof TextView) { + int foreground = ((TextView) child).getCurrentTextColor(); + if (ColorUtils.calculateContrast(foreground, backgroundColor) < 3) { + return true; + } + } else if (child instanceof ViewGroup) { + if (childrenNeedInversion(backgroundColor, (ViewGroup) child)) { + return true; + } + } + } + + return false; + } + + protected int getBackgroundColor(View view) { + if (view == null) { + return Color.TRANSPARENT; } + Drawable background = view.getBackground(); + if (background instanceof ColorDrawable) { + return ((ColorDrawable) background).getColor(); + } + return Color.TRANSPARENT; + } + + protected void invertViewLuminosity(View view) { + Paint paint = new Paint(); + ColorMatrix matrix = new ColorMatrix(); + ColorMatrix tmp = new ColorMatrix(); + // Inversion should happen on Y'UV space to conserve the colors and + // only affect the luminosity. + matrix.setRGB2YUV(); + tmp.set(new float[]{ + -1f, 0f, 0f, 0f, 255f, + 0f, 1f, 0f, 0f, 0f, + 0f, 0f, 1f, 0f, 0f, + 0f, 0f, 0f, 1f, 0f + }); + matrix.postConcat(tmp); + tmp.setYUV2RGB(); + matrix.postConcat(tmp); + paint.setColorFilter(new ColorMatrixColorFilter(matrix)); + view.setLayerType(View.LAYER_TYPE_HARDWARE, paint); } protected boolean shouldClearBackgroundOnReapply() { |