Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c7bc9df6 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Log notification channels and groups."

parents ce29b882 d373d78d
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -3495,6 +3495,28 @@ message MetricsEvent {
    // FIELD: The new value of preference when it is changed in Settings
    FIELD_SETTINGS_PREFERENCE_CHANGE_VALUE = 855;

    // OPEN: Notification channel created. CLOSE: Notification channel deleted. UPDATE: notification
    // channel updated
    // PACKAGE: the package the channel belongs too
    // CATEGORY: NOTIFICATION
    // OS: O
    ACTION_NOTIFICATION_CHANNEL = 856;

    // Tagged data for notification channel. String.
    FIELD_NOTIFICATION_CHANNEL_ID = 857;

    // Tagged data for notification channel. int.
    FIELD_NOTIFICATION_CHANNEL_IMPORTANCE = 858;

    // OPEN: Notification channel group created.
    // PACKAGE: the package the group belongs to
    // CATEGORY: NOTIFICATION
    // OS: O
    ACTION_NOTIFICATION_CHANNEL_GROUP = 859;

    // Tagged data for notification channel group. String.
    FIELD_NOTIFICATION_CHANNEL_GROUP_ID = 860;

    // ---- End O Constants, all O constants go above this line ----

    // Add new aosp constants above this line.
+1 −0
Original line number Diff line number Diff line
@@ -2792,6 +2792,7 @@ public class NotificationManagerService extends SystemService {
            dump.put("bans", mRankingHelper.dumpBansJson(filter));
            dump.put("ranking", mRankingHelper.dumpJson(filter));
            dump.put("stats", mUsageStats.dumpJson(filter));
            dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
        } catch (JSONException e) {
            e.printStackTrace();
        }
+74 −1
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ import static android.app.NotificationManager.IMPORTANCE_NONE;

import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.util.Preconditions;

import android.app.Notification;
@@ -30,6 +32,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.metrics.LogMaker;
import android.os.Build;
import android.os.UserHandle;
import android.provider.Settings;
@@ -485,6 +488,12 @@ public class RankingHelper implements RankingConfig {
        if (r == null) {
            throw new IllegalArgumentException("Invalid package");
        }
        LogMaker lm = new LogMaker(MetricsProto.MetricsEvent.ACTION_NOTIFICATION_CHANNEL_GROUP)
                .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
                .addTaggedData(MetricsProto.MetricsEvent.FIELD_NOTIFICATION_CHANNEL_GROUP_ID,
                        group.getId())
                .setPackageName(pkg);
        MetricsLogger.action(lm);
        r.groups.put(group.getId(), group);
        updateConfig();
    }
@@ -516,8 +525,11 @@ public class RankingHelper implements RankingConfig {
        if (existing != null) {
            if (existing.isDeleted()) {
                existing.setDeleted(false);
                updateConfig();
            }

            MetricsLogger.action(getChannelLog(channel, pkg));

            updateConfig();
            return;
        }
        if (channel.getImportance() < NotificationManager.IMPORTANCE_NONE
@@ -541,6 +553,8 @@ public class RankingHelper implements RankingConfig {
                    Notification.AUDIO_ATTRIBUTES_DEFAULT);
        }
        r.channels.put(channel.getId(), channel);
        MetricsLogger.action(getChannelLog(channel, pkg).setType(
                MetricsProto.MetricsEvent.TYPE_OPEN));
        updateConfig();
    }

@@ -568,6 +582,8 @@ public class RankingHelper implements RankingConfig {
            updatedChannel.setLockscreenVisibility(Ranking.VISIBILITY_NO_OVERRIDE);
        }
        r.channels.put(updatedChannel.getId(), updatedChannel);

        MetricsLogger.action(getChannelLog(updatedChannel, pkg));
        updateConfig();
    }

@@ -615,6 +631,7 @@ public class RankingHelper implements RankingConfig {
        }
        // Assistant cannot change the group

        MetricsLogger.action(getChannelLog(channel, pkg));
        r.channels.put(channel.getId(), channel);
        updateConfig();
    }
@@ -664,6 +681,9 @@ public class RankingHelper implements RankingConfig {
        if (channel != null) {
            channel.setDeleted(true);
        }
        LogMaker lm = getChannelLog(channel, pkg);
        lm.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
        MetricsLogger.action(lm);
    }

    @Override
