1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.support.v4.app; 18 19import static android.support.v4.app.NotificationCompat.DEFAULT_ALL; 20import static android.support.v4.app.NotificationCompat.DEFAULT_LIGHTS; 21import static android.support.v4.app.NotificationCompat.DEFAULT_SOUND; 22import static android.support.v4.app.NotificationCompat.DEFAULT_VIBRATE; 23import static android.support.v4.app.NotificationCompat.GROUP_ALERT_ALL; 24import static android.support.v4.app.NotificationCompat.GROUP_ALERT_CHILDREN; 25import static android.support.v4.app.NotificationCompat.GROUP_ALERT_SUMMARY; 26 27import static org.junit.Assert.assertEquals; 28import static org.junit.Assert.assertFalse; 29import static org.junit.Assert.assertNotNull; 30import static org.junit.Assert.assertNull; 31import static org.junit.Assert.assertSame; 32import static org.junit.Assert.assertTrue; 33 34import android.annotation.TargetApi; 35import android.app.Notification; 36import android.content.Context; 37import android.net.Uri; 38import android.os.Build; 39import android.os.Bundle; 40import android.support.test.filters.SdkSuppress; 41import android.support.test.filters.SmallTest; 42import android.support.test.runner.AndroidJUnit4; 43import android.support.v4.BaseInstrumentationTestCase; 44import android.support.v4.os.BuildCompat; 45 46import org.junit.Before; 47import org.junit.Test; 48import org.junit.runner.RunWith; 49 50import java.util.ArrayList; 51 52 53@RunWith(AndroidJUnit4.class) 54@SmallTest 55public class NotificationCompatTest extends BaseInstrumentationTestCase<TestSupportActivity> { 56 private static final String TEXT_RESULT_KEY = "text"; 57 private static final String DATA_RESULT_KEY = "data"; 58 private static final String EXTRA_COLORIZED = "android.colorized"; 59 60 Context mContext; 61 62 public NotificationCompatTest() { 63 super(TestSupportActivity.class); 64 } 65 66 @Before 67 public void setup() { 68 mContext = mActivityTestRule.getActivity(); 69 } 70 71 @Test 72 public void testBadgeIcon() throws Throwable { 73 int badgeIcon = NotificationCompat.BADGE_ICON_SMALL; 74 Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity()) 75 .setBadgeIconType(badgeIcon) 76 .build(); 77 if (BuildCompat.isAtLeastO()) { 78 assertEquals(badgeIcon, NotificationCompat.getBadgeIconType(n)); 79 } else { 80 assertEquals(NotificationCompat.BADGE_ICON_NONE, 81 NotificationCompat.getBadgeIconType(n)); 82 } 83 } 84 85 @Test 86 public void testTimeout() throws Throwable { 87 long timeout = 23552; 88 Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity()) 89 .setTimeout(timeout) 90 .build(); 91 if (BuildCompat.isAtLeastO()) { 92 assertEquals(timeout, NotificationCompat.getTimeout(n)); 93 } else { 94 assertEquals(0, NotificationCompat.getTimeout(n)); 95 } 96 } 97 98 @Test 99 public void testShortcutId() throws Throwable { 100 String shortcutId = "fgdfg"; 101 Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity()) 102 .setShortcutId(shortcutId) 103 .build(); 104 if (BuildCompat.isAtLeastO()) { 105 assertEquals(shortcutId, NotificationCompat.getShortcutId(n)); 106 } else { 107 assertEquals(null, NotificationCompat.getShortcutId(n)); 108 } 109 } 110 111 @Test 112 public void testNotificationChannel() throws Throwable { 113 String channelId = "new ID"; 114 Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity()) 115 .setChannel(channelId) 116 .build(); 117 if (BuildCompat.isAtLeastO()) { 118 assertEquals(channelId, NotificationCompat.getChannel(n)); 119 } else { 120 assertNull(NotificationCompat.getChannel(n)); 121 } 122 } 123 124 @Test 125 public void testNotificationChannel_assignedFromBuilder() throws Throwable { 126 String channelId = "new ID"; 127 Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity(), channelId) 128 .build(); 129 if (BuildCompat.isAtLeastO()) { 130 assertEquals(channelId, NotificationCompat.getChannel(n)); 131 } else { 132 assertNull(NotificationCompat.getChannel(n)); 133 } 134 } 135 136 @Test 137 public void testNotificationActionBuilder_assignsColorized() throws Throwable { 138 Notification n = newNotificationBuilder().setColorized(true).build(); 139 if (BuildCompat.isAtLeastO()) { 140 Bundle extras = NotificationCompat.getExtras(n); 141 assertTrue(Boolean.TRUE.equals(extras.get(EXTRA_COLORIZED))); 142 } 143 } 144 145 @Test 146 public void testNotificationActionBuilder_unassignesColorized() throws Throwable { 147 Notification n = newNotificationBuilder().setColorized(false).build(); 148 if (BuildCompat.isAtLeastO()) { 149 Bundle extras = NotificationCompat.getExtras(n); 150 assertTrue(Boolean.FALSE.equals(extras.get(EXTRA_COLORIZED))); 151 } 152 } 153 154 @Test 155 public void testNotificationActionBuilder_doesntAssignColorized() throws Throwable { 156 Notification n = newNotificationBuilder().build(); 157 if (BuildCompat.isAtLeastO()) { 158 Bundle extras = NotificationCompat.getExtras(n); 159 assertFalse(extras.containsKey(EXTRA_COLORIZED)); 160 } 161 } 162 163 @Test 164 public void testNotificationActionBuilder_copiesRemoteInputs() throws Throwable { 165 NotificationCompat.Action a = newActionBuilder() 166 .addRemoteInput(new RemoteInput("a", "b", null, false, null, null)).build(); 167 168 NotificationCompat.Action aCopy = new NotificationCompat.Action.Builder(a).build(); 169 170 assertSame(a.getRemoteInputs()[0], aCopy.getRemoteInputs()[0]); 171 } 172 173 @Test 174 public void testNotificationActionBuilder_copiesAllowGeneratedReplies() throws Throwable { 175 NotificationCompat.Action a = newActionBuilder() 176 .setAllowGeneratedReplies(true).build(); 177 178 NotificationCompat.Action aCopy = new NotificationCompat.Action.Builder(a).build(); 179 180 assertEquals(a.getAllowGeneratedReplies(), aCopy.getAllowGeneratedReplies()); 181 } 182 183 @Test 184 public void testNotificationActionBuilder_defaultAllowGeneratedRepliesTrue() throws Throwable { 185 NotificationCompat.Action a = newActionBuilder().build(); 186 187 assertTrue(a.getAllowGeneratedReplies()); 188 } 189 190 @Test 191 public void testNotificationAction_defaultAllowGeneratedRepliesTrue() throws Throwable { 192 NotificationCompat.Action a = new NotificationCompat.Action(0, null, null); 193 194 assertTrue(a.getAllowGeneratedReplies()); 195 } 196 197 @Test 198 public void testNotificationActionBuilder_setAllowGeneratedRepliesFalse() throws Throwable { 199 NotificationCompat.Action a = newActionBuilder() 200 .setAllowGeneratedReplies(false).build(); 201 202 assertFalse(a.getAllowGeneratedReplies()); 203 } 204 205 @SdkSuppress(minSdkVersion = 17) 206 @TargetApi(17) 207 @Test 208 public void testNotificationWearableExtenderAction_setAllowGeneratedRepliesTrue() 209 throws Throwable { 210 NotificationCompat.Action a = newActionBuilder() 211 .setAllowGeneratedReplies(true).build(); 212 NotificationCompat.WearableExtender extender = new NotificationCompat.WearableExtender() 213 .addAction(a); 214 Notification notification = newNotificationBuilder().extend(extender).build(); 215 assertTrue(new NotificationCompat.WearableExtender(notification).getActions().get(0) 216 .getAllowGeneratedReplies()); 217 } 218 219 @SdkSuppress(minSdkVersion = 17) 220 @TargetApi(17) 221 @Test 222 public void testNotificationWearableExtenderAction_setAllowGeneratedRepliesFalse() 223 throws Throwable { 224 NotificationCompat.Action a = newActionBuilder() 225 .setAllowGeneratedReplies(false).build(); 226 NotificationCompat.WearableExtender extender = new NotificationCompat.WearableExtender() 227 .addAction(a); 228 Notification notification = newNotificationBuilder().extend(extender).build(); 229 assertFalse(new NotificationCompat.WearableExtender(notification).getActions().get(0) 230 .getAllowGeneratedReplies()); 231 } 232 233 234 @SdkSuppress(maxSdkVersion = 16) 235 @SmallTest 236 @Test 237 public void testNotificationWearableExtenderAction_noActions() 238 throws Throwable { 239 NotificationCompat.Action a = newActionBuilder() 240 .setAllowGeneratedReplies(true).build(); 241 NotificationCompat.WearableExtender extender = new NotificationCompat.WearableExtender() 242 .addAction(a); 243 Notification notification = newNotificationBuilder().extend(extender).build(); 244 assertTrue(new NotificationCompat.WearableExtender(notification).getActions().size() == 0); 245 } 246 247 @Test 248 public void testNotificationActionBuilder_setDataOnlyRemoteInput() throws Throwable { 249 NotificationCompat.Action a = newActionBuilder() 250 .addRemoteInput(newDataOnlyRemoteInput()).build(); 251 RemoteInput[] textInputs = a.getRemoteInputs(); 252 assertTrue(textInputs == null || textInputs.length == 0); 253 verifyRemoteInputArrayHasSingleResult(a.getDataOnlyRemoteInputs(), DATA_RESULT_KEY); 254 } 255 256 @Test 257 public void testNotificationActionBuilder_setTextAndDataOnlyRemoteInput() throws Throwable { 258 NotificationCompat.Action a = newActionBuilder() 259 .addRemoteInput(newDataOnlyRemoteInput()) 260 .addRemoteInput(newTextRemoteInput()) 261 .build(); 262 263 verifyRemoteInputArrayHasSingleResult(a.getRemoteInputs(), TEXT_RESULT_KEY); 264 verifyRemoteInputArrayHasSingleResult(a.getDataOnlyRemoteInputs(), DATA_RESULT_KEY); 265 } 266 267 @Test 268 public void testMessage_setAndGetExtras() throws Throwable { 269 String extraKey = "extra_key"; 270 CharSequence extraValue = "extra_value"; 271 NotificationCompat.MessagingStyle.Message m = 272 new NotificationCompat.MessagingStyle.Message("text", 0 /*timestamp */, "sender"); 273 m.getExtras().putCharSequence(extraKey, extraValue); 274 assertEquals(extraValue, m.getExtras().getCharSequence(extraKey)); 275 276 ArrayList<NotificationCompat.MessagingStyle.Message> messages = new ArrayList<>(1); 277 messages.add(m); 278 Bundle[] bundleArray = 279 NotificationCompat.MessagingStyle.Message.getBundleArrayForMessages(messages); 280 assertEquals(1, bundleArray.length); 281 NotificationCompat.MessagingStyle.Message fromBundle = 282 NotificationCompat.MessagingStyle.Message.getMessageFromBundle(bundleArray[0]); 283 assertEquals(extraValue, fromBundle.getExtras().getCharSequence(extraKey)); 284 } 285 286 @Test 287 public void testGetGroupAlertBehavior() throws Throwable { 288 Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity()) 289 .setGroupAlertBehavior(GROUP_ALERT_CHILDREN) 290 .build(); 291 if (BuildCompat.isAtLeastO()) { 292 assertEquals(GROUP_ALERT_CHILDREN, NotificationCompat.getGroupAlertBehavior(n)); 293 } else { 294 assertEquals(GROUP_ALERT_ALL, NotificationCompat.getGroupAlertBehavior(n)); 295 } 296 } 297 298 @Test 299 public void testGroupAlertBehavior_mutesGroupNotifications() throws Throwable { 300 // valid between api 20, when groups were added, and api 25, the last to use sound 301 // and vibration from the notification itself 302 303 Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity()) 304 .setGroupAlertBehavior(GROUP_ALERT_CHILDREN) 305 .setVibrate(new long[] {235}) 306 .setSound(Uri.EMPTY) 307 .setDefaults(DEFAULT_ALL) 308 .setGroup("grouped") 309 .setGroupSummary(true) 310 .build(); 311 312 Notification n2 = new NotificationCompat.Builder(mActivityTestRule.getActivity()) 313 .setGroupAlertBehavior(GROUP_ALERT_SUMMARY) 314 .setVibrate(new long[] {235}) 315 .setSound(Uri.EMPTY) 316 .setDefaults(DEFAULT_ALL) 317 .setGroup("grouped") 318 .setGroupSummary(false) 319 .build(); 320 321 if (Build.VERSION.SDK_INT >= 20 && !BuildCompat.isAtLeastO()) { 322 assertNull(n.sound); 323 assertNull(n.vibrate); 324 assertTrue((n.defaults & DEFAULT_LIGHTS) != 0); 325 assertTrue((n.defaults & DEFAULT_SOUND) == 0); 326 assertTrue((n.defaults & DEFAULT_VIBRATE) == 0); 327 328 assertNull(n2.sound); 329 assertNull(n2.vibrate); 330 assertTrue((n2.defaults & DEFAULT_LIGHTS) != 0); 331 assertTrue((n2.defaults & DEFAULT_SOUND) == 0); 332 assertTrue((n2.defaults & DEFAULT_VIBRATE) == 0); 333 } else if (Build.VERSION.SDK_INT < 20) { 334 assertNotNull(n.sound); 335 assertNotNull(n.vibrate); 336 assertTrue((n.defaults & DEFAULT_LIGHTS) != 0); 337 assertTrue((n.defaults & DEFAULT_SOUND) != 0); 338 assertTrue((n.defaults & DEFAULT_VIBRATE) != 0); 339 340 assertNotNull(n2.sound); 341 assertNotNull(n2.vibrate); 342 assertTrue((n2.defaults & DEFAULT_LIGHTS) != 0); 343 assertTrue((n2.defaults & DEFAULT_SOUND) != 0); 344 assertTrue((n2.defaults & DEFAULT_VIBRATE) != 0); 345 } 346 } 347 348 @Test 349 public void testGroupAlertBehavior_doesNotMuteIncorrectGroupNotifications() throws Throwable { 350 Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity()) 351 .setGroupAlertBehavior(GROUP_ALERT_SUMMARY) 352 .setVibrate(new long[] {235}) 353 .setSound(Uri.EMPTY) 354 .setDefaults(DEFAULT_ALL) 355 .setGroup("grouped") 356 .setGroupSummary(true) 357 .build(); 358 359 Notification n2 = new NotificationCompat.Builder(mActivityTestRule.getActivity()) 360 .setGroupAlertBehavior(GROUP_ALERT_CHILDREN) 361 .setVibrate(new long[] {235}) 362 .setSound(Uri.EMPTY) 363 .setDefaults(DEFAULT_ALL) 364 .setGroup("grouped") 365 .setGroupSummary(false) 366 .build(); 367 368 Notification n3 = new NotificationCompat.Builder(mActivityTestRule.getActivity()) 369 .setVibrate(new long[] {235}) 370 .setSound(Uri.EMPTY) 371 .setDefaults(DEFAULT_ALL) 372 .setGroup("grouped") 373 .setGroupSummary(false) 374 .build(); 375 376 if (Build.VERSION.SDK_INT >= 20 && !BuildCompat.isAtLeastO()) { 377 assertNotNull(n.sound); 378 assertNotNull(n.vibrate); 379 assertTrue((n.defaults & DEFAULT_LIGHTS) != 0); 380 assertTrue((n.defaults & DEFAULT_SOUND) != 0); 381 assertTrue((n.defaults & DEFAULT_VIBRATE) != 0); 382 383 assertNotNull(n2.sound); 384 assertNotNull(n2.vibrate); 385 assertTrue((n2.defaults & DEFAULT_LIGHTS) != 0); 386 assertTrue((n2.defaults & DEFAULT_SOUND) != 0); 387 assertTrue((n2.defaults & DEFAULT_VIBRATE) != 0); 388 389 assertNotNull(n3.sound); 390 assertNotNull(n3.vibrate); 391 assertTrue((n3.defaults & DEFAULT_LIGHTS) != 0); 392 assertTrue((n3.defaults & DEFAULT_SOUND) != 0); 393 assertTrue((n3.defaults & DEFAULT_VIBRATE) != 0); 394 } 395 } 396 397 @Test 398 public void testGroupAlertBehavior_doesNotMuteNonGroupNotifications() throws Throwable { 399 Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity()) 400 .setGroupAlertBehavior(GROUP_ALERT_CHILDREN) 401 .setVibrate(new long[] {235}) 402 .setSound(Uri.EMPTY) 403 .setDefaults(DEFAULT_ALL) 404 .setGroup(null) 405 .setGroupSummary(false) 406 .build(); 407 if (!BuildCompat.isAtLeastO()) { 408 assertNotNull(n.sound); 409 assertNotNull(n.vibrate); 410 assertTrue((n.defaults & DEFAULT_LIGHTS) != 0); 411 assertTrue((n.defaults & DEFAULT_SOUND) != 0); 412 assertTrue((n.defaults & DEFAULT_VIBRATE) != 0); 413 } 414 } 415 416 private static RemoteInput newDataOnlyRemoteInput() { 417 return new RemoteInput.Builder(DATA_RESULT_KEY) 418 .setAllowFreeFormInput(false) 419 .setAllowDataType("mimeType", true) 420 .build(); 421 } 422 423 private static RemoteInput newTextRemoteInput() { 424 return new RemoteInput.Builder(TEXT_RESULT_KEY).build(); // allowFreeForm defaults to true 425 } 426 427 private static void verifyRemoteInputArrayHasSingleResult( 428 RemoteInput[] remoteInputs, String expectedResultKey) { 429 assertTrue(remoteInputs != null && remoteInputs.length == 1); 430 assertEquals(expectedResultKey, remoteInputs[0].getResultKey()); 431 } 432 433 private static NotificationCompat.Action.Builder newActionBuilder() { 434 return new NotificationCompat.Action.Builder(0, "title", null); 435 } 436 437 private NotificationCompat.Builder newNotificationBuilder() { 438 return new NotificationCompat.Builder(mContext) 439 .setSmallIcon(0) 440 .setContentTitle("title") 441 .setContentText("text"); 442 } 443} 444