chromium/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/MockNotificationManagerProxy.java

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.components.browser_ui.notifications;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;

import androidx.annotation.Nullable;

import org.chromium.base.Callback;
import org.chromium.base.task.PostTask;
import org.chromium.base.task.TaskTraits;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * Mocked implementation of the NotificationManagerProxy. Imitates behavior of the Android
 * notification manager, and provides access to the displayed notifications for tests.
 */
public class MockNotificationManagerProxy implements NotificationManagerProxy {
    private static final String KEY_SEPARATOR = ":";

    /** Holds a notification and the arguments passed to #notify and #cancel. */
    public static class NotificationEntry implements StatusBarNotificationProxy {
        public final Notification notification;
        public final String tag;
        public final int id;

        public NotificationEntry(Notification notification, String tag, int id) {
            this.notification = notification;
            this.tag = tag;
            this.id = id;
        }

        @Override
        public int getId() {
            return id;
        }

        @Override
        public String getTag() {
            return tag;
        }

        @Override
        public Notification getNotification() {
            return notification;
        }
    }

    // Maps (id:tag) to a NotificationEntry.
    private final Map<String, NotificationEntry> mNotifications;

    private int mMutationCount;

    private boolean mNotificationsEnabled = true;

    public MockNotificationManagerProxy() {
        mNotifications = new LinkedHashMap<>();
        mMutationCount = 0;
    }

    /**
     * Returns the notifications currently managed by the mocked notification manager, in the order
     * in which they were shown, together with their associated tag and id. The list is not updated
     * when the internal data structure changes.
     *
     * @return List of the managed notifications.
     */
    public List<NotificationEntry> getNotifications() {
        return new ArrayList<>(mNotifications.values());
    }

    /**
     * May be used by tests to determine if a call has recently successfully been handled by the
     * notification manager. If the mutation count is higher than zero, it will be decremented by
     * one automatically.
     *
     * @return The number of recent mutations.
     */
    public int getMutationCountAndDecrement() {
        int mutationCount = mMutationCount;
        if (mutationCount > 0) mMutationCount--;

        return mutationCount;
    }

    public void setNotificationsEnabled(boolean enabled) {
        mNotificationsEnabled = enabled;
    }

    @Override
    public boolean areNotificationsEnabled() {
        return mNotificationsEnabled;
    }

    @Override
    public void cancel(int id) {
        cancel(/* tag= */ null, id);
    }

    @Override
    public void cancel(@Nullable String tag, int id) {
        String key = makeKey(id, tag);
        mNotifications.remove(key);
        mMutationCount++;
    }

    @Override
    public void cancelAll() {
        mNotifications.clear();
        mMutationCount++;
    }

    @Override
    public void notify(int id, Notification notification) {
        notify(/* tag= */ null, id, notification);
    }

    @Override
    public void notify(@Nullable String tag, int id, Notification notification) {
        mNotifications.put(makeKey(id, tag), new NotificationEntry(notification, tag, id));
        mMutationCount++;
    }

    @Override
    public void notify(NotificationWrapper notification) {
        notify(
                notification.getMetadata().tag,
                notification.getMetadata().id,
                notification.getNotification());
    }

    private static String makeKey(int id, @Nullable String tag) {
        String key = Integer.toString(id);
        if (tag != null) key += KEY_SEPARATOR + tag;
        return key;
    }

    // The following Channel methods are not implemented because a naive implementation would
    // have compatibility issues (NotificationChannel is new in O), and we currently don't need them
    // where the MockNotificationManagerProxy is used in tests.

    @Override
    public void createNotificationChannel(NotificationChannel channel) {}

    @Override
    public void createNotificationChannelGroup(NotificationChannelGroup channelGroup) {}

    @Override
    public List<NotificationChannel> getNotificationChannels() {
        return null;
    }

    @Override
    public void getNotificationChannelGroups(Callback<List<NotificationChannelGroup>> callback) {
        callback.onResult(null);
    }

    @Override
    public void getNotificationChannels(Callback<List<NotificationChannel>> callback) {
        callback.onResult(null);
    }

    @Override
    public void deleteNotificationChannel(String id) {}

    @Override
    public void deleteAllNotificationChannels(Function<String, Boolean> func) {}

    @Override
    public NotificationChannel getNotificationChannel(String channelId) {
        return null;
    }

    @Override
    public void deleteNotificationChannelGroup(String groupId) {}

    @Override
    public void getActiveNotifications(
            Callback<List<? extends StatusBarNotificationProxy>> callback) {
        PostTask.runOrPostTask(TaskTraits.UI_DEFAULT, () -> callback.onResult(getNotifications()));
    }
}