Loading core/java/android/app/Notification.java +59 −21 Original line number Diff line number Diff line Loading @@ -70,6 +70,7 @@ import android.widget.RemoteViews; import com.android.internal.R; import com.android.internal.util.ArrayUtils; import com.android.internal.util.NotificationColorUtil; import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; Loading Loading @@ -2341,6 +2342,11 @@ public class Notification implements Parcelable */ private int mCachedContrastColor = COLOR_INVALID; private int mCachedContrastColorIsFor = COLOR_INVALID; /** * Caches a ambient version of {@link #mCachedContrastColorIsFor}. */ private int mCachedAmbientColor = COLOR_INVALID; private int mCachedAmbientColorIsFor = COLOR_INVALID; /** * Caches an instance of StandardTemplateParams. Note that this may have been used before, Loading Loading @@ -3329,7 +3335,7 @@ public class Notification implements Parcelable final Bundle ex = mN.extras; bindNotificationHeader(contentView); bindNotificationHeader(contentView, p.ambient); bindLargeIcon(contentView); boolean showProgress = handleProgressBar(p.hasProgress, contentView, ex); if (p.title != null) { Loading Loading @@ -3404,14 +3410,17 @@ public class Notification implements Parcelable } } private void bindNotificationHeader(RemoteViews contentView) { bindSmallIcon(contentView); bindHeaderAppName(contentView); private void bindNotificationHeader(RemoteViews contentView, boolean ambient) { bindSmallIcon(contentView, ambient); bindHeaderAppName(contentView, ambient); if (!ambient) { // Ambient view does not have these bindHeaderText(contentView); bindHeaderChronometerAndTime(contentView); bindExpandButton(contentView); bindProfileBadge(contentView); } } private void bindExpandButton(RemoteViews contentView) { contentView.setDrawableParameters(R.id.expand_button, false, -1, resolveContrastColor(), Loading Loading @@ -3493,19 +3502,20 @@ public class Notification implements Parcelable return String.valueOf(name); } private void bindHeaderAppName(RemoteViews contentView) { private void bindHeaderAppName(RemoteViews contentView, boolean ambient) { contentView.setTextViewText(R.id.app_name_text, loadHeaderAppName()); contentView.setTextColor(R.id.app_name_text, resolveContrastColor()); contentView.setTextColor(R.id.app_name_text, ambient ? resolveAmbientColor() : resolveContrastColor()); } private void bindSmallIcon(RemoteViews contentView) { private void bindSmallIcon(RemoteViews contentView, boolean ambient) { if (mN.mSmallIcon == null && mN.icon != 0) { mN.mSmallIcon = Icon.createWithResource(mContext, mN.icon); } contentView.setImageViewIcon(R.id.icon, mN.mSmallIcon); contentView.setDrawableParameters(R.id.icon, false /* targetBackground */, -1 /* alpha */, -1 /* colorFilter */, null /* mode */, mN.iconLevel); processSmallIconColor(mN.mSmallIcon, contentView); processSmallIconColor(mN.mSmallIcon, contentView, ambient); } /** Loading Loading @@ -3546,11 +3556,14 @@ public class Notification implements Parcelable boolean validRemoteInput = false; int N = mActions.size(); boolean emphazisedMode = mN.fullScreenIntent != null; boolean emphazisedMode = mN.fullScreenIntent != null && !p.ambient; big.setBoolean(R.id.actions, "setEmphasizedMode", emphazisedMode); if (N > 0) { big.setViewVisibility(R.id.actions_container, View.VISIBLE); big.setViewVisibility(R.id.actions, View.VISIBLE); if (p.ambient) { big.setInt(R.id.actions, "setBackgroundColor", Color.TRANSPARENT); } big.setViewLayoutMarginBottomDimen(R.id.notification_action_list_margin_target, R.dimen.notification_action_list_height); if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS; Loading @@ -3559,7 +3572,7 @@ public class Notification implements Parcelable validRemoteInput |= hasValidRemoteInput(action); final RemoteViews button = generateActionButton(action, emphazisedMode, i % 2 != 0); i % 2 != 0, p.ambient); big.addView(R.id.actions, button); } } else { Loading @@ -3567,7 +3580,7 @@ public class Notification implements Parcelable } CharSequence[] replyText = mN.extras.getCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY); if (validRemoteInput && replyText != null if (!p.ambient && validRemoteInput && replyText != null && replyText.length > 0 && !TextUtils.isEmpty(replyText[0])) { big.setViewVisibility(R.id.notification_material_reply_container, View.VISIBLE); big.setTextViewText(R.id.notification_material_reply_text_1, replyText[0]); Loading Loading @@ -3652,10 +3665,22 @@ public class Notification implements Parcelable RemoteViews header = new BuilderRemoteViews(mContext.getApplicationInfo(), R.layout.notification_template_header); resetNotificationHeader(header); bindNotificationHeader(header); bindNotificationHeader(header, false /* ambient */); return header; } /** * Construct a RemoteViews for the ambient version of the notification. * * @hide */ public RemoteViews makeAmbientNotification() { RemoteViews ambient = applyStandardTemplateWithActions( R.layout.notification_template_material_ambient, mParams.reset().fillTextsFrom(this).hasProgress(false).ambient(true)); return ambient; } private void hideLine1Text(RemoteViews result) { if (result != null) { result.setViewVisibility(R.id.text_line_1, View.GONE); Loading Loading @@ -3725,7 +3750,7 @@ public class Notification implements Parcelable private RemoteViews generateActionButton(Action action, boolean emphazisedMode, boolean oddAction) { boolean oddAction, boolean ambient) { final boolean tombstone = (action.actionIntent == null); RemoteViews button = new BuilderRemoteViews(mContext.getApplicationInfo(), emphazisedMode ? getEmphasizedActionLayoutResource() Loading Loading @@ -3763,7 +3788,8 @@ public class Notification implements Parcelable } else { button.setTextViewText(R.id.action0, processLegacyText(action.title)); if (mN.color != COLOR_DEFAULT) { button.setTextColor(R.id.action0, resolveContrastColor()); button.setTextColor(R.id.action0, ambient ? resolveAmbientColor() : resolveContrastColor()); } } return button; Loading Loading @@ -3894,15 +3920,17 @@ public class Notification implements Parcelable /** * Apply any necessariy colors to the small icon */ private void processSmallIconColor(Icon smallIcon, RemoteViews contentView) { private void processSmallIconColor(Icon smallIcon, RemoteViews contentView, boolean ambient) { boolean colorable = !isLegacy() || getColorUtil().isGrayscaleIcon(mContext, smallIcon); int color = ambient ? resolveAmbientColor() : resolveContrastColor(); if (colorable) { contentView.setDrawableParameters(R.id.icon, false, -1, resolveContrastColor(), contentView.setDrawableParameters(R.id.icon, false, -1, color, PorterDuff.Mode.SRC_ATOP, -1); } contentView.setInt(R.id.notification_header, "setOriginalIconColor", colorable ? resolveContrastColor() : NotificationHeaderView.NO_COLOR); colorable ? color : NotificationHeaderView.NO_COLOR); } /** Loading Loading @@ -3935,6 +3963,16 @@ public class Notification implements Parcelable return mCachedContrastColor = contrasted; } int resolveAmbientColor() { if (mCachedAmbientColorIsFor == mN.color && mCachedAmbientColorIsFor != COLOR_INVALID) { return mCachedAmbientColor; } final int contrasted = NotificationColorUtil.resolveAmbientColor(mContext, mN.color); mCachedAmbientColorIsFor = mN.color; return mCachedAmbientColor = contrasted; } /** * Apply the unstyled operations and return a new {@link Notification} object. * @hide Loading core/java/com/android/internal/util/NotificationColorUtil.java +23 −0 Original line number Diff line number Diff line Loading @@ -306,6 +306,10 @@ public class NotificationColorUtil { return ColorUtilsFromCompat.LABToColor(high, a, b); } public static int ensureTextContrastOnBlack(int color) { return findContrastColorAgainstDark(color, Color.BLACK, true /* fg */, 12); } /** * Finds a text color with sufficient contrast over bg that has the same hue as the original * color, assuming it is for large text. Loading Loading @@ -393,6 +397,25 @@ public class NotificationColorUtil { return ColorUtilsFromCompat.LABToColor(result[0], result[1], result[2]); } public static int resolveAmbientColor(Context context, int notificationColor) { final int resolvedColor = resolveColor(context, notificationColor); int color = resolvedColor; color = NotificationColorUtil.ensureTextContrastOnBlack(color); if (color != resolvedColor) { if (DEBUG){ Log.w(TAG, String.format( "Ambient contrast of notification for %s is %s (over black)" + " by changing #%s to #%s", context.getPackageName(), NotificationColorUtil.contrastChange(resolvedColor, color, Color.BLACK), Integer.toHexString(resolvedColor), Integer.toHexString(color))); } } return color; } /** * Framework copy of functions needed from android.support.v4.graphics.ColorUtils. */ Loading core/res/res/layout/notification_template_material_ambient.xml 0 → 100644 +73 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ 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. --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/status_bar_latest_event_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:tag="ambient" > <include layout="@layout/notification_template_header" /> <LinearLayout android:id="@+id/notification_action_list_margin_target" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="top" android:layout_marginTop="@dimen/notification_content_margin_top" android:layout_marginBottom="@dimen/notification_action_list_height" android:clipToPadding="false" android:orientation="vertical"> <LinearLayout android:id="@+id/notification_main_column" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:paddingStart="@dimen/notification_content_margin_start" android:paddingEnd="@dimen/notification_content_margin_end" android:clipToPadding="false" android:minHeight="@dimen/notification_min_content_height" android:orientation="vertical" > <TextView android:id="@+id/title" android:textAppearance="@style/TextAppearance.Material.Notification.Title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:singleLine="true" android:ellipsize="marquee" android:fadingEdge="horizontal" android:textSize="20sp" android:textColor="@android:color/white" /> <TextView android:id="@+id/text" android:layout_width="match_parent" android:layout_height="0dp" android:paddingBottom="@dimen/notification_content_margin_bottom" android:textAppearance="@style/TextAppearance.Material.Notification" android:singleLine="false" android:layout_weight="1" android:gravity="top" android:visibility="gone" android:textSize="18sp" android:textColor="@android:color/white" android:layout_marginTop="4dp" /> </LinearLayout> </LinearLayout> <include layout="@layout/notification_material_action_list" /> </FrameLayout> core/res/res/values/symbols.xml +2 −0 Original line number Diff line number Diff line Loading @@ -2772,6 +2772,8 @@ <java-symbol type="dimen" name="config_appTransitionAnimationDurationScaleDefault" /> <java-symbol type="layout" name="notification_template_material_ambient" /> <!-- Network Recommendation --> <java-symbol type="array" name="config_networkRecommendationPackageNames" /> Loading Loading
core/java/android/app/Notification.java +59 −21 Original line number Diff line number Diff line Loading @@ -70,6 +70,7 @@ import android.widget.RemoteViews; import com.android.internal.R; import com.android.internal.util.ArrayUtils; import com.android.internal.util.NotificationColorUtil; import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; Loading Loading @@ -2341,6 +2342,11 @@ public class Notification implements Parcelable */ private int mCachedContrastColor = COLOR_INVALID; private int mCachedContrastColorIsFor = COLOR_INVALID; /** * Caches a ambient version of {@link #mCachedContrastColorIsFor}. */ private int mCachedAmbientColor = COLOR_INVALID; private int mCachedAmbientColorIsFor = COLOR_INVALID; /** * Caches an instance of StandardTemplateParams. Note that this may have been used before, Loading Loading @@ -3329,7 +3335,7 @@ public class Notification implements Parcelable final Bundle ex = mN.extras; bindNotificationHeader(contentView); bindNotificationHeader(contentView, p.ambient); bindLargeIcon(contentView); boolean showProgress = handleProgressBar(p.hasProgress, contentView, ex); if (p.title != null) { Loading Loading @@ -3404,14 +3410,17 @@ public class Notification implements Parcelable } } private void bindNotificationHeader(RemoteViews contentView) { bindSmallIcon(contentView); bindHeaderAppName(contentView); private void bindNotificationHeader(RemoteViews contentView, boolean ambient) { bindSmallIcon(contentView, ambient); bindHeaderAppName(contentView, ambient); if (!ambient) { // Ambient view does not have these bindHeaderText(contentView); bindHeaderChronometerAndTime(contentView); bindExpandButton(contentView); bindProfileBadge(contentView); } } private void bindExpandButton(RemoteViews contentView) { contentView.setDrawableParameters(R.id.expand_button, false, -1, resolveContrastColor(), Loading Loading @@ -3493,19 +3502,20 @@ public class Notification implements Parcelable return String.valueOf(name); } private void bindHeaderAppName(RemoteViews contentView) { private void bindHeaderAppName(RemoteViews contentView, boolean ambient) { contentView.setTextViewText(R.id.app_name_text, loadHeaderAppName()); contentView.setTextColor(R.id.app_name_text, resolveContrastColor()); contentView.setTextColor(R.id.app_name_text, ambient ? resolveAmbientColor() : resolveContrastColor()); } private void bindSmallIcon(RemoteViews contentView) { private void bindSmallIcon(RemoteViews contentView, boolean ambient) { if (mN.mSmallIcon == null && mN.icon != 0) { mN.mSmallIcon = Icon.createWithResource(mContext, mN.icon); } contentView.setImageViewIcon(R.id.icon, mN.mSmallIcon); contentView.setDrawableParameters(R.id.icon, false /* targetBackground */, -1 /* alpha */, -1 /* colorFilter */, null /* mode */, mN.iconLevel); processSmallIconColor(mN.mSmallIcon, contentView); processSmallIconColor(mN.mSmallIcon, contentView, ambient); } /** Loading Loading @@ -3546,11 +3556,14 @@ public class Notification implements Parcelable boolean validRemoteInput = false; int N = mActions.size(); boolean emphazisedMode = mN.fullScreenIntent != null; boolean emphazisedMode = mN.fullScreenIntent != null && !p.ambient; big.setBoolean(R.id.actions, "setEmphasizedMode", emphazisedMode); if (N > 0) { big.setViewVisibility(R.id.actions_container, View.VISIBLE); big.setViewVisibility(R.id.actions, View.VISIBLE); if (p.ambient) { big.setInt(R.id.actions, "setBackgroundColor", Color.TRANSPARENT); } big.setViewLayoutMarginBottomDimen(R.id.notification_action_list_margin_target, R.dimen.notification_action_list_height); if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS; Loading @@ -3559,7 +3572,7 @@ public class Notification implements Parcelable validRemoteInput |= hasValidRemoteInput(action); final RemoteViews button = generateActionButton(action, emphazisedMode, i % 2 != 0); i % 2 != 0, p.ambient); big.addView(R.id.actions, button); } } else { Loading @@ -3567,7 +3580,7 @@ public class Notification implements Parcelable } CharSequence[] replyText = mN.extras.getCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY); if (validRemoteInput && replyText != null if (!p.ambient && validRemoteInput && replyText != null && replyText.length > 0 && !TextUtils.isEmpty(replyText[0])) { big.setViewVisibility(R.id.notification_material_reply_container, View.VISIBLE); big.setTextViewText(R.id.notification_material_reply_text_1, replyText[0]); Loading Loading @@ -3652,10 +3665,22 @@ public class Notification implements Parcelable RemoteViews header = new BuilderRemoteViews(mContext.getApplicationInfo(), R.layout.notification_template_header); resetNotificationHeader(header); bindNotificationHeader(header); bindNotificationHeader(header, false /* ambient */); return header; } /** * Construct a RemoteViews for the ambient version of the notification. * * @hide */ public RemoteViews makeAmbientNotification() { RemoteViews ambient = applyStandardTemplateWithActions( R.layout.notification_template_material_ambient, mParams.reset().fillTextsFrom(this).hasProgress(false).ambient(true)); return ambient; } private void hideLine1Text(RemoteViews result) { if (result != null) { result.setViewVisibility(R.id.text_line_1, View.GONE); Loading Loading @@ -3725,7 +3750,7 @@ public class Notification implements Parcelable private RemoteViews generateActionButton(Action action, boolean emphazisedMode, boolean oddAction) { boolean oddAction, boolean ambient) { final boolean tombstone = (action.actionIntent == null); RemoteViews button = new BuilderRemoteViews(mContext.getApplicationInfo(), emphazisedMode ? getEmphasizedActionLayoutResource() Loading Loading @@ -3763,7 +3788,8 @@ public class Notification implements Parcelable } else { button.setTextViewText(R.id.action0, processLegacyText(action.title)); if (mN.color != COLOR_DEFAULT) { button.setTextColor(R.id.action0, resolveContrastColor()); button.setTextColor(R.id.action0, ambient ? resolveAmbientColor() : resolveContrastColor()); } } return button; Loading Loading @@ -3894,15 +3920,17 @@ public class Notification implements Parcelable /** * Apply any necessariy colors to the small icon */ private void processSmallIconColor(Icon smallIcon, RemoteViews contentView) { private void processSmallIconColor(Icon smallIcon, RemoteViews contentView, boolean ambient) { boolean colorable = !isLegacy() || getColorUtil().isGrayscaleIcon(mContext, smallIcon); int color = ambient ? resolveAmbientColor() : resolveContrastColor(); if (colorable) { contentView.setDrawableParameters(R.id.icon, false, -1, resolveContrastColor(), contentView.setDrawableParameters(R.id.icon, false, -1, color, PorterDuff.Mode.SRC_ATOP, -1); } contentView.setInt(R.id.notification_header, "setOriginalIconColor", colorable ? resolveContrastColor() : NotificationHeaderView.NO_COLOR); colorable ? color : NotificationHeaderView.NO_COLOR); } /** Loading Loading @@ -3935,6 +3963,16 @@ public class Notification implements Parcelable return mCachedContrastColor = contrasted; } int resolveAmbientColor() { if (mCachedAmbientColorIsFor == mN.color && mCachedAmbientColorIsFor != COLOR_INVALID) { return mCachedAmbientColor; } final int contrasted = NotificationColorUtil.resolveAmbientColor(mContext, mN.color); mCachedAmbientColorIsFor = mN.color; return mCachedAmbientColor = contrasted; } /** * Apply the unstyled operations and return a new {@link Notification} object. * @hide Loading
core/java/com/android/internal/util/NotificationColorUtil.java +23 −0 Original line number Diff line number Diff line Loading @@ -306,6 +306,10 @@ public class NotificationColorUtil { return ColorUtilsFromCompat.LABToColor(high, a, b); } public static int ensureTextContrastOnBlack(int color) { return findContrastColorAgainstDark(color, Color.BLACK, true /* fg */, 12); } /** * Finds a text color with sufficient contrast over bg that has the same hue as the original * color, assuming it is for large text. Loading Loading @@ -393,6 +397,25 @@ public class NotificationColorUtil { return ColorUtilsFromCompat.LABToColor(result[0], result[1], result[2]); } public static int resolveAmbientColor(Context context, int notificationColor) { final int resolvedColor = resolveColor(context, notificationColor); int color = resolvedColor; color = NotificationColorUtil.ensureTextContrastOnBlack(color); if (color != resolvedColor) { if (DEBUG){ Log.w(TAG, String.format( "Ambient contrast of notification for %s is %s (over black)" + " by changing #%s to #%s", context.getPackageName(), NotificationColorUtil.contrastChange(resolvedColor, color, Color.BLACK), Integer.toHexString(resolvedColor), Integer.toHexString(color))); } } return color; } /** * Framework copy of functions needed from android.support.v4.graphics.ColorUtils. */ Loading
core/res/res/layout/notification_template_material_ambient.xml 0 → 100644 +73 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ 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. --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/status_bar_latest_event_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:tag="ambient" > <include layout="@layout/notification_template_header" /> <LinearLayout android:id="@+id/notification_action_list_margin_target" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="top" android:layout_marginTop="@dimen/notification_content_margin_top" android:layout_marginBottom="@dimen/notification_action_list_height" android:clipToPadding="false" android:orientation="vertical"> <LinearLayout android:id="@+id/notification_main_column" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:paddingStart="@dimen/notification_content_margin_start" android:paddingEnd="@dimen/notification_content_margin_end" android:clipToPadding="false" android:minHeight="@dimen/notification_min_content_height" android:orientation="vertical" > <TextView android:id="@+id/title" android:textAppearance="@style/TextAppearance.Material.Notification.Title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:singleLine="true" android:ellipsize="marquee" android:fadingEdge="horizontal" android:textSize="20sp" android:textColor="@android:color/white" /> <TextView android:id="@+id/text" android:layout_width="match_parent" android:layout_height="0dp" android:paddingBottom="@dimen/notification_content_margin_bottom" android:textAppearance="@style/TextAppearance.Material.Notification" android:singleLine="false" android:layout_weight="1" android:gravity="top" android:visibility="gone" android:textSize="18sp" android:textColor="@android:color/white" android:layout_marginTop="4dp" /> </LinearLayout> </LinearLayout> <include layout="@layout/notification_material_action_list" /> </FrameLayout>
core/res/res/values/symbols.xml +2 −0 Original line number Diff line number Diff line Loading @@ -2772,6 +2772,8 @@ <java-symbol type="dimen" name="config_appTransitionAnimationDurationScaleDefault" /> <java-symbol type="layout" name="notification_template_material_ambient" /> <!-- Network Recommendation --> <java-symbol type="array" name="config_networkRecommendationPackageNames" /> Loading