blob: 40dc6bce0e3eaeab88240a0a88aebdbaf7e84d72 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.notifications;
import static android.content.Context.NOTIFICATION_SERVICE;
import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Build;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.text.SpannableStringBuilder;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.MinAndroidSdkLevel;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions;
import org.chromium.chrome.browser.util.UrlUtilities;
import org.chromium.chrome.browser.widget.RoundedIconGenerator;
import org.chromium.content_public.browser.test.NativeLibraryTestRule;
/**
* Instrumentation unit tests for StandardNotificationBuilder.
*
* Extends NativeLibraryTestBase so that {@link UrlUtilities#getDomainAndRegistry} can access
* native GetDomainAndRegistry, when called by {@link RoundedIconGenerator#getIconTextForUrl} during
* notification construction.
*/
@RunWith(BaseJUnit4ClassRunner.class)
public class StandardNotificationBuilderTest {
@Rule
public NativeLibraryTestRule mActivityTestRule = new NativeLibraryTestRule();
@Before
public void setUp() throws Exception {
// Not initializing the browser process is safe because GetDomainAndRegistry() is
// stand-alone.
mActivityTestRule.loadNativeLibraryNoBrowserProcess();
}
private NotificationBuilderBase createAllOptionsBuilder(
PendingIntent[] outContentAndDeleteIntents) {
if (outContentAndDeleteIntents == null || outContentAndDeleteIntents.length != 2) {
throw new IllegalArgumentException();
}
Context context = InstrumentationRegistry.getTargetContext();
Intent contentIntent = new Intent("contentIntent");
outContentAndDeleteIntents[0] = PendingIntent.getBroadcast(
context, 0 /* requestCode */, contentIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Intent deleteIntent = new Intent("deleteIntent");
outContentAndDeleteIntents[1] = PendingIntent.getBroadcast(
context, 1 /* requestCode */, deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Bitmap image = Bitmap.createBitmap(
new int[] {Color.BLUE}, 1 /* width */, 1 /* height */, Bitmap.Config.ARGB_8888);
image = image.copy(Bitmap.Config.ARGB_8888, true /* isMutable */);
Bitmap largeIcon = Bitmap.createBitmap(
new int[] {Color.RED}, 1 /* width */, 1 /* height */, Bitmap.Config.ARGB_8888);
largeIcon = largeIcon.copy(Bitmap.Config.ARGB_8888, true /* isMutable */);
Bitmap actionIcon = Bitmap.createBitmap(
new int[] {Color.GRAY}, 1 /* width */, 1 /* height */, Bitmap.Config.ARGB_8888);
actionIcon = actionIcon.copy(Bitmap.Config.ARGB_8888, true /* isMutable */);
return new StandardNotificationBuilder(context)
.setTitle("title")
.setBody("body")
.setOrigin("origin")
.setChannelId(ChannelDefinitions.ChannelId.SITES)
.setTicker(new SpannableStringBuilder("ticker"))
.setImage(image)
.setLargeIcon(largeIcon)
.setSmallIconId(R.drawable.ic_chrome)
.setDefaults(Notification.DEFAULT_ALL)
.setVibrate(new long[] {100L})
.setContentIntent(outContentAndDeleteIntents[0])
.setDeleteIntent(outContentAndDeleteIntents[1])
.addButtonAction(actionIcon, "button 1", null /* intent */)
.addButtonAction(actionIcon, "button 2", null /* intent */)
.addSettingsAction(0 /* iconId */, "settings", null /* intent */);
}
@Test
@SmallTest
@Feature({"Browser", "Notifications"})
public void testSetAll() {
PendingIntent[] contentAndDeleteIntents = new PendingIntent[2];
NotificationBuilderBase builder = createAllOptionsBuilder(contentAndDeleteIntents);
Notification notification = builder.build();
Assert.assertEquals("title", NotificationTestUtil.getExtraTitle(notification));
Assert.assertEquals("body", NotificationTestUtil.getExtraText(notification));
Assert.assertEquals("origin", NotificationTestUtil.getExtraSubText(notification));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
Assert.assertEquals(
NotificationConstants.GROUP_WEB_PREFIX + "origin", notification.getGroup());
}
Assert.assertEquals("ticker", notification.tickerText.toString());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// EXTRA_TEMPLATE was added in Android L; style cannot be verified in earlier versions.
Assert.assertEquals("android.app.Notification$BigPictureStyle",
notification.extras.getString(Notification.EXTRA_TEMPLATE));
}
Bitmap picture = NotificationTestUtil.getExtraPicture(notification);
Assert.assertNotNull(picture);
Assert.assertTrue(picture.getWidth() > 0 && picture.getHeight() > 0);
Context context = InstrumentationRegistry.getTargetContext();
Bitmap smallIcon =
BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_chrome);
Assert.assertTrue(smallIcon.sameAs(
NotificationTestUtil.getSmallIconFromNotification(context, notification)));
Assert.assertNotNull(
NotificationTestUtil.getLargeIconFromNotification(context, notification));
Assert.assertEquals(Notification.DEFAULT_ALL, notification.defaults);
Assert.assertEquals(1, notification.vibrate.length);
Assert.assertEquals(100L, notification.vibrate[0]);
Assert.assertEquals(contentAndDeleteIntents[0], notification.contentIntent);
Assert.assertEquals(contentAndDeleteIntents[1], notification.deleteIntent);
Notification.Action[] actions = NotificationTestUtil.getActions(notification);
Assert.assertEquals(3, actions.length);
Assert.assertEquals("button 1", NotificationTestUtil.getActionTitle(actions[0]));
Assert.assertEquals("button 2", NotificationTestUtil.getActionTitle(actions[1]));
Assert.assertEquals("settings", NotificationTestUtil.getActionTitle(actions[2]));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Notification.publicVersion was added in Android L.
Assert.assertNotNull(notification.publicVersion);
Assert.assertEquals(context.getString(R.string.notification_hidden_text),
NotificationTestUtil.getExtraText(notification.publicVersion));
}
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
Assert.assertEquals(
"origin", NotificationTestUtil.getExtraSubText(notification.publicVersion));
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Assert.assertEquals(
"origin", NotificationTestUtil.getExtraTitle(notification.publicVersion));
}
}
@Test
@SmallTest
@Feature({"Browser", "Notifications"})
public void testBigTextStyle() {
PendingIntent[] contentAndDeleteIntents = new PendingIntent[2];
NotificationBuilderBase builder = createAllOptionsBuilder(contentAndDeleteIntents);
builder.setImage(null);
Notification notification = builder.build();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// EXTRA_TEMPLATE was added in Android L; style cannot be verified in earlier versions.
Assert.assertEquals("android.app.Notification$BigTextStyle",
notification.extras.getString(Notification.EXTRA_TEMPLATE));
}
}
@Test
@SmallTest
@Feature({"Browser", "Notifications"})
public void testSetSmallIcon() {
Context context = InstrumentationRegistry.getTargetContext();
NotificationBuilderBase notificationBuilder = new StandardNotificationBuilder(context);
Bitmap bitmap =
BitmapFactory.decodeResource(context.getResources(), R.drawable.chrome_sync_logo);
notificationBuilder.setSmallIconId(R.drawable.ic_chrome);
notificationBuilder.setStatusBarIcon(bitmap);
notificationBuilder.setChannelId(ChannelDefinitions.ChannelId.SITES);
Notification notification = notificationBuilder.build();
Bitmap result = NotificationTestUtil.getSmallIconFromNotification(context, notification);
Assert.assertNotNull(result);
if (NotificationBuilderBase.deviceSupportsBitmapStatusBarIcons()) {
// Check the white overlay was applied.
Bitmap expected = bitmap.copy(bitmap.getConfig(), true);
NotificationBuilderBase.applyWhiteOverlayToBitmap(expected);
Assert.assertTrue(expected.sameAs(result));
// Check using the same bitmap on another builder gives the same result.
NotificationBuilderBase otherBuilder = new StandardNotificationBuilder(context);
otherBuilder.setStatusBarIcon(bitmap).setChannelId(ChannelDefinitions.ChannelId.SITES);
Notification otherNotification = otherBuilder.build();
Assert.assertTrue(expected.sameAs(
NotificationTestUtil.getSmallIconFromNotification(context, otherNotification)));
} else {
Bitmap expected =
BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_chrome);
Assert.assertTrue(expected.sameAs(result));
}
}
/**
* Regression test for crash observed on Samsung/Coolpad Marshmallow devices - see crbug/829367.
*/
@Test
@MinAndroidSdkLevel(Build.VERSION_CODES.M)
@SmallTest
@Feature({"Browser", "Notifications"})
public void testRenotifyWithCustomBadgeDoesNotCrash() {
Context context = InstrumentationRegistry.getTargetContext();
Notification notification = new StandardNotificationBuilder(context)
.setChannelId(ChannelDefinitions.ChannelId.SITES)
.setSmallIconId(R.drawable.ic_chrome)
.build();
Bitmap bitmap = Bitmap.createBitmap(new int[] {Color.BLUE}, 1, 1, Bitmap.Config.ARGB_8888);
Notification notificationWithBitmap =
new StandardNotificationBuilder(context)
.setChannelId(ChannelDefinitions.ChannelId.SITES)
.setSmallIconId(R.drawable.ic_chrome)
.setStatusBarIcon(bitmap)
.build();
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify("tag-1", 1, notification);
notificationManager.notify("tag-1", 1, notificationWithBitmap);
}
@Test
@MinAndroidSdkLevel(Build.VERSION_CODES.KITKAT_WATCH)
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH) // RemoteInputs were only added in KITKAT_WATCH.
@SmallTest
@Feature({"Browser", "Notifications"})
public void testAddTextActionSetsRemoteInput() {
Context context = InstrumentationRegistry.getTargetContext();
NotificationBuilderBase notificationBuilder =
new StandardNotificationBuilder(context)
.setChannelId(ChannelDefinitions.ChannelId.SITES)
.addTextAction(null, "Action Title", null, "Placeholder");
Notification notification = notificationBuilder.build();
Assert.assertEquals(1, notification.actions.length);
Assert.assertEquals("Action Title", notification.actions[0].title);
Assert.assertNotNull(notification.actions[0].getRemoteInputs());
Assert.assertEquals(1, notification.actions[0].getRemoteInputs().length);
Assert.assertEquals("Placeholder", notification.actions[0].getRemoteInputs()[0].getLabel());
}
}