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

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

Merge "One time permission grant to default noti assistant"

parents 1507c3ef 7380d873
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -3249,4 +3249,7 @@
    <string name="config_fontFamilyButton">@string/font_family_button_material</string>

    <string translatable="false" name="config_batterySaverDeviceSpecificConfig"></string>

    <!-- Package name that should be granted Notification Assistant access -->
    <string name="config_defaultAssistantAccessPackage" translatable="false">android.ext.services</string>
</resources>
+2 −0
Original line number Diff line number Diff line
@@ -3216,4 +3216,6 @@
  <java-symbol type="string" name="harmful_app_warning_uninstall" />
  <java-symbol type="string" name="harmful_app_warning_launch_anyway" />
  <java-symbol type="string" name="harmful_app_warning_title" />

  <java-symbol type="string" name="config_defaultAssistantAccessPackage" />
</resources>
+18 −1
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@@ -98,6 +99,9 @@ abstract public class ManagedServices {
    static final String ATT_APPROVED_LIST = "approved";
    static final String ATT_USER_ID = "user";
    static final String ATT_IS_PRIMARY = "primary";
    static final String ATT_VERSION = "version";

    static final int DB_VERSION = 1;

    static final int APPROVAL_BY_PACKAGE = 0;
    static final int APPROVAL_BY_COMPONENT = 1;
@@ -295,6 +299,8 @@ abstract public class ManagedServices {
    public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
        out.startTag(null, getConfig().xmlTag);

        out.attribute(null, ATT_VERSION, String.valueOf(DB_VERSION));

        if (forBackup) {
            trimApprovedListsAccordingToInstalledServices();
        }
@@ -336,6 +342,14 @@ abstract public class ManagedServices {

    public void readXml(XmlPullParser parser)
            throws XmlPullParserException, IOException {
        // upgrade xml
        int xmlVersion = XmlUtils.readIntAttribute(parser, ATT_VERSION, 0);
        final List<UserInfo> activeUsers = mUm.getUsers(true);
        for (UserInfo userInfo : activeUsers) {
            upgradeXml(xmlVersion, userInfo.getUserHandle().getIdentifier());
        }

        // read grants
        int type;
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
            String tag = parser.getName();
@@ -346,6 +360,7 @@ abstract public class ManagedServices {
            if (type == XmlPullParser.START_TAG) {
                if (TAG_MANAGED_SERVICES.equals(tag)) {
                    Slog.i(TAG, "Read " + mConfig.caption + " permissions from xml");

                    final String approved = XmlUtils.readStringAttribute(parser, ATT_APPROVED_LIST);
                    final int userId = XmlUtils.readIntAttribute(parser, ATT_USER_ID, 0);
                    final boolean isPrimary =
@@ -360,6 +375,8 @@ abstract public class ManagedServices {
        rebindServices(false);
    }

    protected void upgradeXml(final int xmlVersion, final int userId) {}

    private void loadAllowedComponentsFromSettings() {

        UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
@@ -379,7 +396,7 @@ abstract public class ManagedServices {
        Slog.d(TAG, "Done loading approved values from settings");
    }

    private void addApprovedList(String approved, int userId, boolean isPrimary) {
    protected void addApprovedList(String approved, int userId, boolean isPrimary) {
        if (TextUtils.isEmpty(approved)) {
            approved = "";
        }
+39 −4
Original line number Diff line number Diff line
@@ -434,6 +434,7 @@ public class NotificationManagerService extends SystemService {
                }
            }
        }

        String defaultDndAccess = getContext().getResources().getString(
                com.android.internal.R.string.config_defaultDndAccessPackages);
        if (defaultListenerAccess != null) {
@@ -446,6 +447,29 @@ public class NotificationManagerService extends SystemService {
                }
            }
        }

        readDefaultAssistant(userId);
    }

    protected void readDefaultAssistant(int userId) {
        String defaultAssistantAccess = getContext().getResources().getString(
                com.android.internal.R.string.config_defaultAssistantAccessPackage);
        if (defaultAssistantAccess != null) {
            // Gather all notification assistant components for candidate pkg. There should
            // only be one
            Set<ComponentName> approvedAssistants =
                    mAssistants.queryPackageForServices(defaultAssistantAccess,
                            PackageManager.MATCH_DIRECT_BOOT_AWARE
                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
            for (ComponentName cn : approvedAssistants) {
                try {
                    getBinderService().setNotificationAssistantAccessGrantedForUser(cn,
                            userId, true);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    void readPolicyXml(InputStream stream, boolean forRestore)
@@ -1155,6 +1179,7 @@ public class NotificationManagerService extends SystemService {
        }
    }

    @VisibleForTesting
    void clearNotifications() {
        mEnqueuedNotifications.clear();
        mNotificationList.clear();
@@ -1374,7 +1399,8 @@ public class NotificationManagerService extends SystemService {
                AppGlobals.getPackageManager(), getContext().getPackageManager(),
                getLocalService(LightsManager.class),
                new NotificationListeners(AppGlobals.getPackageManager()),
                new NotificationAssistants(AppGlobals.getPackageManager()),
                new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles,
                        AppGlobals.getPackageManager()),
                new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
                null, snoozeHelper, new NotificationUsageStats(getContext()),
                new AtomicFile(new File(systemDir, "notification_policy.xml")),
@@ -5553,8 +5579,9 @@ public class NotificationManagerService extends SystemService {
    public class NotificationAssistants extends ManagedServices {
        static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";

        public NotificationAssistants(IPackageManager pm) {
            super(getContext(), mNotificationLock, mUserProfiles, pm);
        public NotificationAssistants(Context context, Object lock, UserProfiles up,
                IPackageManager pm) {
            super(context, lock, up, pm);
        }

        @Override
@@ -5659,6 +5686,14 @@ public class NotificationManagerService extends SystemService {
        public boolean isEnabled() {
            return !getServices().isEmpty();
        }

        protected void upgradeXml(final int xmlVersion, final int userId) {
            if (xmlVersion == 0) {
                // one time approval of the OOB assistant
                Slog.d(TAG, "Approving default notification assistant for user " + userId);
                readDefaultAssistant(userId);
            }
        }
    }

    public class NotificationListeners extends ManagedServices {
@@ -6072,7 +6107,7 @@ public class NotificationManagerService extends SystemService {
        public static final String USAGE = "help\n"
                + "allow_listener COMPONENT [user_id]\n"
                + "disallow_listener COMPONENT [user_id]\n"
                + "set_assistant COMPONENT\n"
                + "allow_assistant COMPONENT\n"
                + "remove_assistant COMPONENT\n"
                + "allow_dnd PACKAGE\n"
                + "disallow_dnd PACKAGE";
+174 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.server.notification;

import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.ComponentName;
import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.os.UserManager;
import android.util.Slog;
import android.util.Xml;

import com.android.internal.util.FastXmlSerializer;
import com.android.server.UiServiceTestCase;
import com.android.server.notification.NotificationManagerService.NotificationAssistants;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;

public class NotificationAssistantsTest extends UiServiceTestCase {

    @Mock
    private PackageManager mPm;
    @Mock
    private IPackageManager miPm;
    @Mock
    private UserManager mUm;
    @Mock
    NotificationManagerService mNm;

    NotificationAssistants mAssistants;

    @Mock
    private ManagedServices.UserProfiles mUserProfiles;

    Object mLock = new Object();

    UserInfo mZero = new UserInfo(0, "zero", 0);
    UserInfo mTen = new UserInfo(10, "ten", 0);

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);

        getContext().setMockPackageManager(mPm);
        getContext().addMockSystemService(Context.USER_SERVICE, mUm);
        mAssistants = spy(mNm.new NotificationAssistants(getContext(), mLock, mUserProfiles, miPm));

        List<ResolveInfo> approved = new ArrayList<>();
        ResolveInfo resolve = new ResolveInfo();
        approved.add(resolve);
        ServiceInfo info = new ServiceInfo();
        info.packageName = "a";
        info.name="a";
        resolve.serviceInfo = info;
        when(mPm.queryIntentServicesAsUser(any(), anyInt(), anyInt()))
                .thenReturn(approved);

        List<UserInfo> users = new ArrayList<>();
        users.add(mZero);
        users.add(mTen);
        users.add(new UserInfo(11, "11", 0));
        users.add(new UserInfo(12, "12", 0));
        for (UserInfo user : users) {
            when(mUm.getUserInfo(eq(user.id))).thenReturn(user);
        }
        when(mUm.getUsers()).thenReturn(users);
        when(mUm.getUsers(anyBoolean())).thenReturn(users);
        when(mUserProfiles.getCurrentProfileIds()).thenReturn(new int[] {0, 10, 11, 12});
    }

    @Test
    public void testXmlUpgrade() throws Exception {
        String xml = "<enabled_assistants/>";

        XmlPullParser parser = Xml.newPullParser();
        parser.setInput(new BufferedInputStream(
                new ByteArrayInputStream(xml.toString().getBytes())), null);
        parser.nextTag();
        mAssistants.readXml(parser);

        //once per user
        verify(mNm, times(mUm.getUsers().size())).readDefaultAssistant(anyInt());
    }

    @Test
    public void testXmlUpgradeExistingApprovedComponents() throws Exception {
        String xml = "<enabled_assistants>"
                + "<service_listing approved=\"b/b\" user=\"10\" primary=\"true\" />"
                + "</enabled_assistants>";

        XmlPullParser parser = Xml.newPullParser();
        parser.setInput(new BufferedInputStream(
                new ByteArrayInputStream(xml.toString().getBytes())), null);
        parser.nextTag();
        mAssistants.readXml(parser);

        // once per user
        verify(mNm, times(mUm.getUsers().size())).readDefaultAssistant(anyInt());
        verify(mAssistants, times(1)).addApprovedList(
                new ComponentName("b", "b").flattenToString(),10, true);
    }

    @Test
    public void testXmlUpgradeOnce() throws Exception {
        String xml = "<enabled_assistants/>";

        XmlPullParser parser = Xml.newPullParser();
        parser.setInput(new BufferedInputStream(
                new ByteArrayInputStream(xml.toString().getBytes())), null);
        parser.nextTag();
        mAssistants.readXml(parser);

        XmlSerializer serializer = new FastXmlSerializer();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
        serializer.startDocument(null, true);
        mAssistants.writeXml(serializer, true);
        serializer.endDocument();
        serializer.flush();

        //once per user
        verify(mNm, times(mUm.getUsers().size())).readDefaultAssistant(anyInt());

        Mockito.reset(mNm);

        parser = Xml.newPullParser();
        parser.setInput(new BufferedInputStream(
                new ByteArrayInputStream(baos.toByteArray())), null);
        parser.nextTag();
        mAssistants.readXml(parser);

        //once per user
        verify(mNm, never()).readDefaultAssistant(anyInt());
    }
}