@@ -935,6 +955,49 @@ public class RankingHelper implements RankingConfig {
        return packageBans;
    }

    /**
     * Dump only the channel information as structured JSON for the stats collector.
     *
     * This is intentionally redundant with {#link dumpJson} because the old
     * scraper will expect this format.
     *
     * @param filter
     * @return
     */
    public JSONArray dumpChannelsJson(NotificationManagerService.DumpFilter filter) {
        JSONArray channels = new JSONArray();
        Map<String, Integer> packageChannels = getPackageChannels();
        for(Entry<String, Integer> channelCount : packageChannels.entrySet()) {
            final String packageName = channelCount.getKey();
            if (filter == null || filter.matches(packageName)) {
                JSONObject channelCountJson = new JSONObject();
                try {
                    channelCountJson.put("packageName", packageName);
                    channelCountJson.put("channelCount", channelCount.getValue());
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                channels.put(channelCountJson);
            }
        }
        return channels;
    }

    private Map<String, Integer> getPackageChannels() {
        ArrayMap<String, Integer> packageChannels = new ArrayMap<>();
        for (int i = 0; i < mRecords.size(); i++) {
            final Record r = mRecords.valueAt(i);
            int channelCount = 0;
            for (int j = 0; j < r.channels.size();j++) {
                if (!r.channels.valueAt(j).isDeleted()) {
                    channelCount++;
                }
            }
            packageChannels.put(r.pkg, channelCount);
        }
        return packageChannels;
    }

    public void onPackagesChanged(boolean removingPackage, int changeUserId, String[] pkgList,
            int[] uidList) {
        if (pkgList == null || pkgList.length == 0) {
@@ -982,6 +1045,16 @@ public class RankingHelper implements RankingConfig {
        }
    }

    private LogMaker getChannelLog(NotificationChannel channel, String pkg) {
        return new LogMaker(MetricsProto.MetricsEvent.ACTION_NOTIFICATION_CHANNEL)
                .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
                .setPackageName(pkg)
                .addTaggedData(MetricsProto.MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID,
                        channel.getId())
                .addTaggedData(MetricsProto.MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE,
                        channel.getImportance());
    }

    private static class Record {
        static int UNKNOWN_UID = UserHandle.USER_NULL;

+56 −1
Original line number Diff line number Diff line
@@ -15,12 +15,15 @@
 */
package com.android.server.notification;

import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;

import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.fail;

import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -48,6 +51,7 @@ import android.service.notification.StatusBarNotification;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArrayMap;
import android.util.Xml;

import java.io.BufferedInputStream;
@@ -60,12 +64,14 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;

@@ -991,4 +997,53 @@ public class RankingHelperTest {
            }
        }
    }

    @Test
    public void testCreateChannel_updateNameResId() throws Exception {
        NotificationChannel nc = new NotificationChannel("id", 1, IMPORTANCE_DEFAULT);
        mHelper.createNotificationChannel(pkg, uid, nc, true);

        nc = new NotificationChannel("id", 2, IMPORTANCE_DEFAULT);
        mHelper.createNotificationChannel(pkg, uid, nc, true);

        assertEquals(2, mHelper.getNotificationChannel(pkg, uid, "id", false).getNameResId());
    }

    @Test
    public void testDumpChannelsJson() throws Exception {
        final ApplicationInfo upgrade = new ApplicationInfo();
        upgrade.targetSdkVersion = Build.VERSION_CODES.O;
        try {
            when(mPm.getApplicationInfoAsUser(
                    anyString(), anyInt(), anyInt())).thenReturn(upgrade);
        } catch (PackageManager.NameNotFoundException e) {
        }
        ArrayMap<String, Integer> expectedChannels = new ArrayMap<>();
        int numPackages = ThreadLocalRandom.current().nextInt(1, 5);
        for (int i = 0; i < numPackages; i++) {
            String pkgName = "pkg" + i;
            int numChannels = ThreadLocalRandom.current().nextInt(1, 10);
            for (int j = 0; j < numChannels; j++) {
                mHelper.createNotificationChannel(pkgName, uid,
                        new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true);
            }
            expectedChannels.put(pkgName, numChannels);
        }

        // delete the first channel of the first package
        String pkg = expectedChannels.keyAt(0);
        mHelper.deleteNotificationChannel("pkg" + 0, uid, "0");
        // dump should not include deleted channels
        int count = expectedChannels.get(pkg);
        expectedChannels.put(pkg, count - 1);

        JSONArray actual = mHelper.dumpChannelsJson(new NotificationManagerService.DumpFilter());
        assertEquals(numPackages, actual.length());
        for (int i = 0; i < numPackages; i++) {
            JSONObject object = actual.getJSONObject(i);
            assertTrue(expectedChannels.containsKey(object.get("packageName")));
            assertEquals(expectedChannels.get(object.get("packageName")).intValue() + 1,
                    object.getInt("channelCount"));
        }
    }
}