com.test.onesignal.GenerateNotificationRunner.java Source code

Java tutorial

Introduction

Here is the source code for com.test.onesignal.GenerateNotificationRunner.java

Source

/**
 * Modified MIT License
 *
 * Copyright 2016 OneSignal
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * 1. The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * 2. All copies of substantial portions of the Software may only be used in connection
 * with services provided by OneSignal.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.test.onesignal;

import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;

import com.onesignal.BuildConfig;
import com.onesignal.GcmBroadcastReceiver;
import com.onesignal.GcmIntentService;
import com.onesignal.NotificationExtenderService;
import com.onesignal.OSNotification;
import com.onesignal.OSNotificationOpenResult;
import com.onesignal.OSNotificationPayload;
import com.onesignal.OSNotificationReceivedResult;
import com.onesignal.OneSignal;
import com.onesignal.OneSignalDbHelper;
import com.onesignal.OneSignalPackagePrivateHelper;
import com.onesignal.ShadowBadgeCountUpdater;
import com.onesignal.ShadowGcmBroadcastReceiver;
import com.onesignal.ShadowNotificationManagerCompat;
import com.onesignal.ShadowNotificationRestorer;
import com.onesignal.ShadowOneSignal;
import com.onesignal.ShadowOneSignalRestClient;
import com.onesignal.ShadowRoboNotificationManager;
import com.onesignal.ShadowRoboNotificationManager.PostedNotification;
import com.onesignal.StaticResetHelper;
import com.onesignal.example.BlankActivity;
import com.onesignal.OneSignalPackagePrivateHelper.NotificationTable;
import com.onesignal.OneSignalPackagePrivateHelper.NotificationRestorer;

import junit.framework.Assert;

import org.json.JSONObject;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLog;
import org.robolectric.shadows.ShadowSystemClock;
import org.robolectric.util.ActivityController;
import org.robolectric.util.ServiceController;

import java.math.BigInteger;
import java.util.Iterator;
import java.util.Map;

import static com.onesignal.OneSignalPackagePrivateHelper.NotificationBundleProcessor_ProcessFromGCMIntentService;
import static com.onesignal.OneSignalPackagePrivateHelper.NotificationBundleProcessor_ProcessFromGCMIntentService_NoWrap;
import static com.onesignal.OneSignalPackagePrivateHelper.NotificationOpenedProcessor_processFromContext;
import static com.onesignal.OneSignalPackagePrivateHelper.NotificationSummaryManager_updateSummaryNotificationAfterChildRemoved;
import static com.onesignal.OneSignalPackagePrivateHelper.createInternalPayloadBundle;
import static com.test.onesignal.TestHelpers.threadAndTaskWait;
import static org.robolectric.Shadows.shadowOf;

@Config(packageName = "com.onesignal.example", constants = BuildConfig.class, instrumentedPackages = {
        "com.onesignal" }, shadows = { ShadowRoboNotificationManager.class, ShadowOneSignalRestClient.class,
                ShadowBadgeCountUpdater.class, ShadowNotificationManagerCompat.class }, sdk = 21)
@RunWith(RobolectricTestRunner.class)
public class GenerateNotificationRunner {

    private Activity blankActivity;
    private static ActivityController<BlankActivity> blankActivityController;

    private static final String notifMessage = "Robo test message";

    @BeforeClass // Runs only once, before any tests
    public static void setUpClass() throws Exception {
        ShadowLog.stream = System.out;
        StaticResetHelper.saveStaticValues();
    }

    @Before // Before each test
    public void beforeEachTest() throws Exception {
        // Robolectric mocks System.currentTimeMillis() to 0, we need the current real time to match our SQL records.
        ShadowSystemClock.setCurrentTimeMillis(System.currentTimeMillis());

        blankActivityController = Robolectric.buildActivity(BlankActivity.class).create();
        blankActivity = blankActivityController.get();
        blankActivity.getApplicationInfo().name = "UnitTestApp";

        overrideNotificationId = -1;

        TestHelpers.betweenTestsCleanup();

        NotificationManager notificationManager = (NotificationManager) blankActivity
                .getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.cancelAll();
    }

    @AfterClass
    public static void afterEverything() {
        StaticResetHelper.restSetStaticFields();
    }

    public static Bundle getBaseNotifBundle() {
        return getBaseNotifBundle("UUID");
    }

    public static Bundle getBaseNotifBundle(String id) {
        Bundle bundle = new Bundle();
        bundle.putString("alert", notifMessage);
        bundle.putString("custom", "{\"i\": \"" + id + "\"}");

        return bundle;
    }

    private static Intent createOpenIntent(int notifId, Bundle bundle) {
        return new Intent().putExtra("notificationId", notifId).putExtra("onesignal_data",
                OneSignalPackagePrivateHelper.bundleAsJSONObject(bundle).toString());
    }

    private Intent createOpenIntent(Bundle bundle) {
        return createOpenIntent(ShadowRoboNotificationManager.lastNotifId, bundle);
    }

    @Test
    public void shouldSetTitleCorrectly() throws Exception {
        // Should use app's Title by default
        Bundle bundle = getBaseNotifBundle();
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);
        Assert.assertEquals("UnitTestApp", ShadowRoboNotificationManager.getLastShadowNotif().getContentTitle());
        Assert.assertEquals(1, ShadowBadgeCountUpdater.lastCount);

        // Should allow title from GCM payload.
        bundle = getBaseNotifBundle("UUID2");
        bundle.putString("title", "title123");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);
        Assert.assertEquals("title123", ShadowRoboNotificationManager.getLastShadowNotif().getContentTitle());
        Assert.assertEquals(2, ShadowBadgeCountUpdater.lastCount);
    }

    @Test
    public void shouldProcessRestore() throws Exception {
        Bundle bundle = createInternalPayloadBundle(getBaseNotifBundle());
        bundle.putInt("android_notif_id", 0);
        bundle.putBoolean("restoring", true);

        NotificationBundleProcessor_ProcessFromGCMIntentService_NoWrap(blankActivity, bundle, null);
        Assert.assertEquals("UnitTestApp", ShadowRoboNotificationManager.getLastShadowNotif().getContentTitle());
    }

    private static OSNotificationOpenResult lastOpenResult;

    @Test
    public void shouldContainPayloadWhenOldSummaryNotificationIsOpened() throws Exception {
        OneSignal.setInFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification);
        OneSignal.init(blankActivity, "123456789", "b2f7f966-d8cc-11e4-bed1-df8f05be55ba",
                new OneSignal.NotificationOpenedHandler() {
                    @Override
                    public void notificationOpened(OSNotificationOpenResult result) {
                        lastOpenResult = result;
                    }
                });

        // Display 2 notifications that will be grouped together.
        Bundle bundle = getBaseNotifBundle("UUID1");
        bundle.putString("grp", "test1");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);

        bundle = getBaseNotifBundle("UUID2");
        bundle.putString("grp", "test1");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);

        // Go forward 4 weeks
        ShadowSystemClock.setCurrentTimeMillis(System.currentTimeMillis() + 2419202L * 1000L);

        // Display a 3 normal notification.
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, getBaseNotifBundle("UUID3"), null);

        Map<Integer, PostedNotification> postedNotifs = ShadowRoboNotificationManager.notifications;

        // Open the summary notification
        Iterator<Map.Entry<Integer, PostedNotification>> postedNotifsIterator = postedNotifs.entrySet().iterator();
        PostedNotification postedNotification = postedNotifsIterator.next().getValue();
        Intent intent = Shadows.shadowOf(postedNotification.notif.contentIntent).getSavedIntent();
        NotificationOpenedProcessor_processFromContext(blankActivity, intent);

        // Make sure we get a payload when it is opened.
        Assert.assertNotNull(lastOpenResult.notification.payload);
    }

    @Test
    public void shouldSetCorrectNumberOfButtonsOnSummaryNotification() throws Exception {
        // Setup - Init
        OneSignal.setInFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification);
        OneSignal.init(blankActivity, "123456789", "b2f7f966-d8cc-11e4-bed1-df8f05be55ba");
        threadAndTaskWait();

        // Setup - Display a single notification with a grouped.
        Bundle bundle = getBaseNotifBundle("UUID1");
        bundle.putString("grp", "test1");
        bundle.putString("custom", "{\"i\": \"some_UUID\", \"a\": {\"actionButtons\": [{\"text\": \"test\"} ]}}");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);

        Map<Integer, PostedNotification> postedNotifs = ShadowRoboNotificationManager.notifications;
        Iterator<Map.Entry<Integer, PostedNotification>> postedNotifsIterator = postedNotifs.entrySet().iterator();
        PostedNotification postedSummaryNotification = postedNotifsIterator.next().getValue();

        Assert.assertEquals(Notification.FLAG_GROUP_SUMMARY,
                postedSummaryNotification.notif.flags & Notification.FLAG_GROUP_SUMMARY);
        Assert.assertEquals(1, postedSummaryNotification.notif.actions.length);
    }

    @Test
    public void shouldCancelAllNotificationsPartOfAGroup() throws Exception {
        // Setup - Init
        OneSignal.setInFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification);
        OneSignal.init(blankActivity, "123456789", "b2f7f966-d8cc-11e4-bed1-df8f05be55ba");
        threadAndTaskWait();

        // Setup - Display 3 notifications, 2 of which that will be grouped together.
        Bundle bundle = getBaseNotifBundle("UUID0");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);

        bundle = getBaseNotifBundle("UUID1");
        bundle.putString("grp", "test1");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);
        bundle = getBaseNotifBundle("UUID2");
        bundle.putString("grp", "test1");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);

        Assert.assertEquals(4, ShadowRoboNotificationManager.notifications.size());

        OneSignal.cancelGroupedNotifications("test1");
        Assert.assertEquals(1, ShadowRoboNotificationManager.notifications.size());
    }

    @Test
    @Config(shadows = { ShadowNotificationRestorer.class })
    public void shouldCancelNotificationAndUpdateSummary() throws Exception {
        // Setup - Init
        OneSignal.setInFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification);
        OneSignal.init(blankActivity, "123456789", "b2f7f966-d8cc-11e4-bed1-df8f05be55ba");
        threadAndTaskWait();

        // Setup - Display 3 notifications that will be grouped together.
        Bundle bundle = getBaseNotifBundle("UUID1");
        bundle.putString("grp", "test1");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);

        bundle = getBaseNotifBundle("UUID2");
        bundle.putString("grp", "test1");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);

        bundle = getBaseNotifBundle("UUID3");
        bundle.putString("grp", "test1");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);

        Map<Integer, PostedNotification> postedNotifs = ShadowRoboNotificationManager.notifications;
        Iterator<Map.Entry<Integer, PostedNotification>> postedNotifsIterator = postedNotifs.entrySet().iterator();

        // Test - 3 notifis + 1 summary
        Assert.assertEquals(4, postedNotifs.size());

        // Test - First notification should be the summary
        PostedNotification postedSummaryNotification = postedNotifsIterator.next().getValue();
        Assert.assertEquals("3 new messages", postedSummaryNotification.getShadow().getContentText());
        Assert.assertEquals(Notification.FLAG_GROUP_SUMMARY,
                postedSummaryNotification.notif.flags & Notification.FLAG_GROUP_SUMMARY);

        // Setup - Let's cancel a child notification.
        PostedNotification postedNotification = postedNotifsIterator.next().getValue();
        OneSignal.cancelNotification(postedNotification.id);

        // Test - It should update summary text to say 2 notifications
        postedNotifs = ShadowRoboNotificationManager.notifications;
        Assert.assertEquals(3, postedNotifs.size()); // 2 notifis + 1 summary
        postedNotifsIterator = postedNotifs.entrySet().iterator();
        postedSummaryNotification = postedNotifsIterator.next().getValue();
        Assert.assertEquals("2 new messages", postedSummaryNotification.getShadow().getContentText());
        Assert.assertEquals(Notification.FLAG_GROUP_SUMMARY,
                postedSummaryNotification.notif.flags & Notification.FLAG_GROUP_SUMMARY);

        // Setup - Let's cancel a 2nd child notification.
        postedNotification = postedNotifsIterator.next().getValue();
        OneSignal.cancelNotification(postedNotification.id);

        // Test - It should update summary notification to be the text of the last remaining one.
        postedNotifs = ShadowRoboNotificationManager.notifications;
        Assert.assertEquals(2, postedNotifs.size()); // 1 notifis + 1 summary
        postedNotifsIterator = postedNotifs.entrySet().iterator();
        postedSummaryNotification = postedNotifsIterator.next().getValue();
        Assert.assertEquals(notifMessage, postedSummaryNotification.getShadow().getContentText());
        Assert.assertEquals(Notification.FLAG_GROUP_SUMMARY,
                postedSummaryNotification.notif.flags & Notification.FLAG_GROUP_SUMMARY);

        // Test - Let's make sure we will have our last notification too
        postedNotification = postedNotifsIterator.next().getValue();
        Assert.assertEquals(notifMessage, postedNotification.getShadow().getContentText());

        // Setup - Let's cancel our 3rd and last child notification.
        OneSignal.cancelNotification(postedNotification.id);

        // Test - No more notifications! :)
        postedNotifs = ShadowRoboNotificationManager.notifications;
        Assert.assertEquals(0, postedNotifs.size());
    }

    @Test
    public void shouldUpdateBadgesWhenDismissingNotification() {
        Bundle bundle = getBaseNotifBundle();
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);
        Assert.assertEquals(notifMessage, ShadowRoboNotificationManager.getLastShadowNotif().getContentText());
        Assert.assertEquals(1, ShadowBadgeCountUpdater.lastCount);

        Map<Integer, PostedNotification> postedNotifs = ShadowRoboNotificationManager.notifications;
        Iterator<Map.Entry<Integer, PostedNotification>> postedNotifsIterator = postedNotifs.entrySet().iterator();
        PostedNotification postedNotification = postedNotifsIterator.next().getValue();
        Intent intent = Shadows.shadowOf(postedNotification.notif.deleteIntent).getSavedIntent();
        NotificationOpenedProcessor_processFromContext(blankActivity, intent);

        Assert.assertEquals(0, ShadowBadgeCountUpdater.lastCount);
    }

    @Test
    public void shouldNotSetBadgesWhenNotificationPermissionIsDisabled() throws Exception {
        ShadowNotificationManagerCompat.enabled = false;
        OneSignal.init(blankActivity, "123456789", "b2f7f966-d8cc-11e4-bed1-df8f05be55ba");
        threadAndTaskWait();

        Bundle bundle = getBaseNotifBundle();
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);
        Assert.assertEquals(0, ShadowBadgeCountUpdater.lastCount);
    }

    @Test
    public void shouldUpdateNormalNotificationDisplayWhenReplacingANotification() throws Exception {
        // Setup - init
        OneSignal.setInFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification);
        OneSignal.init(blankActivity, "123456789", "b2f7f966-d8cc-11e4-bed1-df8f05be55ba");
        threadAndTaskWait();

        // Setup - Display 2 notifications with the same group and collapse_id
        Bundle bundle = getBaseNotifBundle("UUID1");
        bundle.putString("grp", "test1");
        bundle.putString("collapse_key", "1");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);

        bundle = getBaseNotifBundle("UUID2");
        bundle.putString("grp", "test1");
        bundle.putString("collapse_key", "1");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);

        // Test - Summary created and sub notification. Summary will look the same as the normal notification.
        Map<Integer, PostedNotification> postedNotifs = ShadowRoboNotificationManager.notifications;
        Iterator<Map.Entry<Integer, PostedNotification>> postedNotifsIterator = postedNotifs.entrySet().iterator();
        Assert.assertEquals(2, postedNotifs.size());
        PostedNotification postedSummaryNotification = postedNotifsIterator.next().getValue();
        Assert.assertEquals(notifMessage, postedSummaryNotification.getShadow().getContentText());
        Assert.assertEquals(Notification.FLAG_GROUP_SUMMARY,
                postedSummaryNotification.notif.flags & Notification.FLAG_GROUP_SUMMARY);

        int lastNotifId = postedNotifsIterator.next().getValue().id;
        ShadowRoboNotificationManager.notifications.clear();

        // Setup - Restore
        bundle = getBaseNotifBundle("UUID2");
        bundle.putString("grp", "test1");
        bundle = createInternalPayloadBundle(bundle);
        bundle.putInt("android_notif_id", lastNotifId);
        bundle.putBoolean("restoring", true);
        NotificationBundleProcessor_ProcessFromGCMIntentService_NoWrap(blankActivity, bundle, null);

        // Test - Restored notifications display exactly the same as they did when recevied.
        postedNotifs = ShadowRoboNotificationManager.notifications;
        postedNotifsIterator = postedNotifs.entrySet().iterator();
        // Test - 1 notifi + 1 summary
        Assert.assertEquals(2, postedNotifs.size());
        Assert.assertEquals(notifMessage, postedSummaryNotification.getShadow().getContentText());
        Assert.assertEquals(Notification.FLAG_GROUP_SUMMARY,
                postedSummaryNotification.notif.flags & Notification.FLAG_GROUP_SUMMARY);
    }

    @Test
    public void shouldHandleBasicNotifications() throws Exception {
        // Make sure the notification got posted and the content is correct.
        Bundle bundle = getBaseNotifBundle();
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);
        Assert.assertEquals(notifMessage, ShadowRoboNotificationManager.getLastShadowNotif().getContentText());
        Assert.assertEquals(1, ShadowBadgeCountUpdater.lastCount);

        // Should have 1 DB record with the correct time stamp
        SQLiteDatabase readableDb = OneSignalDbHelper.getInstance(blankActivity).getReadableDatabase();
        Cursor cursor = readableDb.query(NotificationTable.TABLE_NAME, new String[] { "created_time" }, null, null,
                null, null, null);
        Assert.assertEquals(1, cursor.getCount());
        // Time stamp should be set and within a small range.
        long currentTime = System.currentTimeMillis() / 1000;
        cursor.moveToFirst();
        Assert.assertTrue(cursor.getLong(0) > currentTime - 2 && cursor.getLong(0) <= currentTime);
        cursor.close();

        // Should get marked as opened.
        NotificationOpenedProcessor_processFromContext(blankActivity, createOpenIntent(bundle));
        cursor = readableDb.query(NotificationTable.TABLE_NAME,
                new String[] { "opened", "android_notification_id" }, null, null, null, null, null);
        cursor.moveToFirst();
        Assert.assertEquals(1, cursor.getInt(0));
        Assert.assertEquals(0, ShadowBadgeCountUpdater.lastCount);
        cursor.close();

        // Should not display a duplicate notification, count should still be 1
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);
        readableDb = OneSignalDbHelper.getInstance(blankActivity).getReadableDatabase();
        cursor = readableDb.query(NotificationTable.TABLE_NAME, null, null, null, null, null, null);
        Assert.assertEquals(1, cursor.getCount());
        Assert.assertEquals(0, ShadowBadgeCountUpdater.lastCount);
        cursor.close();

        // Display a second notification
        bundle = getBaseNotifBundle("UUID2");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);

        // Go forward 4 weeks
        // Note: Does not effect the SQL function strftime
        ShadowSystemClock.setCurrentTimeMillis(System.currentTimeMillis() + 2419201L * 1000L);

        // Display a 3rd notification
        // Should of been added for a total of 2 records now.
        // First opened should of been cleaned up, 1 week old non opened notification should stay, and one new record.
        bundle = getBaseNotifBundle("UUID3");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);
        readableDb = OneSignalDbHelper.getInstance(blankActivity).getReadableDatabase();
        cursor = readableDb.query(NotificationTable.TABLE_NAME,
                new String[] { "android_notification_id", "created_time" }, null, null, null, null, null);

        Assert.assertEquals(1, cursor.getCount());
        Assert.assertEquals(1, ShadowBadgeCountUpdater.lastCount);

        cursor.close();
    }

    @Test
    public void shouldRestoreNotifications() throws Exception {
        NotificationRestorer.restore(blankActivity);
        NotificationRestorer.restored = false;

        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, getBaseNotifBundle(), null);

        NotificationRestorer.restore(blankActivity);
        NotificationRestorer.restored = false;
        Intent intent = Shadows.shadowOf(blankActivity).getNextStartedService();
        Assert.assertEquals(GcmIntentService.class.getName(), intent.getComponent().getClassName());

        // Go forward 1 week
        // Note: Does not effect the SQL function strftime
        ShadowSystemClock.setCurrentTimeMillis(System.currentTimeMillis() + 604801L * 1000L);

        // Restorer should not fire service since the notification is over 1 week old.
        NotificationRestorer.restore(blankActivity);
        NotificationRestorer.restored = false;
        Assert.assertNull(Shadows.shadowOf(blankActivity).getNextStartedService());
    }

    @Test
    public void shouldGenerate2BasicGroupNotifications() throws Exception {
        // Make sure the notification got posted and the content is correct.
        Bundle bundle = getBaseNotifBundle();
        bundle.putString("grp", "test1");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);

        Map<Integer, PostedNotification> postedNotifs = ShadowRoboNotificationManager.notifications;
        Assert.assertEquals(2, postedNotifs.size());

        // Test summary notification
        Iterator<Map.Entry<Integer, PostedNotification>> postedNotifsIterator = postedNotifs.entrySet().iterator();
        PostedNotification postedNotification = postedNotifsIterator.next().getValue();

        Assert.assertEquals(notifMessage, postedNotification.getShadow().getContentText());
        Assert.assertEquals(Notification.FLAG_GROUP_SUMMARY,
                postedNotification.notif.flags & Notification.FLAG_GROUP_SUMMARY);

        // Test Android Wear notification
        postedNotification = postedNotifsIterator.next().getValue();
        Assert.assertEquals(notifMessage, postedNotification.getShadow().getContentText());
        Assert.assertEquals(0, postedNotification.notif.flags & Notification.FLAG_GROUP_SUMMARY);
        // Badge count should only be one as only one notification is visible in the notification area.
        Assert.assertEquals(1, ShadowBadgeCountUpdater.lastCount);

        // Should be 2 DB entries (summary and individual)
        SQLiteDatabase readableDb = OneSignalDbHelper.getInstance(blankActivity).getReadableDatabase();
        Cursor cursor = readableDb.query(NotificationTable.TABLE_NAME, null, null, null, null, null, null);
        Assert.assertEquals(2, cursor.getCount());
        cursor.close();

        // Add another notification to the group.
        ShadowRoboNotificationManager.notifications.clear();
        bundle = new Bundle();
        bundle.putString("alert", "Notif test 2");
        bundle.putString("custom", "{\"i\": \"UUID2\"}");
        bundle.putString("grp", "test1");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);

        postedNotifs = ShadowRoboNotificationManager.notifications;
        Assert.assertEquals(2, postedNotifs.size());
        Assert.assertEquals(2, ShadowBadgeCountUpdater.lastCount);

        postedNotifsIterator = postedNotifs.entrySet().iterator();
        postedNotification = postedNotifsIterator.next().getValue();
        Assert.assertEquals("2 new messages", postedNotification.getShadow().getContentText());
        Assert.assertEquals(Notification.FLAG_GROUP_SUMMARY,
                postedNotification.notif.flags & Notification.FLAG_GROUP_SUMMARY);

        // Test Android Wear notification
        postedNotification = postedNotifsIterator.next().getValue();
        Assert.assertEquals("Notif test 2", postedNotification.getShadow().getContentText());
        Assert.assertEquals(0, postedNotification.notif.flags & Notification.FLAG_GROUP_SUMMARY);

        // Should be 3 DB entries (summary and 2 individual)
        readableDb = OneSignalDbHelper.getInstance(blankActivity).getReadableDatabase();
        cursor = readableDb.query(NotificationTable.TABLE_NAME, null, null, null, null, null, null);
        Assert.assertEquals(3, cursor.getCount());

        // Open summary notification
        postedNotifsIterator = postedNotifs.entrySet().iterator();
        postedNotification = postedNotifsIterator.next().getValue();
        Intent intent = createOpenIntent(postedNotification.id, bundle).putExtra("summary", "test1");
        NotificationOpenedProcessor_processFromContext(blankActivity, intent);
        Assert.assertEquals(0, ShadowBadgeCountUpdater.lastCount);
        // 2 open calls should fire.
        Assert.assertEquals(2, ShadowOneSignalRestClient.networkCallCount);
        ShadowRoboNotificationManager.notifications.clear();

        // Send 3rd notification
        bundle = new Bundle();
        bundle.putString("alert", "Notif test 3");
        bundle.putString("custom", "{\"i\": \"UUID3\"}");
        bundle.putString("grp", "test1");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);

        postedNotifsIterator = postedNotifs.entrySet().iterator();
        postedNotification = postedNotifsIterator.next().getValue();
        Assert.assertEquals("Notif test 3", postedNotification.getShadow().getContentText());
        Assert.assertEquals(Notification.FLAG_GROUP_SUMMARY,
                postedNotification.notif.flags & Notification.FLAG_GROUP_SUMMARY);
        Assert.assertEquals(1, ShadowBadgeCountUpdater.lastCount);
        cursor.close();
    }

    @Test
    public void shouldHandleOpeningInAppAlertWithGroupKeySet() throws Exception {
        SQLiteDatabase writableDb = OneSignalDbHelper.getInstance(RuntimeEnvironment.application)
                .getWritableDatabase();
        NotificationSummaryManager_updateSummaryNotificationAfterChildRemoved(blankActivity, writableDb,
                "some_group", false);
    }

    @Test
    public void shouldNotDisplaySummaryWhenDismissingAnInAppAlertIfOneDidntAlreadyExist() throws Exception {
        // Setup - init
        OneSignal.setInFocusDisplaying(OneSignal.OSInFocusDisplayOption.InAppAlert);
        OneSignal.init(blankActivity, "123456789", "b2f7f966-d8cc-11e4-bed1-df8f05be55ba");
        threadAndTaskWait();

        // Setup1 - Display a notification with a group set
        Bundle bundle = getBaseNotifBundle("UUID1");
        bundle.putString("grp", "test1");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);

        // Test1 - Manually trigger a refresh on grouped notification.
        SQLiteDatabase writableDb = OneSignalDbHelper.getInstance(RuntimeEnvironment.application)
                .getWritableDatabase();
        NotificationSummaryManager_updateSummaryNotificationAfterChildRemoved(blankActivity, writableDb, "test1",
                false);
        Assert.assertEquals(0, ShadowRoboNotificationManager.notifications.size());

        // Setup2 - Display a 2nd notification with the same group key
        bundle = getBaseNotifBundle("UUID2");
        bundle.putString("grp", "test1");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);

        // Test2 - Manually trigger a refresh on grouped notification.
        writableDb = OneSignalDbHelper.getInstance(RuntimeEnvironment.application).getWritableDatabase();
        NotificationSummaryManager_updateSummaryNotificationAfterChildRemoved(blankActivity, writableDb, "test1",
                false);
        Assert.assertEquals(0, ShadowRoboNotificationManager.notifications.size());
    }

    @Test
    public void shouldCorrectlyDisplaySummaryWithMixedInAppAlertsAndNotifications() throws Exception {
        // Setup - init
        OneSignal.setInFocusDisplaying(OneSignal.OSInFocusDisplayOption.InAppAlert);
        OneSignal.init(blankActivity, "123456789", "b2f7f966-d8cc-11e4-bed1-df8f05be55ba");
        threadAndTaskWait();

        // Setup - Display a notification with a group set
        Bundle bundle = getBaseNotifBundle("UUID1");
        bundle.putString("grp", "test1");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);

        Assert.assertEquals(0, ShadowRoboNotificationManager.notifications.size());

        // Setup - Background app
        blankActivityController.pause();
        threadAndTaskWait();

        // Setup - Send 2 more notifications with the same group
        bundle = getBaseNotifBundle("UUID2");
        bundle.putString("grp", "test1");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);
        bundle = getBaseNotifBundle("UUID3");
        bundle.putString("grp", "test1");
        NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, bundle, null);

        // Test - equals 3 - Should be 2 notifications + 1 summary.
        //         Alert should stay as an in-app alert.
        Assert.assertEquals(3, ShadowRoboNotificationManager.notifications.size());
    }

    @Test
    @Config(shadows = { ShadowGcmBroadcastReceiver.class })
    public void shouldSetButtonsCorrectly() throws Exception {
        Intent intentGcm = new Intent();
        intentGcm.setAction("com.google.android.c2dm.intent.RECEIVE");
        intentGcm.putExtra("message_type", "gcm");
        Bundle bundle = getBaseNotifBundle();
        bundle.putString("o", "[{\"n\": \"text1\", \"i\": \"id1\"}]");
        intentGcm.putExtras(bundle);

        GcmBroadcastReceiver gcmBroadcastReceiver = new GcmBroadcastReceiver();
        gcmBroadcastReceiver.onReceive(blankActivity, intentGcm);

        Intent intent = Shadows.shadowOf(blankActivity).getNextStartedService();
        Assert.assertEquals("com.onesignal.GcmIntentService", intent.getComponent().getClassName());

        JSONObject jsonPayload = new JSONObject(intent.getStringExtra("json_payload"));

        Assert.assertEquals(null, jsonPayload.optString("o", null));
        JSONObject customJson = new JSONObject(jsonPayload.optString("custom"));
        JSONObject additionalData = new JSONObject((customJson.getString("a")));
        Assert.assertEquals("id1", additionalData.getJSONArray("actionButtons").getJSONObject(0).getString("id"));
    }

    @Test
    @Config(shadows = { ShadowGcmBroadcastReceiver.class })
    public void shouldPreventOtherGCMReceiversWhenSettingEnabled() throws Exception {
        OneSignal.setInFocusDisplaying(OneSignal.OSInFocusDisplayOption.InAppAlert);
        OneSignal.startInit(blankActivity).filterOtherGCMReceivers(true).init();
        threadAndTaskWait();

        Intent intentGcm = new Intent();
        intentGcm.setAction("com.google.android.c2dm.intent.RECEIVE");
        intentGcm.putExtra("message_type", "gcm");
        Bundle bundle = getBaseNotifBundle();
        bundle.putString("o", "[{\"n\": \"text1\", \"i\": \"id1\"}]");
        intentGcm.putExtras(bundle);

        GcmBroadcastReceiver gcmBroadcastReceiver = new GcmBroadcastReceiver();
        gcmBroadcastReceiver.onReceive(blankActivity, intentGcm);

        Assert.assertNull(ShadowGcmBroadcastReceiver.lastResultCode);
        Assert.assertTrue(ShadowGcmBroadcastReceiver.calledAbortBroadcast);
    }

    private OSNotification lastNotificationReceived;

    @Test
    public void shouldStillFireReceivedHandlerWhenNotificationExtenderServiceIsUsed() throws Exception {
        OneSignal.setInFocusDisplaying(OneSignal.OSInFocusDisplayOption.None);
        OneSignal.init(blankActivity, "123456789", "b2f7f966-d8cc-11e4-bed1-df8f05be55ba", null,
                new OneSignal.NotificationReceivedHandler() {
                    @Override
                    public void notificationReceived(OSNotification notification) {
                        lastNotificationReceived = notification;
                    }
                });
        threadAndTaskWait();

        startNotificationExtender(createInternalPayloadBundle(getBaseNotifBundle()),
                NotificationExtenderServiceTestReturnFalse.class);

        Assert.assertNotNull(lastNotificationReceived);
    }

    @Test
    public void notificationExtenderServiceOverrideShouldOverrideAndroidNotificationId() throws Exception {
        overrideNotificationId = 1;

        startNotificationExtender(createInternalPayloadBundle(getBaseNotifBundle("NewUUID1")),
                NotificationExtenderServiceTest.class);
        startNotificationExtender(createInternalPayloadBundle(getBaseNotifBundle("NewUUID2")),
                NotificationExtenderServiceTest.class);
        Assert.assertEquals(1, ShadowBadgeCountUpdater.lastCount);
    }

    @Test
    @Config(sdk = 17)
    public void notificationExtenderServiceOverridePropertiesWithSummaryApi17() throws Exception {
        testNotificationExtenderServiceOverridePropertiesWithSummary();

        Map<Integer, PostedNotification> postedNotifs = ShadowRoboNotificationManager.notifications;
        Iterator<Map.Entry<Integer, PostedNotification>> postedNotifsIterator = postedNotifs.entrySet().iterator();

        // Test - First notification should be the summary with the custom sound set.
        PostedNotification postedSummaryNotification = postedNotifsIterator.next().getValue();
        Assert.assertNotSame(Notification.DEFAULT_SOUND,
                postedSummaryNotification.notif.flags & Notification.DEFAULT_SOUND);
        Assert.assertEquals("content://media/internal/audio/media/32",
                postedSummaryNotification.notif.sound.toString());

        Assert.assertEquals(1, postedNotifs.size());
    }

    @Test
    @Config(sdk = 21)
    public void notificationExtenderServiceOverridePropertiesWithSummary() throws Exception {
        testNotificationExtenderServiceOverridePropertiesWithSummary();

        Map<Integer, PostedNotification> postedNotifs = ShadowRoboNotificationManager.notifications;
        Iterator<Map.Entry<Integer, PostedNotification>> postedNotifsIterator = postedNotifs.entrySet().iterator();

        // Test - First notification should be the summary with the custom sound set.
        PostedNotification postedSummaryNotification = postedNotifsIterator.next().getValue();
        Assert.assertNotSame(Notification.DEFAULT_SOUND,
                postedSummaryNotification.notif.flags & Notification.DEFAULT_SOUND);
        Assert.assertEquals("content://media/internal/audio/media/32",
                postedSummaryNotification.notif.sound.toString());

        // Test - individual notification 1 should not play a sound
        PostedNotification notification = postedNotifsIterator.next().getValue();
        Assert.assertNotSame(Notification.DEFAULT_SOUND, notification.notif.flags & Notification.DEFAULT_SOUND);
        Assert.assertNull(notification.notif.sound);

        // Test - individual notification 2 should not play a sound
        notification = postedNotifsIterator.next().getValue();
        Assert.assertNotSame(Notification.DEFAULT_SOUND, notification.notif.flags & Notification.DEFAULT_SOUND);
        Assert.assertNull(notification.notif.sound);
    }

    // Test to make sure changed bodies and titles are used for the summary notification.
    private void testNotificationExtenderServiceOverridePropertiesWithSummary() throws Exception {
        Bundle bundle = getBaseNotifBundle("UUID1");
        bundle.putString("grp", "test1");

        startNotificationExtender(createInternalPayloadBundle(bundle),
                NotificationExtenderServiceOverrideProperties.class);

        bundle = getBaseNotifBundle("UUID2");
        bundle.putString("grp", "test1");

        startNotificationExtender(createInternalPayloadBundle(bundle),
                NotificationExtenderServiceOverrideProperties.class);

        Map<Integer, PostedNotification> postedNotifs = ShadowRoboNotificationManager.notifications;
        Iterator<Map.Entry<Integer, PostedNotification>> postedNotifsIterator = postedNotifs.entrySet().iterator();

        // Test - First notification should be the summary
        PostedNotification postedSummaryNotification = postedNotifsIterator.next().getValue();
        Assert.assertEquals("2 new messages", postedSummaryNotification.getShadow().getContentText());
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT)
            Assert.assertEquals(Notification.FLAG_GROUP_SUMMARY,
                    postedSummaryNotification.notif.flags & Notification.FLAG_GROUP_SUMMARY);

        // Test - Make sure summary build saved and used the developer's extender settings for the body and title
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) {
            CharSequence[] lines = postedSummaryNotification.notif.extras
                    .getCharSequenceArray(Notification.EXTRA_TEXT_LINES);
            for (CharSequence line : lines)
                Assert.assertEquals("[Modified Tile] [Modified Body(ContentText)]", line.toString());
        }
    }

    private NotificationExtenderServiceTestBase startNotificationExtender(Bundle bundlePayload,
            Class serviceClass) {
        ServiceController<NotificationExtenderServiceTestBase> controller = Robolectric.buildService(serviceClass);
        NotificationExtenderServiceTestBase service = controller.attach().create().get();
        Intent testIntent = new Intent(RuntimeEnvironment.application,
                NotificationExtenderServiceTestReturnFalse.class);
        testIntent.putExtras(bundlePayload);
        controller.withIntent(testIntent).startCommand(0, 0);

        return service;
    }

    @Test
    @Config(shadows = { ShadowOneSignal.class })
    public void shouldFireNotificationExtenderService() throws Exception {
        // Test that GCM receiver starts the NotificationExtenderServiceTest when it is in the AndroidManifest.xml
        Bundle bundle = getBaseNotifBundle();

        Intent serviceIntent = new Intent();
        serviceIntent.setPackage("com.onesignal.example");
        serviceIntent.setAction("com.onesignal.NotificationExtender");
        ResolveInfo resolveInfo = new ResolveInfo();
        resolveInfo.serviceInfo = new ServiceInfo();
        resolveInfo.serviceInfo.name = "com.onesignal.example.NotificationExtenderServiceTest";
        RuntimeEnvironment.getRobolectricPackageManager().addResolveInfoForIntent(serviceIntent, resolveInfo);

        boolean ret = OneSignalPackagePrivateHelper.GcmBroadcastReceiver_processBundle(blankActivity, bundle);
        Assert.assertTrue(ret);

        Intent intent = Shadows.shadowOf(blankActivity).getNextStartedService();
        Assert.assertEquals("com.onesignal.NotificationExtender", intent.getAction());

        // Test that all options are set.
        NotificationExtenderServiceTest service = (NotificationExtenderServiceTest) startNotificationExtender(
                createInternalPayloadBundle(getBundleWithAllOptionsSet()), NotificationExtenderServiceTest.class);

        OSNotificationReceivedResult notificationReceived = service.notification;
        OSNotificationPayload notificationPayload = notificationReceived.payload;
        Assert.assertEquals("Test H", notificationPayload.title);
        Assert.assertEquals("Test B", notificationPayload.body);
        Assert.assertEquals("9764eaeb-10ce-45b1-a66d-8f95938aaa51", notificationPayload.notificationID);

        Assert.assertEquals(0, notificationPayload.lockScreenVisibility);
        Assert.assertEquals("FF0000FF", notificationPayload.smallIconAccentColor);
        Assert.assertEquals("703322744261", notificationPayload.fromProjectNumber);
        Assert.assertEquals("FFFFFF00", notificationPayload.ledColor);
        Assert.assertEquals("big_picture", notificationPayload.bigPicture);
        Assert.assertEquals("large_icon", notificationPayload.largeIcon);
        Assert.assertEquals("small_icon", notificationPayload.smallIcon);
        Assert.assertEquals("test_sound", notificationPayload.sound);
        Assert.assertEquals("You test $[notif_count] MSGs!", notificationPayload.groupMessage);
        Assert.assertEquals("http://google.com", notificationPayload.launchURL);
        Assert.assertEquals(10, notificationPayload.priority);
        Assert.assertEquals("a_key", notificationPayload.collapseId);

        Assert.assertEquals("id1", notificationPayload.actionButtons.get(0).id);
        Assert.assertEquals("button1", notificationPayload.actionButtons.get(0).text);
        Assert.assertEquals("ic_menu_share", notificationPayload.actionButtons.get(0).icon);
        Assert.assertEquals("id2", notificationPayload.actionButtons.get(1).id);
        Assert.assertEquals("button2", notificationPayload.actionButtons.get(1).text);
        Assert.assertEquals("ic_menu_send", notificationPayload.actionButtons.get(1).icon);

        Assert.assertEquals("test_image_url", notificationPayload.backgroundImageLayout.image);
        Assert.assertEquals("FF000000", notificationPayload.backgroundImageLayout.titleTextColor);
        Assert.assertEquals("FFFFFFFF", notificationPayload.backgroundImageLayout.bodyTextColor);

        JSONObject additionalData = notificationPayload.additionalData;
        Assert.assertEquals("myValue", additionalData.getString("myKey"));
        Assert.assertEquals("nValue", additionalData.getJSONObject("nested").getString("nKey"));

        Assert.assertNotSame(-1, service.notificationId);

        // Test a basic notification without anything special.
        startNotificationExtender(createInternalPayloadBundle(getBaseNotifBundle()),
                NotificationExtenderServiceTest.class);
        Assert.assertFalse(ShadowOneSignal.messages.contains("Error assigning"));

        // Test that a notification is still displayed if the developer's code in onNotificationProcessing throws an Exception.
        NotificationExtenderServiceTest.throwInAppCode = true;
        startNotificationExtender(createInternalPayloadBundle(getBaseNotifBundle("NewUUID1")),
                NotificationExtenderServiceTest.class);

        Assert.assertTrue(ShadowOneSignal.messages.contains("onNotificationProcessing throw an exception"));
        Map<Integer, PostedNotification> postedNotifs = ShadowRoboNotificationManager.notifications;
        Assert.assertEquals(3, postedNotifs.size());
    }

    private static Bundle getBundleWithAllOptionsSet() {
        Bundle bundle = new Bundle();

        bundle.putString("title", "Test H");
        bundle.putString("alert", "Test B");
        bundle.putString("bgn", "1");
        bundle.putString("vis", "0");
        bundle.putString("bgac", "FF0000FF");
        bundle.putString("from", "703322744261");
        bundle.putString("ledc", "FFFFFF00");
        bundle.putString("bicon", "big_picture");
        bundle.putString("licon", "large_icon");
        bundle.putString("sicon", "small_icon");
        bundle.putString("sound", "test_sound");
        bundle.putString("grp_msg", "You test $[notif_count] MSGs!");
        bundle.putString("collapse_key", "a_key"); // GCM sets this to 'do_not_collapse' when not set.
        bundle.putString("bg_img",
                "{\"img\": \"test_image_url\"," + "\"tc\": \"FF000000\"," + "\"bc\": \"FFFFFFFF\"}");

        bundle.putInt("pri", 10);
        bundle.putString("custom", "{\"a\": {" + "        \"myKey\": \"myValue\","
                + "        \"nested\": {\"nKey\": \"nValue\"},"
                + "        \"actionButtons\": [{\"id\": \"id1\", \"text\": \"button1\", \"icon\": \"ic_menu_share\"},"
                + "                            {\"id\": \"id2\", \"text\": \"button2\", \"icon\": \"ic_menu_send\"}"
                + "        ]," + "         \"actionSelected\": \"__DEFAULT__\"" + "      },"
                + "\"u\":\"http://google.com\"," + "\"i\":\"9764eaeb-10ce-45b1-a66d-8f95938aaa51\"" + "}");

        return bundle;
    }

    static abstract class NotificationExtenderServiceTestBase extends NotificationExtenderService {
        // Override onStart to manually call onHandleIntent on the main thread.
        @Override
        public void onStart(Intent intent, int startId) {
            onHandleIntent(intent);
            stopSelf(startId);
        }
    }

    static int overrideNotificationId;

    public static class NotificationExtenderServiceTest extends NotificationExtenderServiceTestBase {
        public OSNotificationReceivedResult notification;
        public int notificationId = -1;
        public static boolean throwInAppCode;

        @Override
        protected boolean onNotificationProcessing(OSNotificationReceivedResult notification) {
            if (throwInAppCode)
                throw new NullPointerException();

            this.notification = notification;

            OverrideSettings overrideSettings = new OverrideSettings();
            if (overrideNotificationId != -1)
                overrideSettings.androidNotificationId = overrideNotificationId;

            notificationId = displayNotification(overrideSettings).androidNotificationId;

            return true;
        }
    }

    public static class NotificationExtenderServiceOverrideProperties extends NotificationExtenderServiceTestBase {

        @Override
        protected boolean onNotificationProcessing(OSNotificationReceivedResult notification) {

            OverrideSettings overrideSettings = new OverrideSettings();
            overrideSettings.extender = new NotificationCompat.Extender() {
                @Override
                public NotificationCompat.Builder extend(NotificationCompat.Builder builder) {
                    // Must disable the default sound when setting a custom one
                    builder.mNotification.flags &= ~Notification.DEFAULT_SOUND;
                    builder.setDefaults(builder.mNotification.flags);

                    return builder.setSound(Uri.parse("content://media/internal/audio/media/32"))
                            .setColor(new BigInteger("FF00FF00", 16).intValue()).setContentTitle("[Modified Tile]")
                            .setStyle(new NotificationCompat.BigTextStyle().bigText("[Modified Body(bigText)]"))
                            .setContentText("[Modified Body(ContentText)]");
                }
            };
            displayNotification(overrideSettings);

            return true;
        }
    }

    public static class NotificationExtenderServiceTestReturnFalse extends NotificationExtenderServiceTest {
        @Override
        protected boolean onNotificationProcessing(OSNotificationReceivedResult notification) {
            return false;
        }
    }
}