summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/Notification.java118
-rw-r--r--core/java/android/widget/RemoteViews.java94
-rw-r--r--core/java/com/android/internal/util/ImageUtils.java (renamed from packages/SystemUI/src/com/android/systemui/ImageUtils.java)6
-rw-r--r--core/java/com/android/internal/util/LegacyNotificationUtil.java193
-rw-r--r--core/res/res/drawable/notification_icon_legacy_bg.xml (renamed from packages/SystemUI/res/drawable/notification_icon_legacy_bg.xml)0
-rw-r--r--core/res/res/drawable/notification_icon_legacy_bg_inset.xml (renamed from packages/SystemUI/res/drawable/notification_icon_legacy_bg_inset.xml)0
-rw-r--r--core/res/res/layout/notification_quantum_action.xml2
-rw-r--r--core/res/res/layout/notification_quantum_action_list.xml2
-rw-r--r--core/res/res/layout/notification_quantum_action_tombstone.xml2
-rw-r--r--core/res/res/layout/notification_template_quantum_base.xml2
-rw-r--r--core/res/res/layout/notification_template_quantum_big_base.xml4
-rw-r--r--core/res/res/layout/notification_template_quantum_big_text.xml6
-rw-r--r--core/res/res/layout/notification_template_quantum_inbox.xml6
-rw-r--r--core/res/res/values/colors.xml3
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--packages/SystemUI/res/values/colors.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java236
17 files changed, 419 insertions, 259 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 13e74da..36d2635 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -17,12 +17,14 @@
package android.app;
import com.android.internal.R;
+import com.android.internal.util.LegacyNotificationUtil;
import android.annotation.IntDef;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.PorterDuff;
import android.media.AudioManager;
import android.net.Uri;
import android.os.BadParcelableException;
@@ -653,13 +655,6 @@ public class Notification implements Parcelable
public static final String EXTRA_AS_HEADS_UP = "headsup";
/**
- * Extra added from {@link Notification.Builder} to indicate that the remote views were inflated
- * from the builder, as opposed to being created directly from the application.
- * @hide
- */
- public static final String EXTRA_BUILDER_REMOTE_VIEWS = "android.builderRemoteViews";
-
- /**
* Allow certain system-generated notifications to appear before the device is provisioned.
* Only available to notifications coming from the android package.
* @hide
@@ -1315,6 +1310,7 @@ public class Notification implements Parcelable
private int mVisibility = VISIBILITY_PRIVATE;
private Notification mPublicVersion = null;
private boolean mQuantumTheme;
+ private final LegacyNotificationUtil mLegacyNotificationUtil;
/**
* Constructs a new Builder with the defaults:
@@ -1345,6 +1341,10 @@ public class Notification implements Parcelable
// TODO: Decide on targetSdk from calling app whether to use quantum theme.
mQuantumTheme = true;
+
+ // TODO: Decide on targetSdk from calling app whether to instantiate the processor at
+ // all.
+ mLegacyNotificationUtil = LegacyNotificationUtil.getInstance();
}
/**
@@ -1846,42 +1846,50 @@ public class Notification implements Parcelable
boolean showLine3 = false;
boolean showLine2 = false;
int smallIconImageViewId = R.id.icon;
- if (mLargeIcon != null) {
- contentView.setImageViewBitmap(R.id.icon, mLargeIcon);
- smallIconImageViewId = R.id.right_icon;
- }
if (!mQuantumTheme && mPriority < PRIORITY_LOW) {
contentView.setInt(R.id.icon,
"setBackgroundResource", R.drawable.notification_template_icon_low_bg);
contentView.setInt(R.id.status_bar_latest_event_content,
"setBackgroundResource", R.drawable.notification_bg_low);
}
+ if (mLargeIcon != null) {
+ contentView.setImageViewBitmap(R.id.icon, mLargeIcon);
+ processLegacyLargeIcon(mLargeIcon, contentView);
+ smallIconImageViewId = R.id.right_icon;
+ }
if (mSmallIcon != 0) {
contentView.setImageViewResource(smallIconImageViewId, mSmallIcon);
contentView.setViewVisibility(smallIconImageViewId, View.VISIBLE);
+ if (mLargeIcon != null) {
+ processLegacySmallIcon(mSmallIcon, smallIconImageViewId, contentView);
+ } else {
+ processLegacyLargeIcon(mSmallIcon, contentView);
+ }
+
} else {
contentView.setViewVisibility(smallIconImageViewId, View.GONE);
}
if (mContentTitle != null) {
- contentView.setTextViewText(R.id.title, mContentTitle);
+ contentView.setTextViewText(R.id.title, processLegacyText(mContentTitle));
}
if (mContentText != null) {
- contentView.setTextViewText(R.id.text, mContentText);
+ contentView.setTextViewText(R.id.text, processLegacyText(mContentText));
showLine3 = true;
}
if (mContentInfo != null) {
- contentView.setTextViewText(R.id.info, mContentInfo);
+ contentView.setTextViewText(R.id.info, processLegacyText(mContentInfo));
contentView.setViewVisibility(R.id.info, View.VISIBLE);
showLine3 = true;
} else if (mNumber > 0) {
final int tooBig = mContext.getResources().getInteger(
R.integer.status_bar_notification_info_maxnum);
if (mNumber > tooBig) {
- contentView.setTextViewText(R.id.info, mContext.getResources().getString(
- R.string.status_bar_notification_info_overflow));
+ contentView.setTextViewText(R.id.info, processLegacyText(
+ mContext.getResources().getString(
+ R.string.status_bar_notification_info_overflow)));
} else {
NumberFormat f = NumberFormat.getIntegerInstance();
- contentView.setTextViewText(R.id.info, f.format(mNumber));
+ contentView.setTextViewText(R.id.info, processLegacyText(f.format(mNumber)));
}
contentView.setViewVisibility(R.id.info, View.VISIBLE);
showLine3 = true;
@@ -1891,9 +1899,9 @@ public class Notification implements Parcelable
// Need to show three lines?
if (mSubText != null) {
- contentView.setTextViewText(R.id.text, mSubText);
+ contentView.setTextViewText(R.id.text, processLegacyText(mSubText));
if (mContentText != null) {
- contentView.setTextViewText(R.id.text2, mContentText);
+ contentView.setTextViewText(R.id.text2, processLegacyText(mContentText));
contentView.setViewVisibility(R.id.text2, View.VISIBLE);
showLine2 = true;
} else {
@@ -2001,15 +2009,78 @@ public class Notification implements Parcelable
tombstone ? getActionTombstoneLayoutResource()
: getActionLayoutResource());
button.setTextViewCompoundDrawablesRelative(R.id.action0, action.icon, 0, 0, 0);
- button.setTextViewText(R.id.action0, action.title);
+ button.setTextViewText(R.id.action0, processLegacyText(action.title));
if (!tombstone) {
button.setOnClickPendingIntent(R.id.action0, action.actionIntent);
}
button.setContentDescription(R.id.action0, action.title);
+ processLegacyAction(action, button);
return button;
}
/**
+ * @return Whether we are currently building a notification from a legacy (an app that
+ * doesn't create quantum notifications by itself) app.
+ */
+ private boolean isLegacy() {
+ return mLegacyNotificationUtil != null;
+ }
+
+ private void processLegacyAction(Action action, RemoteViews button) {
+ if (isLegacy()) {
+ if (mLegacyNotificationUtil.isGrayscale(mContext, action.icon)) {
+ button.setTextViewCompoundDrawablesRelativeColorFilter(R.id.action0, 0,
+ mContext.getResources().getColor(
+ R.color.notification_action_legacy_color_filter),
+ PorterDuff.Mode.MULTIPLY);
+ }
+ }
+ }
+
+ private CharSequence processLegacyText(CharSequence charSequence) {
+ if (isLegacy()) {
+ return mLegacyNotificationUtil.invertCharSequenceColors(charSequence);
+ } else {
+ return charSequence;
+ }
+ }
+
+ private void processLegacyLargeIcon(int largeIconId, RemoteViews contentView) {
+ if (isLegacy()) {
+ processLegacyLargeIcon(
+ mLegacyNotificationUtil.isGrayscale(mContext, largeIconId),
+ contentView);
+ }
+ }
+
+ private void processLegacyLargeIcon(Bitmap largeIcon, RemoteViews contentView) {
+ if (isLegacy()) {
+ processLegacyLargeIcon(
+ mLegacyNotificationUtil.isGrayscale(largeIcon),
+ contentView);
+ }
+ }
+
+ private void processLegacyLargeIcon(boolean isGrayscale, RemoteViews contentView) {
+ if (isLegacy() && isGrayscale) {
+ contentView.setInt(R.id.icon, "setBackgroundResource",
+ R.drawable.notification_icon_legacy_bg_inset);
+ }
+ }
+
+ private void processLegacySmallIcon(int smallIconDrawableId, int smallIconImageViewId,
+ RemoteViews contentView) {
+ if (isLegacy()) {
+ if (mLegacyNotificationUtil.isGrayscale(mContext, smallIconDrawableId)) {
+ contentView.setDrawableParameters(smallIconImageViewId, false, -1,
+ mContext.getResources().getColor(
+ R.color.notification_action_legacy_color_filter),
+ PorterDuff.Mode.MULTIPLY, -1);
+ }
+ }
+ }
+
+ /**
* Apply the unstyled operations and return a new {@link Notification} object.
* @hide
*/
@@ -2075,7 +2146,6 @@ public class Notification implements Parcelable
extras.putBoolean(EXTRA_PROGRESS_INDETERMINATE, mProgressIndeterminate);
extras.putBoolean(EXTRA_SHOW_CHRONOMETER, mUseChronometer);
extras.putBoolean(EXTRA_SHOW_WHEN, mShowWhen);
- extras.putBoolean(EXTRA_BUILDER_REMOTE_VIEWS, mContentView == null);
if (mLargeIcon != null) {
extras.putParcelable(EXTRA_LARGE_ICON, mLargeIcon);
}
@@ -2226,7 +2296,7 @@ public class Notification implements Parcelable
mSummaryTextSet ? mSummaryText
: mBuilder.mSubText;
if (overflowText != null) {
- contentView.setTextViewText(R.id.text, overflowText);
+ contentView.setTextViewText(R.id.text, mBuilder.processLegacyText(overflowText));
contentView.setViewVisibility(R.id.overflow_divider, View.VISIBLE);
contentView.setViewVisibility(R.id.line3, View.VISIBLE);
} else {
@@ -2437,7 +2507,7 @@ public class Notification implements Parcelable
contentView.setViewPadding(R.id.line1, 0, 0, 0, 0);
}
- contentView.setTextViewText(R.id.big_text, mBigText);
+ contentView.setTextViewText(R.id.big_text, mBuilder.processLegacyText(mBigText));
contentView.setViewVisibility(R.id.big_text, View.VISIBLE);
contentView.setViewVisibility(R.id.text2, View.GONE);
@@ -2542,7 +2612,7 @@ public class Notification implements Parcelable
CharSequence str = mTexts.get(i);
if (str != null && !str.equals("")) {
contentView.setViewVisibility(rowIds[i], View.VISIBLE);
- contentView.setTextViewText(rowIds[i], str);
+ contentView.setTextViewText(rowIds[i], mBuilder.processLegacyText(str));
}
i++;
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 0d3df51..f7d20b53 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1516,6 +1516,75 @@ public class RemoteViews implements Parcelable, Filter {
}
/**
+ * Helper action to set a color filter on a compound drawable on a TextView. Supports relative
+ * (s/t/e/b) or cardinal (l/t/r/b) arrangement.
+ */
+ private class TextViewDrawableColorFilterAction extends Action {
+ public TextViewDrawableColorFilterAction(int viewId, boolean isRelative, int index,
+ int color, PorterDuff.Mode mode) {
+ this.viewId = viewId;
+ this.isRelative = isRelative;
+ this.index = index;
+ this.color = color;
+ this.mode = mode;
+ }
+
+ public TextViewDrawableColorFilterAction(Parcel parcel) {
+ viewId = parcel.readInt();
+ isRelative = (parcel.readInt() != 0);
+ index = parcel.readInt();
+ color = parcel.readInt();
+ mode = readPorterDuffMode(parcel);
+ }
+
+ private PorterDuff.Mode readPorterDuffMode(Parcel parcel) {
+ int mode = parcel.readInt();
+ if (mode >= 0 && mode < PorterDuff.Mode.values().length) {
+ return PorterDuff.Mode.values()[mode];
+ } else {
+ return PorterDuff.Mode.CLEAR;
+ }
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(TAG);
+ dest.writeInt(viewId);
+ dest.writeInt(isRelative ? 1 : 0);
+ dest.writeInt(index);
+ dest.writeInt(color);
+ dest.writeInt(mode.ordinal());
+ }
+
+ @Override
+ public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
+ final TextView target = (TextView) root.findViewById(viewId);
+ if (target == null) return;
+ Drawable[] drawables = isRelative
+ ? target.getCompoundDrawablesRelative()
+ : target.getCompoundDrawables();
+ if (index < 0 || index >= 4) {
+ throw new IllegalStateException("index must be in range [0, 3].");
+ }
+ Drawable d = drawables[index];
+ if (d != null) {
+ d.mutate();
+ d.setColorFilter(color, mode);
+ }
+ }
+
+ public String getActionName() {
+ return "TextViewDrawableColorFilterAction";
+ }
+
+ final boolean isRelative;
+ final int index;
+ final int color;
+ final PorterDuff.Mode mode;
+
+ public final static int TAG = 17;
+ }
+
+ /**
* Simple class used to keep track of memory usage in a RemoteViews.
*
*/
@@ -1686,6 +1755,9 @@ public class RemoteViews implements Parcelable, Filter {
case SetRemoteViewsAdapterList.TAG:
mActions.add(new SetRemoteViewsAdapterList(parcel));
break;
+ case TextViewDrawableColorFilterAction.TAG:
+ mActions.add(new TextViewDrawableColorFilterAction(parcel));
+ break;
default:
throw new ActionException("Tag " + tag + " not found");
}
@@ -1921,6 +1993,28 @@ public class RemoteViews implements Parcelable, Filter {
}
/**
+ * Equivalent to applying a color filter on one of the drawables in
+ * {@link android.widget.TextView#getCompoundDrawablesRelative()}.
+ *
+ * @param viewId The id of the view whose text should change.
+ * @param index The index of the drawable in the array of
+ * {@link android.widget.TextView#getCompoundDrawablesRelative()} to set the color
+ * filter on. Must be in [0, 3].
+ * @param color The color of the color filter. See
+ * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)}.
+ * @param mode The mode of the color filter. See
+ * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)}.
+ * @hide
+ */
+ public void setTextViewCompoundDrawablesRelativeColorFilter(int viewId,
+ int index, int color, PorterDuff.Mode mode) {
+ if (index < 0 || index >= 4) {
+ throw new IllegalArgumentException("index must be in range [0, 3].");
+ }
+ addAction(new TextViewDrawableColorFilterAction(viewId, true, index, color, mode));
+ }
+
+ /**
* Equivalent to calling ImageView.setImageResource
*
* @param viewId The id of the view whose drawable should change
diff --git a/packages/SystemUI/src/com/android/systemui/ImageUtils.java b/core/java/com/android/internal/util/ImageUtils.java
index 540ba20..a5ce6e0 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageUtils.java
+++ b/core/java/com/android/internal/util/ImageUtils.java
@@ -14,12 +14,14 @@
* limitations under the License
*/
-package com.android.systemui;
+package com.android.internal.util;
import android.graphics.Bitmap;
/**
* Utility class for image analysis and processing.
+ *
+ * @hide
*/
public class ImageUtils {
@@ -65,7 +67,7 @@ public class ImageUtils {
*
* Note that really transparent colors are always grayscale.
*/
- public boolean isGrayscale(int color) {
+ public static boolean isGrayscale(int color) {
int alpha = 0xFF & (color >> 24);
if (alpha < ALPHA_TOLERANCE) {
return true;
diff --git a/core/java/com/android/internal/util/LegacyNotificationUtil.java b/core/java/com/android/internal/util/LegacyNotificationUtil.java
new file mode 100644
index 0000000..0394bbc
--- /dev/null
+++ b/core/java/com/android/internal/util/LegacyNotificationUtil.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2014 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.internal.util;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.AnimationDrawable;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.style.TextAppearanceSpan;
+import android.util.Log;
+import android.util.Pair;
+
+import java.util.Arrays;
+import java.util.WeakHashMap;
+
+/**
+ * Helper class to process legacy (Holo) notifications to make them look like quantum notifications.
+ *
+ * @hide
+ */
+public class LegacyNotificationUtil {
+
+ private static final String TAG = "LegacyNotificationUtil";
+
+ private static final Object sLock = new Object();
+ private static LegacyNotificationUtil sInstance;
+
+ private final ImageUtils mImageUtils = new ImageUtils();
+ private final WeakHashMap<Bitmap, Pair<Boolean, Integer>> mGrayscaleBitmapCache =
+ new WeakHashMap<Bitmap, Pair<Boolean, Integer>>();
+
+ public static LegacyNotificationUtil getInstance() {
+ synchronized (sLock) {
+ if (sInstance == null) {
+ sInstance = new LegacyNotificationUtil();
+ }
+ return sInstance;
+ }
+ }
+
+ /**
+ * Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect
+ * gray".
+ *
+ * @param bitmap The bitmap to test.
+ * @return Whether the bitmap is grayscale.
+ */
+ public boolean isGrayscale(Bitmap bitmap) {
+ synchronized (sLock) {
+ Pair<Boolean, Integer> cached = mGrayscaleBitmapCache.get(bitmap);
+ if (cached != null) {
+ if (cached.second == bitmap.getGenerationId()) {
+ return cached.first;
+ }
+ }
+ }
+ boolean result;
+ int generationId;
+ synchronized (mImageUtils) {
+ result = mImageUtils.isGrayscale(bitmap);
+
+ // generationId and the check whether the Bitmap is grayscale can't be read atomically
+ // here. However, since the thread is in the process of posting the notification, we can
+ // assume that it doesn't modify the bitmap while we are checking the pixels.
+ generationId = bitmap.getGenerationId();
+ }
+ synchronized (sLock) {
+ mGrayscaleBitmapCache.put(bitmap, Pair.create(result, generationId));
+ }
+ return result;
+ }
+
+ /**
+ * Checks whether a drawable is grayscale. Grayscale here means "very close to a perfect
+ * gray".
+ *
+ * @param d The drawable to test.
+ * @return Whether the drawable is grayscale.
+ */
+ public boolean isGrayscale(Drawable d) {
+ if (d == null) {
+ return false;
+ } else if (d instanceof BitmapDrawable) {
+ BitmapDrawable bd = (BitmapDrawable) d;
+ return bd.getBitmap() != null && isGrayscale(bd.getBitmap());
+ } else if (d instanceof AnimationDrawable) {
+ AnimationDrawable ad = (AnimationDrawable) d;
+ int count = ad.getNumberOfFrames();
+ return count > 0 && isGrayscale(ad.getFrame(0));
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Checks whether a drawable with a resoure id is grayscale. Grayscale here means "very close
+ * to a perfect gray".
+ *
+ * @param context The context to load the drawable from.
+ * @return Whether the drawable is grayscale.
+ */
+ public boolean isGrayscale(Context context, int drawableResId) {
+ if (drawableResId != 0) {
+ try {
+ return isGrayscale(context.getDrawable(drawableResId));
+ } catch (Resources.NotFoundException ex) {
+ Log.e(TAG, "Drawable not found: " + drawableResId);
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Inverts all the grayscale colors set by {@link android.text.style.TextAppearanceSpan}s on
+ * the text.
+ *
+ * @param charSequence The text to process.
+ * @return The color inverted text.
+ */
+ public CharSequence invertCharSequenceColors(CharSequence charSequence) {
+ if (charSequence instanceof Spanned) {
+ Spanned ss = (Spanned) charSequence;
+ Object[] spans = ss.getSpans(0, ss.length(), Object.class);
+ SpannableStringBuilder builder = new SpannableStringBuilder(ss.toString());
+ for (Object span : spans) {
+ Object resultSpan = span;
+ if (span instanceof TextAppearanceSpan) {
+ resultSpan = processTextAppearanceSpan((TextAppearanceSpan) span);
+ }
+ builder.setSpan(resultSpan, ss.getSpanStart(span), ss.getSpanEnd(span),
+ ss.getSpanFlags(span));
+ }
+ return builder;
+ }
+ return charSequence;
+ }
+
+ private TextAppearanceSpan processTextAppearanceSpan(TextAppearanceSpan span) {
+ ColorStateList colorStateList = span.getTextColor();
+ if (colorStateList != null) {
+ int[] colors = colorStateList.getColors();
+ boolean changed = false;
+ for (int i = 0; i < colors.length; i++) {
+ if (ImageUtils.isGrayscale(colors[i])) {
+
+ // Allocate a new array so we don't change the colors in the old color state
+ // list.
+ if (!changed) {
+ colors = Arrays.copyOf(colors, colors.length);
+ }
+ colors[i] = processColor(colors[i]);
+ changed = true;
+ }
+ }
+ if (changed) {
+ return new TextAppearanceSpan(
+ span.getFamily(), span.getTextStyle(), span.getTextSize(),
+ new ColorStateList(colorStateList.getStates(), colors),
+ span.getLinkTextColor());
+ }
+ }
+ return span;
+ }
+
+ private int processColor(int color) {
+ return Color.argb(Color.alpha(color),
+ 255 - Color.red(color),
+ 255 - Color.green(color),
+ 255 - Color.blue(color));
+ }
+}
diff --git a/packages/SystemUI/res/drawable/notification_icon_legacy_bg.xml b/core/res/res/drawable/notification_icon_legacy_bg.xml
index 4ac67c3..4ac67c3 100644
--- a/packages/SystemUI/res/drawable/notification_icon_legacy_bg.xml
+++ b/core/res/res/drawable/notification_icon_legacy_bg.xml
diff --git a/packages/SystemUI/res/drawable/notification_icon_legacy_bg_inset.xml b/core/res/res/drawable/notification_icon_legacy_bg_inset.xml
index 96c5573..96c5573 100644
--- a/packages/SystemUI/res/drawable/notification_icon_legacy_bg_inset.xml
+++ b/core/res/res/drawable/notification_icon_legacy_bg_inset.xml
diff --git a/core/res/res/layout/notification_quantum_action.xml b/core/res/res/layout/notification_quantum_action.xml
index 775182f..0986343 100644
--- a/core/res/res/layout/notification_quantum_action.xml
+++ b/core/res/res/layout/notification_quantum_action.xml
@@ -16,7 +16,7 @@
-->
<Button xmlns:android="http://schemas.android.com/apk/res/android"
- style="?android:attr/borderlessButtonStyle"
+ style="@android:style/Widget.Quantum.Light.Button.Borderless.Small"
android:id="@+id/action0"
android:layout_width="0dp"
android:layout_height="48dp"
diff --git a/core/res/res/layout/notification_quantum_action_list.xml b/core/res/res/layout/notification_quantum_action_list.xml
index a8aef97..d723dcd 100644
--- a/core/res/res/layout/notification_quantum_action_list.xml
+++ b/core/res/res/layout/notification_quantum_action_list.xml
@@ -23,7 +23,7 @@
android:visibility="gone"
android:layout_marginBottom="8dp"
android:showDividers="middle"
- android:divider="?android:attr/listDivider"
+ android:divider="@drawable/list_divider_quantum_light"
android:dividerPadding="12dp"
>
<!-- actions will be added here -->
diff --git a/core/res/res/layout/notification_quantum_action_tombstone.xml b/core/res/res/layout/notification_quantum_action_tombstone.xml
index 9104991..51e4205 100644
--- a/core/res/res/layout/notification_quantum_action_tombstone.xml
+++ b/core/res/res/layout/notification_quantum_action_tombstone.xml
@@ -16,7 +16,7 @@
-->
<Button xmlns:android="http://schemas.android.com/apk/res/android"
- style="?android:attr/borderlessButtonStyle"
+ style="@android:style/Widget.Quantum.Light.Button.Borderless.Small"
android:id="@+id/action0"
android:layout_width="0dp"
android:layout_height="48dp"
diff --git a/core/res/res/layout/notification_template_quantum_base.xml b/core/res/res/layout/notification_template_quantum_base.xml
index 3e97b2a..8863cfa 100644
--- a/core/res/res/layout/notification_template_quantum_base.xml
+++ b/core/res/res/layout/notification_template_quantum_base.xml
@@ -92,7 +92,7 @@
android:layout_height="12dp"
android:layout_marginStart="8dp"
android:visibility="gone"
- style="?android:attr/progressBarStyleHorizontal"
+ style="@style/Widget.Quantum.Light.ProgressBar.Horizontal"
/>
<LinearLayout
android:id="@+id/line3"
diff --git a/core/res/res/layout/notification_template_quantum_big_base.xml b/core/res/res/layout/notification_template_quantum_big_base.xml
index d860045..483ea07 100644
--- a/core/res/res/layout/notification_template_quantum_big_base.xml
+++ b/core/res/res/layout/notification_template_quantum_big_base.xml
@@ -148,7 +148,7 @@
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:visibility="gone"
- style="?android:attr/progressBarStyleHorizontal"
+ style="@style/Widget.Quantum.Light.ProgressBar.Horizontal"
/>
</LinearLayout>
<ImageView
@@ -156,7 +156,7 @@
android:layout_height="1dp"
android:id="@+id/action_divider"
android:visibility="gone"
- android:background="?android:attr/dividerHorizontal" />
+ android:background="@drawable/list_divider_quantum_light" />
<include
layout="@layout/notification_quantum_action_list"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/notification_template_quantum_big_text.xml b/core/res/res/layout/notification_template_quantum_big_text.xml
index 585be80..4fe91c0 100644
--- a/core/res/res/layout/notification_template_quantum_big_text.xml
+++ b/core/res/res/layout/notification_template_quantum_big_text.xml
@@ -101,7 +101,7 @@
android:layout_marginEnd="8dp"
android:visibility="gone"
android:layout_weight="0"
- style="?android:attr/progressBarStyleHorizontal"
+ style="@style/Widget.Quantum.Light.ProgressBar.Horizontal"
/>
<TextView android:id="@+id/big_text"
android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
@@ -121,7 +121,7 @@
android:layout_height="1dip"
android:id="@+id/action_divider"
android:visibility="gone"
- android:background="?android:attr/dividerHorizontal" />
+ android:background="@drawable/list_divider_quantum_light" />
<include
layout="@layout/notification_quantum_action_list"
android:layout_width="match_parent"
@@ -135,7 +135,7 @@
android:id="@+id/overflow_divider"
android:layout_marginBottom="8dp"
android:visibility="visible"
- android:background="?android:attr/dividerHorizontal" />
+ android:background="@drawable/list_divider_quantum_light" />
<LinearLayout
android:id="@+id/line3"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/notification_template_quantum_inbox.xml b/core/res/res/layout/notification_template_quantum_inbox.xml
index 31ed508..fd9089b 100644
--- a/core/res/res/layout/notification_template_quantum_inbox.xml
+++ b/core/res/res/layout/notification_template_quantum_inbox.xml
@@ -103,7 +103,7 @@
android:layout_marginEnd="8dp"
android:visibility="gone"
android:layout_weight="0"
- style="?android:attr/progressBarStyleHorizontal"
+ style="@style/Widget.Quantum.Light.ProgressBar.Horizontal"
/>
<TextView android:id="@+id/inbox_text0"
android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
@@ -206,7 +206,7 @@
android:layout_height="1dip"
android:id="@+id/action_divider"
android:visibility="gone"
- android:background="?android:attr/dividerHorizontal" />
+ android:background="@drawable/list_divider_quantum_light" />
<include
layout="@layout/notification_quantum_action_list"
android:layout_width="match_parent"
@@ -218,7 +218,7 @@
android:layout_height="1dip"
android:id="@+id/overflow_divider"
android:visibility="visible"
- android:background="?android:attr/dividerHorizontal" />
+ android:background="@drawable/list_divider_quantum_light" />
<LinearLayout
android:id="@+id/line3"
android:layout_width="match_parent"
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 1947c50..d0c455b 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -193,6 +193,9 @@
<drawable name="notification_template_icon_bg">#3333B5E5</drawable>
<drawable name="notification_template_icon_low_bg">#0cffffff</drawable>
+ <color name="notification_icon_legacy_bg_color">#ff4285F4</color>
+ <color name="notification_action_legacy_color_filter">#ff555555</color>
+
<!-- Keyguard colors -->
<color name="keyguard_avatar_frame_color">#ffffffff</color>
<color name="keyguard_avatar_frame_shadow_color">#80000000</color>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index efa873d..db5f66e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1637,6 +1637,8 @@
<java-symbol type="layout" name="notification_template_quantum_big_picture" />
<java-symbol type="layout" name="notification_template_quantum_big_text" />
<java-symbol type="layout" name="notification_template_quantum_inbox" />
+ <java-symbol type="color" name="notification_action_legacy_color_filter" />
+ <java-symbol type="drawable" name="notification_icon_legacy_bg_inset" />
<!-- From SystemUI -->
<java-symbol type="anim" name="push_down_in" />
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index a59dc75..5cf0453 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -39,8 +39,6 @@
<color name="status_bar_clock_color">#FFFFFFFF</color>
<drawable name="notification_item_background_color">#ff111111</drawable>
<drawable name="notification_item_background_color_pressed">#ff454545</drawable>
- <color name="notification_icon_legacy_bg_color">#ff4285F4</color>
- <color name="notification_action_legacy_color_filter">#ff555555</color>
<!-- Tint color for inactive Quick Settings icons. -->
<color name="ic_qs_off">#ff404040</color>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 68c8364..59eaf1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -29,14 +29,9 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
-import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.database.ContentObserver;
-import android.graphics.Color;
-import android.graphics.PorterDuff;
import android.graphics.Rect;
-import android.graphics.drawable.AnimationDrawable;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
@@ -52,14 +47,10 @@ import android.provider.Settings;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
import android.service.notification.StatusBarNotification;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
import android.text.TextUtils;
-import android.text.style.TextAppearanceSpan;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.IWindowManager;
import android.view.LayoutInflater;
@@ -70,7 +61,6 @@ import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
-import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupMenu;
@@ -80,8 +70,8 @@ import android.widget.TextView;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.util.LegacyNotificationUtil;
import com.android.internal.widget.SizeAdaptiveLayout;
-import com.android.systemui.ImageUtils;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.SearchPanelView;
@@ -91,7 +81,6 @@ import com.android.systemui.statusbar.policy.NotificationRowLayout;
import java.util.ArrayList;
import java.util.Locale;
-import java.util.Stack;
public abstract class BaseStatusBar extends SystemUI implements
CommandQueue.Callbacks {
@@ -157,8 +146,7 @@ public abstract class BaseStatusBar extends SystemUI implements
// public mode, private notifications, etc
private boolean mLockscreenPublicMode = false;
private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
- private Context mLightThemeContext;
- private ImageUtils mImageUtils = new ImageUtils();
+ private LegacyNotificationUtil mLegacyNotificationUtil = LegacyNotificationUtil.getInstance();
private UserManager mUserManager;
@@ -296,8 +284,6 @@ public abstract class BaseStatusBar extends SystemUI implements
true,
mLockscreenSettingsObserver,
UserHandle.USER_ALL);
- mLightThemeContext = new RemoteViewsThemeContextWrapper(mContext,
- android.R.style.Theme_Holo_Light);
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
@@ -458,158 +444,6 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
- private void processLegacyHoloNotification(StatusBarNotification sbn, View content) {
-
- // TODO: Also skip processing if it is a holo-style notification.
- // If the notification is custom, we can't process it.
- if (!sbn.getNotification().extras.getBoolean(Notification.EXTRA_BUILDER_REMOTE_VIEWS)) {
- return;
- }
-
- processLegacyHoloLargeIcon(content);
- processLegacyHoloActions(content);
- processLegacyNotificationIcon(content);
- processLegacyTextViews(content);
- }
-
- /**
- * @return the context to be used for the inflation of the specified {@code sbn}; this is
- * dependent whether the notification is quantum-style or holo-style
- */
- private Context getInflationContext(StatusBarNotification sbn) {
-
- // TODO: Adjust this logic when we change the theme of the status bar windows.
- if (sbn.getNotification().extras.getBoolean(Notification.EXTRA_BUILDER_REMOTE_VIEWS)) {
- return mLightThemeContext;
- } else {
- return mContext;
- }
- }
-
- private void processLegacyNotificationIcon(View content) {
- View v = content.findViewById(com.android.internal.R.id.right_icon);
- if (v != null & v instanceof ImageView) {
- ImageView iv = (ImageView) v;
- Drawable d = iv.getDrawable();
- if (isMonochrome(d)) {
- d.mutate();
- d.setColorFilter(mLightThemeContext.getResources().getColor(
- R.color.notification_action_legacy_color_filter), PorterDuff.Mode.MULTIPLY);
- }
- }
- }
-
- private void processLegacyHoloLargeIcon(View content) {
- View v = content.findViewById(com.android.internal.R.id.icon);
- if (v != null & v instanceof ImageView) {
- ImageView iv = (ImageView) v;
- if (isMonochrome(iv.getDrawable())) {
- iv.setBackground(mLightThemeContext.getResources().getDrawable(
- R.drawable.notification_icon_legacy_bg_inset));
- }
- }
- }
-
- private boolean isMonochrome(Drawable d) {
- if (d == null) {
- return false;
- } else if (d instanceof BitmapDrawable) {
- BitmapDrawable bd = (BitmapDrawable) d;
- return bd.getBitmap() != null && mImageUtils.isGrayscale(bd.getBitmap());
- } else if (d instanceof AnimationDrawable) {
- AnimationDrawable ad = (AnimationDrawable) d;
- int count = ad.getNumberOfFrames();
- return count > 0 && isMonochrome(ad.getFrame(0));
- } else {
- return false;
- }
- }
-
- private void processLegacyHoloActions(View content) {
- View v = content.findViewById(com.android.internal.R.id.actions);
- if (v != null & v instanceof ViewGroup) {
- ViewGroup vg = (ViewGroup) v;
- int childCount = vg.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = vg.getChildAt(i);
- if (child instanceof Button) {
- Button button = (Button) child;
- Drawable[] compoundDrawables = button.getCompoundDrawablesRelative();
- if (isMonochrome(compoundDrawables[0])) {
- Drawable d = compoundDrawables[0];
- d.mutate();
- d.setColorFilter(mLightThemeContext.getResources().getColor(
- R.color.notification_action_legacy_color_filter),
- PorterDuff.Mode.MULTIPLY);
- }
- }
- }
- }
- }
-
- private void processLegacyTextViews(View content) {
- Stack<View> viewStack = new Stack<View>();
- viewStack.push(content);
- while(!viewStack.isEmpty()) {
- View current = viewStack.pop();
- if(current instanceof ViewGroup){
- ViewGroup currentGroup = (ViewGroup) current;
- int numChildren = currentGroup.getChildCount();
- for(int i=0;i<numChildren;i++){
- viewStack.push(currentGroup.getChildAt(i));
- }
- }
- if (current instanceof TextView) {
- processLegacyTextView((TextView) current);
- }
- }
- }
-
- private void processLegacyTextView(TextView textView) {
- if (textView.getText() instanceof Spanned) {
- Spanned ss = (Spanned) textView.getText();
- Object[] spans = ss.getSpans(0, ss.length(), Object.class);
- SpannableStringBuilder builder = new SpannableStringBuilder(ss.toString());
- for (Object span : spans) {
- Object resultSpan = span;
- if (span instanceof TextAppearanceSpan) {
- resultSpan = processTextAppearanceSpan((TextAppearanceSpan) span);
- }
- builder.setSpan(resultSpan, ss.getSpanStart(span), ss.getSpanEnd(span),
- ss.getSpanFlags(span));
- }
- textView.setText(builder);
- }
- }
-
- private TextAppearanceSpan processTextAppearanceSpan(TextAppearanceSpan span) {
- ColorStateList colorStateList = span.getTextColor();
- if (colorStateList != null) {
- int[] colors = colorStateList.getColors();
- boolean changed = false;
- for (int i = 0; i < colors.length; i++) {
- if (mImageUtils.isGrayscale(colors[i])) {
- colors[i] = processColor(colors[i]);
- changed = true;
- }
- }
- if (changed) {
- return new TextAppearanceSpan(
- span.getFamily(), span.getTextStyle(), span.getTextSize(),
- new ColorStateList(colorStateList.getStates(), colors),
- span.getLinkTextColor());
- }
- }
- return span;
- }
-
- private int processColor(int color) {
- return Color.argb(Color.alpha(color),
- 255 - Color.red(color),
- 255 - Color.green(color),
- 255 - Color.blue(color));
- }
-
private void startApplicationDetailsActivity(String packageName) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", packageName, null));
@@ -947,10 +781,10 @@ public abstract class BaseStatusBar extends SystemUI implements
View contentViewLocal = null;
View bigContentViewLocal = null;
try {
- contentViewLocal = contentView.apply(getInflationContext(sbn), expanded,
+ contentViewLocal = contentView.apply(mContext, expanded,
mOnClickHandler);
if (bigContentView != null) {
- bigContentViewLocal = bigContentView.apply(getInflationContext(sbn), expanded,
+ bigContentViewLocal = bigContentView.apply(mContext, expanded,
mOnClickHandler);
}
}
@@ -983,8 +817,8 @@ public abstract class BaseStatusBar extends SystemUI implements
View publicViewLocal = null;
if (publicNotification != null) {
try {
- publicViewLocal = publicNotification.contentView.apply(getInflationContext(sbn),
- expandedPublic, mOnClickHandler);
+ publicViewLocal = publicNotification.contentView.apply(mContext, expandedPublic,
+ mOnClickHandler);
if (publicViewLocal != null) {
publicViewLocal.setIsRootNamespace(true);
@@ -1005,7 +839,8 @@ public abstract class BaseStatusBar extends SystemUI implements
if (publicViewLocal == null) {
// Add a basic notification template
publicViewLocal = LayoutInflater.from(mContext).inflate(
- com.android.internal.R.layout.notification_template_base, expandedPublic, true);
+ com.android.internal.R.layout.notification_template_quantum_base,
+ expandedPublic, true);
final TextView title = (TextView) publicViewLocal.findViewById(com.android.internal.R.id.title);
try {
@@ -1024,7 +859,12 @@ public abstract class BaseStatusBar extends SystemUI implements
entry.notification.getNotification().number,
entry.notification.getNotification().tickerText);
- icon.setImageDrawable(StatusBarIconView.getIcon(mContext, ic));
+ Drawable iconDrawable = StatusBarIconView.getIcon(mContext, ic);
+ icon.setImageDrawable(iconDrawable);
+ if (mLegacyNotificationUtil.isGrayscale(iconDrawable)) {
+ icon.setBackgroundResource(
+ com.android.internal.R.drawable.notification_icon_legacy_bg_inset);
+ }
final TextView text = (TextView) publicViewLocal.findViewById(com.android.internal.R.id.text);
text.setText("Unlock your device to see this notification.");
@@ -1035,13 +875,6 @@ public abstract class BaseStatusBar extends SystemUI implements
row.setDrawingCacheEnabled(true);
applyLegacyRowBackground(sbn, content);
- processLegacyHoloNotification(sbn, contentViewLocal);
- if (bigContentViewLocal != null) {
- processLegacyHoloNotification(sbn, bigContentViewLocal);
- }
- if (publicViewLocal != null) {
- processLegacyHoloNotification(sbn, publicViewLocal);
- }
if (MULTIUSER_DEBUG) {
TextView debug = (TextView) row.findViewById(R.id.debug_info);
@@ -1459,17 +1292,13 @@ public abstract class BaseStatusBar extends SystemUI implements
: null;
// Reapply the RemoteViews
- contentView.reapply(getInflationContext(notification), entry.expanded, mOnClickHandler);
- processLegacyHoloNotification(notification, entry.expanded);
+ contentView.reapply(mContext, entry.expanded, mOnClickHandler);
if (bigContentView != null && entry.getBigContentView() != null) {
- bigContentView.reapply(getInflationContext(notification), entry.getBigContentView(),
+ bigContentView.reapply(mContext, entry.getBigContentView(),
mOnClickHandler);
- processLegacyHoloNotification(notification, entry.getBigContentView());
}
if (publicContentView != null && entry.getPublicContentView() != null) {
- publicContentView.reapply(getInflationContext(notification),
- entry.getPublicContentView(), mOnClickHandler);
- processLegacyHoloNotification(notification, entry.getPublicContentView());
+ publicContentView.reapply(mContext, entry.getPublicContentView(), mOnClickHandler);
}
// update the contentIntent
final PendingIntent contentIntent = notification.getNotification().contentIntent;
@@ -1540,35 +1369,4 @@ public abstract class BaseStatusBar extends SystemUI implements
}
mContext.unregisterReceiver(mBroadcastReceiver);
}
-
- /**
- * A custom context theme wrapper that applies a platform theme to a created package context.
- * This is useful if you want to inflate {@link RemoteViews} with a custom theme (normally, the
- * theme used there is the default platform theme).
- */
- private static class RemoteViewsThemeContextWrapper extends ContextThemeWrapper {
-
- private int mThemeRes;
-
- private RemoteViewsThemeContextWrapper(Context base, int themeres) {
- super(base, themeres);
- mThemeRes = themeres;
- }
-
- @Override
- public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
- throws NameNotFoundException {
- Context c = super.createPackageContextAsUser(packageName, flags, user);
- c.setTheme(mThemeRes);
- return c;
- }
-
- @Override
- public Context createPackageContext(String packageName, int flags)
- throws NameNotFoundException {
- Context c = super.createPackageContext(packageName, flags);
- c.setTheme(mThemeRes);
- return c;
- }
- }
}