private int mBackgroundColor = COLOR_INVALID;
private int mForegroundColor = COLOR_INVALID;
private int mBackgroundColorHint = COLOR_INVALID;
+ private boolean mRebuildStyledRemoteViews;
/**
* Constructs a new Builder with the defaults:
* @hide
*/
public RemoteViews createContentView(boolean increasedHeight) {
- if (mN.contentView != null && (mStyle == null || !mStyle.displayCustomViewInline())) {
+ if (mN.contentView != null && useExistingRemoteView()) {
return mN.contentView;
} else if (mStyle != null) {
final RemoteViews styleView = mStyle.makeContentView(increasedHeight);
return applyStandardTemplate(getBaseLayoutResource());
}
+ private boolean useExistingRemoteView() {
+ return mStyle == null || (!mStyle.displayCustomViewInline()
+ && !mRebuildStyledRemoteViews);
+ }
+
/**
* Construct a RemoteViews for the final big notification layout.
*/
public RemoteViews createBigContentView() {
RemoteViews result = null;
- if (mN.bigContentView != null
- && (mStyle == null || !mStyle.displayCustomViewInline())) {
+ if (mN.bigContentView != null && useExistingRemoteView()) {
return mN.bigContentView;
} else if (mStyle != null) {
result = mStyle.makeBigContentView();
* @hide
*/
public RemoteViews createHeadsUpContentView(boolean increasedHeight) {
- if (mN.headsUpContentView != null
- && (mStyle == null || !mStyle.displayCustomViewInline())) {
+ if (mN.headsUpContentView != null && useExistingRemoteView()) {
return mN.headsUpContentView;
} else if (mStyle != null) {
final RemoteViews styleView = mStyle.makeHeadsUpContentView(increasedHeight);
}
if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N
- && (mStyle == null || !mStyle.displayCustomViewInline())) {
+ && (useExistingRemoteView())) {
if (mN.contentView == null) {
mN.contentView = createContentView();
mN.extras.putInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT,
public void setBackgroundColorHint(int backgroundColor) {
mBackgroundColorHint = backgroundColor;
}
+
+
+ /**
+ * Forces all styled remoteViews to be built from scratch and not use any cached
+ * RemoteViews.
+ * This is needed for legacy apps that are baking in their remoteviews into the
+ * notification.
+ *
+ * @hide
+ */
+ public void setRebuildStyledRemoteViews(boolean rebuild) {
+ mRebuildStyledRemoteViews = rebuild;
+ }
}
/**
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
+import android.support.annotation.VisibleForTesting;
import android.support.v4.graphics.ColorUtils;
import android.support.v7.graphics.Palette;
import android.util.LayoutDirection;
private boolean mIsLowPriority;
public MediaNotificationProcessor(Context context, Context packageContext) {
+ this(context, packageContext, new ImageGradientColorizer());
+ }
+
+ @VisibleForTesting
+ MediaNotificationProcessor(Context context, Context packageContext,
+ ImageGradientColorizer colorizer) {
mContext = context;
mPackageContext = packageContext;
- mColorizer = new ImageGradientColorizer();
+ mColorizer = colorizer;
}
/**
Bitmap bitmap = null;
Drawable drawable = null;
if (largeIcon != null) {
+ // We're transforming the builder, let's make sure all baked in RemoteViews are
+ // rebuilt!
+ builder.setRebuildStyledRemoteViews(true);
drawable = largeIcon.loadDrawable(mPackageContext);
int backgroundColor = 0;
if (notification.isColorizedMedia()) {
--- /dev/null
+/*
+ * 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 static org.junit.Assert.assertNotSame;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.app.Notification;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.widget.RemoteViews;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MediaNotificationProcessorTest extends SysuiTestCase {
+
+ private MediaNotificationProcessor mProcessor;
+ private Bitmap mBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+ private ImageGradientColorizer mColorizer;
+
+ @Before
+ public void setUp() {
+ mColorizer = spy(new TestableColorizer(mBitmap));
+ mProcessor = new MediaNotificationProcessor(getContext(), getContext(), mColorizer);
+ }
+
+ @Test
+ public void testColorizedWithLargeIcon() {
+ Notification.Builder builder = new Notification.Builder(getContext()).setSmallIcon(
+ R.drawable.ic_person)
+ .setContentTitle("Title")
+ .setLargeIcon(mBitmap)
+ .setContentText("Text");
+ Notification notification = builder.build();
+ mProcessor.processNotification(notification, builder);
+ verify(mColorizer).colorize(any(), anyInt(), anyBoolean());
+ }
+
+ @Test
+ public void testNotColorizedWithoutLargeIcon() {
+ Notification.Builder builder = new Notification.Builder(getContext()).setSmallIcon(
+ R.drawable.ic_person)
+ .setContentTitle("Title")
+ .setContentText("Text");
+ Notification notification = builder.build();
+ mProcessor.processNotification(notification, builder);
+ verifyZeroInteractions(mColorizer);
+ }
+
+ @Test
+ public void testRemoteViewsReset() {
+ Notification.Builder builder = new Notification.Builder(getContext()).setSmallIcon(
+ R.drawable.ic_person)
+ .setContentTitle("Title")
+ .setStyle(new Notification.MediaStyle())
+ .setLargeIcon(mBitmap)
+ .setContentText("Text");
+ Notification notification = builder.build();
+ RemoteViews remoteViews = new RemoteViews(getContext().getPackageName(),
+ R.layout.custom_view_dark);
+ notification.contentView = remoteViews;
+ notification.bigContentView = remoteViews;
+ notification.headsUpContentView = remoteViews;
+ mProcessor.processNotification(notification, builder);
+ verify(mColorizer).colorize(any(), anyInt(), anyBoolean());
+ RemoteViews contentView = builder.createContentView();
+ assertNotSame(contentView, remoteViews);
+ contentView = builder.createBigContentView();
+ assertNotSame(contentView, remoteViews);
+ contentView = builder.createHeadsUpContentView();
+ assertNotSame(contentView, remoteViews);
+ }
+
+ public static class TestableColorizer extends ImageGradientColorizer {
+ private final Bitmap mBitmap;
+
+ private TestableColorizer(Bitmap bitmap) {
+ mBitmap = bitmap;
+ }
+
+ @Override
+ public Bitmap colorize(Drawable drawable, int backgroundColor, boolean isRtl) {
+ return mBitmap;
+ }
+ }
+}
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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
+ * 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.
+ * 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.notification;
+package com.android.systemui.statusbar.notification;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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
+ * 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.
+ * 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.notification;
+package com.android.systemui.statusbar.notification;
import android.service.notification.StatusBarNotification;
import android.support.test.runner.AndroidJUnit4;