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

Commit 80fa6b58 authored by Alison Cichowlas's avatar Alison Cichowlas
Browse files

Limit unconfigurability to specified channels.

Bug: 62426259
Test: Unit test in NotificationBackendTest.java
Change-Id: I79d069cee0b641d520b02f8a25751ec3e0d4632d
parent d77b699e
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -212,7 +212,8 @@ public class AppNotificationSettings extends NotificationSettingsBase {
        MasterSwitchPreference channelPref = new MasterSwitchPreference(
                getPrefContext());
        channelPref.setSwitchEnabled(mSuspendedAppsAdmin == null
                &&  isChannelBlockable(mAppRow.systemApp, channel));
                && isChannelBlockable(mAppRow.systemApp, channel)
                && isChannelConfigurable(channel));
        channelPref.setKey(channel.getId());
        channelPref.setTitle(channel.getName());
        channelPref.setChecked(channel.getImportance() != IMPORTANCE_NONE);
+3 −3
Original line number Diff line number Diff line
@@ -214,7 +214,7 @@ public class ChannelNotificationSettings extends NotificationSettingsBase {
    private void setupVibrate() {
        mVibrate = (RestrictedSwitchPreference) findPreference(KEY_VIBRATE);
        mVibrate.setDisabledByAdmin(mSuspendedAppsAdmin);
        mVibrate.setEnabled(!(mAppRow.lockedImportance || mVibrate.isDisabledByAdmin()));
        mVibrate.setEnabled(!mVibrate.isDisabledByAdmin() && isChannelConfigurable(mChannel));
        mVibrate.setChecked(mChannel.shouldVibrate());
        mVibrate.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
            @Override
@@ -231,7 +231,7 @@ public class ChannelNotificationSettings extends NotificationSettingsBase {
    private void setupRingtone() {
        mRingtone = (NotificationSoundPreference) findPreference(KEY_RINGTONE);
        mRingtone.setRingtone(mChannel.getSound());
        mRingtone.setEnabled(!(mAppRow.lockedImportance));
        mRingtone.setEnabled(isChannelConfigurable(mChannel));
        mRingtone.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
            @Override
            public boolean onPreferenceChange(Preference preference, Object newValue) {
@@ -287,7 +287,7 @@ public class ChannelNotificationSettings extends NotificationSettingsBase {
        channelArgs.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
        channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
        channelArgs.putString(Settings.EXTRA_CHANNEL_ID, mChannel.getId());
        mImportance.setEnabled(mSuspendedAppsAdmin == null && !mAppRow.lockedImportance);
        mImportance.setEnabled(mSuspendedAppsAdmin == null && isChannelConfigurable(mChannel));
        // Set up intent to show importance selection only if this setting is enabled.
        if (mImportance.isEnabled()) {
            Intent channelIntent = Utils.onBuildStartFragmentIntent(getActivity(),
+17 −2
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.os.UserHandle;
import android.util.IconDrawableFactory;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.Utils;

public class NotificationBackend {
@@ -60,15 +61,28 @@ public class NotificationBackend {
        row.systemApp = Utils.isSystemPackage(context.getResources(), pm, app);
        final String[] nonBlockablePkgs = context.getResources().getStringArray(
                    com.android.internal.R.array.config_nonBlockableNotificationPackages);
        markAppRowWithBlockables(nonBlockablePkgs, row, app.packageName);
        return row;
    }

    @VisibleForTesting static void markAppRowWithBlockables(String[] nonBlockablePkgs, AppRow row,
            String packageName) {
        if (nonBlockablePkgs != null) {
            int N = nonBlockablePkgs.length;
            for (int i = 0; i < N; i++) {
                if (app.packageName.equals(nonBlockablePkgs[i])) {
                String pkg = nonBlockablePkgs[i];
                if (pkg == null) {
                    continue;
                } else if (pkg.contains(":")) {
                    // Interpret as channel; lock only this channel for this app.
                    if (packageName.equals(pkg.split(":", 2)[0])) {
                        row.lockedChannelId = pkg.split(":", 2 )[1];
                    }
                } else if (packageName.equals(nonBlockablePkgs[i])) {
                    row.systemApp = row.lockedImportance = true;
                }
            }
        }
        return row;
    }

    public boolean getNotificationsBanned(String pkg, int uid) {
@@ -184,6 +198,7 @@ public class NotificationBackend {
        public boolean first;  // first app in section
        public boolean systemApp;
        public boolean lockedImportance;
        public String lockedChannelId;
        public boolean showBadge;
        public int userId;
    }
+8 −3
Original line number Diff line number Diff line
@@ -293,8 +293,8 @@ abstract public class NotificationSettingsBase extends SettingsPreferenceFragmen
    private void setupImportanceToggle() {
        mImportanceToggle = (RestrictedSwitchPreference) findPreference(KEY_ALLOW_SOUND);
        mImportanceToggle.setDisabledByAdmin(mSuspendedAppsAdmin);
        mImportanceToggle.setEnabled(!(mAppRow.lockedImportance
                || mImportanceToggle.isDisabledByAdmin()));
        mImportanceToggle.setEnabled(isChannelConfigurable(mChannel)
                && !mImportanceToggle.isDisabledByAdmin());
        mImportanceToggle.setChecked(mChannel.getImportance() >= IMPORTANCE_DEFAULT
                || mChannel.getImportance() == IMPORTANCE_UNSPECIFIED);
        mImportanceToggle.setOnPreferenceChangeListener(
@@ -315,7 +315,7 @@ abstract public class NotificationSettingsBase extends SettingsPreferenceFragmen
    protected void setupPriorityPref(boolean priority) {
        mPriority = (RestrictedSwitchPreference) findPreference(KEY_BYPASS_DND);
        mPriority.setDisabledByAdmin(mSuspendedAppsAdmin);
        mPriority.setEnabled(!(mAppRow.lockedImportance || mPriority.isDisabledByAdmin()));
        mPriority.setEnabled(isChannelConfigurable(mChannel) && !mPriority.isDisabledByAdmin());
        mPriority.setChecked(priority);
        mPriority.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
            @Override
@@ -447,10 +447,15 @@ abstract public class NotificationSettingsBase extends SettingsPreferenceFragmen
        return lockscreenSecure;
    }

    protected boolean isChannelConfigurable(NotificationChannel channel) {
        return !channel.getId().equals(mAppRow.lockedChannelId);
    }

    protected boolean isChannelBlockable(boolean systemApp, NotificationChannel channel) {
        if (!mAppRow.systemApp) {
            return true;
        }

        return channel.isBlockableSystem()
                || channel.getImportance() == NotificationManager.IMPORTANCE_NONE;
    }
+134 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */

package com.android.settings.notification;

import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
import android.content.Context;
import android.support.v7.preference.Preference;

import com.android.settings.R;
import com.android.settings.notification.NotificationBackend.AppRow;
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import org.robolectric.annotation.Config;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;


@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class NotificationBackendTest {

    @Test
    public void testMarkAppRow_unblockablePackage() {
        AppRow appRow = new AppRow();
        String packageName = "foo.bar.unblockable";
        appRow.pkg = packageName;
        String[] nonBlockablePkgs = new String[2];
        nonBlockablePkgs[0] = packageName;
        nonBlockablePkgs[1] = "some.other.package";
        NotificationBackend.markAppRowWithBlockables(nonBlockablePkgs, appRow, packageName);

        // This package has a package lock but no locked channels
        assertTrue(appRow.lockedImportance);
        assertNull(appRow.lockedChannelId);
    }

    @Test
    public void testMarkAppRow_unblockableChannelOrPkg() {
        String channelBlockName = "foo.bar.pkgWithChannel";
        String pkgBlockName = "foo.bar.pkgBlock";
        String[] nonBlockablePkgs = new String[2];
        nonBlockablePkgs[0] = pkgBlockName;
        nonBlockablePkgs[1] = channelBlockName + ":SpecificChannel";

        // This package has a channel level lock but no full package lock
        AppRow channelBlockApp = new AppRow();
        channelBlockApp.pkg = channelBlockName;
        NotificationBackend.markAppRowWithBlockables(nonBlockablePkgs, channelBlockApp,
                channelBlockName);
        assertFalse(channelBlockApp.lockedImportance);
        assertEquals("SpecificChannel", channelBlockApp.lockedChannelId);

        // This other package has the reverse
        AppRow pkgBlock = new AppRow();
        pkgBlock.pkg = pkgBlockName;
        NotificationBackend.markAppRowWithBlockables(nonBlockablePkgs, pkgBlock, pkgBlockName);
        assertTrue(pkgBlock.lockedImportance);
        assertNull(pkgBlock.lockedChannelId);

        // This third package has no locks at all
        AppRow otherAppRow = new AppRow();
        otherAppRow.pkg ="foo.bar.nothingBlocked";
        NotificationBackend.markAppRowWithBlockables(nonBlockablePkgs, otherAppRow,
                "foo.bar.nothingBlocked");
        assertFalse(otherAppRow.lockedImportance);
        assertNull(otherAppRow.lockedChannelId);
    }

    @Test
    public void testMarkAppRow_unblockableChannelAndPkg() {
        AppRow appRow = new AppRow();
        String packageName = "foo.bar.unblockable";
        appRow.pkg = packageName;
        String[] nonBlockablePkgs = new String[2];
        nonBlockablePkgs[0] = "foo.bar.unblockable";
        nonBlockablePkgs[1] = "foo.bar.unblockable:SpecificChannel";
        NotificationBackend.markAppRowWithBlockables(nonBlockablePkgs, appRow, packageName);

        // This package has both a channel lock and a package lock
        assertTrue(appRow.lockedImportance);
        assertEquals("SpecificChannel", appRow.lockedChannelId);
    }

    @Test
    public void testMarkAppRow_channelNameWithColons() {
        AppRow appRow = new AppRow();
        String packageName = "foo.bar.unblockable";
        String channelName = "SpecificChannel:1234:abc:defg";
        appRow.pkg = packageName;
        String[] nonBlockablePkgs = new String[1];
        nonBlockablePkgs[0] = packageName + ":" + channelName;
        NotificationBackend.markAppRowWithBlockables(nonBlockablePkgs, appRow, packageName);

        assertEquals(channelName, appRow.lockedChannelId);
    }


    @Test
    public void testMarkAppRow_blocklistWithNullEntries() {
        AppRow appRow = new AppRow();
        String packageName = "foo.bar.unblockable";
        appRow.pkg = packageName;
        String[] nonBlockablePkgs = new String[6]; // extra long list with some entries left null
        nonBlockablePkgs[2] = "foo.bar.unblockable";
        nonBlockablePkgs[4] = "foo.bar.unblockable:SpecificChannel";
        NotificationBackend.markAppRowWithBlockables(nonBlockablePkgs, appRow, packageName);

        assertTrue(appRow.lockedImportance);
        assertEquals("SpecificChannel", appRow.lockedChannelId);
    }
}