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

Commit 25919809 authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Merge cherrypicks of [3054801, 3054802, 3054803, 3055198, 3055199, 3055200] into oc-mr1-release

Change-Id: I3d1525934a1f0575784b9e3d74566bf8412051eb
parents 1ebeeed4 01e41276
Loading
Loading
Loading
Loading
+81 −3
Original line number Diff line number Diff line
@@ -15,8 +15,11 @@
 */
package android.app;

import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.NotificationManager.Importance;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.media.AudioAttributes;
import android.net.Uri;
@@ -26,6 +29,8 @@ import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.text.TextUtils;

import com.android.internal.util.Preconditions;

import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
@@ -562,17 +567,38 @@ public final class NotificationChannel implements Parcelable {
        return mBlockableSystem;
    }

    /**
     * @hide
     */
    public void populateFromXmlForRestore(XmlPullParser parser, Context context) {
        populateFromXml(parser, true, context);
    }

    /**
     * @hide
     */
    @SystemApi
    public void populateFromXml(XmlPullParser parser) {
        populateFromXml(parser, false, null);
    }

    /**
     * If {@param forRestore} is true, {@param Context} MUST be non-null.
     */
    private void populateFromXml(XmlPullParser parser, boolean forRestore,
            @Nullable Context context) {
        Preconditions.checkArgument(!forRestore || context != null,
                "forRestore is true but got null context");

        // Name, id, and importance are set in the constructor.
        setDescription(parser.getAttributeValue(null, ATT_DESC));
        setBypassDnd(Notification.PRIORITY_DEFAULT
                != safeInt(parser, ATT_PRIORITY, Notification.PRIORITY_DEFAULT));
        setLockscreenVisibility(safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY));
        setSound(safeUri(parser, ATT_SOUND), safeAudioAttributes(parser));

        Uri sound = safeUri(parser, ATT_SOUND);
        setSound(forRestore ? restoreSoundUri(context, sound) : sound, safeAudioAttributes(parser));

        enableLights(safeBool(parser, ATT_LIGHTS, false));
        setLightColor(safeInt(parser, ATT_LIGHT_COLOR, DEFAULT_LIGHT_COLOR));
        setVibrationPattern(safeLongArray(parser, ATT_VIBRATION, null));
@@ -584,11 +610,62 @@ public final class NotificationChannel implements Parcelable {
        setBlockableSystem(safeBool(parser, ATT_BLOCKABLE_SYSTEM, false));
    }

    @Nullable
    private Uri restoreSoundUri(Context context, @Nullable Uri uri) {
        if (uri == null) {
            return null;
        }
        ContentResolver contentResolver = context.getContentResolver();
        // There are backups out there with uncanonical uris (because we fixed this after
        // shipping). If uncanonical uris are given to MediaProvider.uncanonicalize it won't
        // verify the uri against device storage and we'll possibly end up with a broken uri.
        // We then canonicalize the uri to uncanonicalize it back, which means we properly check
        // the uri and in the case of not having the resource we end up with the default - better
        // than broken. As a side effect we'll canonicalize already canonicalized uris, this is fine
        // according to the docs because canonicalize method has to handle canonical uris as well.
        Uri canonicalizedUri = contentResolver.canonicalize(uri);
        if (canonicalizedUri == null) {
            // We got a null because the uri in the backup does not exist here, so we return default
            return Settings.System.DEFAULT_NOTIFICATION_URI;
        }
        return contentResolver.uncanonicalize(canonicalizedUri);
    }

    /**
     * @hide
     */
    @SystemApi
    public void writeXml(XmlSerializer out) throws IOException {
        writeXml(out, false, null);
    }

    /**
     * @hide
     */
    public void writeXmlForBackup(XmlSerializer out, Context context) throws IOException {
        writeXml(out, true, context);
    }

    private Uri getSoundForBackup(Context context) {
        Uri sound = getSound();
        if (sound == null) {
            return null;
        }
        Uri canonicalSound = context.getContentResolver().canonicalize(sound);
        if (canonicalSound == null) {
            // The content provider does not support canonical uris so we backup the default
            return Settings.System.DEFAULT_NOTIFICATION_URI;
        }
        return canonicalSound;
    }

    /**
     * If {@param forBackup} is true, {@param Context} MUST be non-null.
     */
    private void writeXml(XmlSerializer out, boolean forBackup, @Nullable Context context)
            throws IOException {
        Preconditions.checkArgument(!forBackup || context != null,
                "forBackup is true but got null context");
        out.startTag(null, TAG_CHANNEL);
        out.attribute(null, ATT_ID, getId());
        if (getName() != null) {
@@ -609,8 +686,9 @@ public final class NotificationChannel implements Parcelable {
            out.attribute(null, ATT_VISIBILITY,
                    Integer.toString(getLockscreenVisibility()));
        }
        if (getSound() != null) {
            out.attribute(null, ATT_SOUND, getSound().toString());
        Uri sound = forBackup ? getSoundForBackup(context) : getSound();
        if (sound != null) {
            out.attribute(null, ATT_SOUND, sound.toString());
        }
        if (getAudioAttributes() != null) {
            out.attribute(null, ATT_USAGE, Integer.toString(getAudioAttributes().getUsage()));
+17 −3
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -517,14 +518,27 @@ final class ServiceRecord extends Binder {
                            } catch (PackageManager.NameNotFoundException e) {
                            }
                        }
                        if (localForegroundNoti.getSmallIcon() == null
                                || nm.getNotificationChannel(localPackageName, appUid,
                        if (nm.getNotificationChannel(localPackageName, appUid,
                                localForegroundNoti.getChannelId()) == null) {
                            int targetSdkVersion = Build.VERSION_CODES.O_MR1;
                            try {
                                final ApplicationInfo applicationInfo =
                                        ams.mContext.getPackageManager().getApplicationInfoAsUser(
                                                appInfo.packageName, 0, userId);
                                targetSdkVersion = applicationInfo.targetSdkVersion;
                            } catch (PackageManager.NameNotFoundException e) {
                            }
                            if (targetSdkVersion >= Build.VERSION_CODES.O_MR1) {
                                throw new RuntimeException(
                                        "invalid channel for service notification: "
                                                + foregroundNoti);
                            }
                        }
                        if (localForegroundNoti.getSmallIcon() == null) {
                            // Notifications whose icon is 0 are defined to not show
                            // a notification, silently ignoring it.  We don't want to
                            // just ignore it, we want to prevent the service from
                            // being foreground.
                            // Also every notification needs a channel.
                            throw new RuntimeException("invalid service notification: "
                                    + foregroundNoti);
                        }
+23 −8
Original line number Diff line number Diff line
@@ -281,6 +281,7 @@ public class NotificationManagerService extends SystemService {
    private WindowManagerInternal mWindowManagerInternal;
    private AlarmManager mAlarmManager;
    private ICompanionDeviceManager mCompanionManager;
    private AccessibilityManager mAccessibilityManager;

    final IBinder mForegroundToken = new Binder();
    private WorkerHandler mHandler;
@@ -1190,6 +1191,12 @@ public class NotificationManagerService extends SystemService {
        mUsageStats = us;
    }

    @VisibleForTesting
    void setAccessibilityManager(AccessibilityManager am) {
        mAccessibilityManager = am;
    }


    // TODO: All tests should use this init instead of the one-off setters above.
    @VisibleForTesting
    void init(Looper looper, IPackageManager packageManager,
@@ -1204,6 +1211,8 @@ public class NotificationManagerService extends SystemService {
                Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
                DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);

        mAccessibilityManager =
                (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
        mAm = ActivityManager.getService();
        mPackageManager = packageManager;
        mPackageManagerClient = packageManagerClient;
@@ -4015,13 +4024,16 @@ public class NotificationManagerService extends SystemService {
        // These are set inside the conditional if the notification is allowed to make noise.
        boolean hasValidVibrate = false;
        boolean hasValidSound = false;

        if (aboveThreshold && isNotificationForCurrentUser(record)) {
        boolean sentAccessibilityEvent = false;
        // If the notification will appear in the status bar, it should send an accessibility
        // event
        if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
            sendAccessibilityEvent(notification, record.sbn.getPackageName());
            sentAccessibilityEvent = true;
        }

        if (aboveThreshold && isNotificationForCurrentUser(record)) {

            if (mSystemReady && mAudioManager != null) {
                Uri soundUri = record.getSound();
                hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
@@ -4039,6 +4051,10 @@ public class NotificationManagerService extends SystemService {

                boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
                if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
                    if (!sentAccessibilityEvent) {
                        sendAccessibilityEvent(notification, record.sbn.getPackageName());
                        sentAccessibilityEvent = true;
                    }
                    if (DBG) Slog.v(TAG, "Interrupting!");
                    if (hasValidSound) {
                        mSoundNotificationKey = key;
@@ -4556,8 +4572,7 @@ public class NotificationManagerService extends SystemService {
    }

    void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
        AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
        if (!manager.isEnabled()) {
        if (!mAccessibilityManager.isEnabled()) {
            return;
        }

@@ -4571,7 +4586,7 @@ public class NotificationManagerService extends SystemService {
            event.getText().add(tickerText);
        }

        manager.sendAccessibilityEvent(event);
        mAccessibilityManager.sendAccessibilityEvent(event);
    }

    /**
+10 −2
Original line number Diff line number Diff line
@@ -227,7 +227,11 @@ public class RankingHelper implements RankingConfig {
                                if (!TextUtils.isEmpty(id) && !TextUtils.isEmpty(channelName)) {
                                    NotificationChannel channel = new NotificationChannel(id,
                                            channelName, channelImportance);
                                    if (forRestore) {
                                        channel.populateFromXmlForRestore(parser, mContext);
                                    } else {
                                        channel.populateFromXml(parser);
                                    }
                                    r.channels.put(id, channel);
                                }
                            }
@@ -390,7 +394,11 @@ public class RankingHelper implements RankingConfig {
                    }

                    for (NotificationChannel channel : r.channels.values()) {
                        if (!forBackup || (forBackup && !channel.isDeleted())) {
                        if (forBackup) {
                            if (!channel.isDeleted()) {
                                channel.writeXmlForBackup(out, mContext);
                            }
                        } else {
                            channel.writeXml(out);
                        }
                    }
+51 −6
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ import static android.app.Notification.GROUP_ALERT_ALL;
import static android.app.Notification.GROUP_ALERT_CHILDREN;
import static android.app.Notification.GROUP_ALERT_SUMMARY;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_MIN;

import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
@@ -57,7 +58,13 @@ import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Slog;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
import android.view.accessibility.IAccessibilityManagerClient;

import com.android.internal.util.IntPair;
import com.android.server.lights.Light;

import org.junit.Before;
@@ -67,6 +74,8 @@ import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -80,6 +89,8 @@ public class BuzzBeepBlinkTest extends NotificationTestCase {
    NotificationManagerService.WorkerHandler mHandler;
    @Mock
    NotificationUsageStats mUsageStats;
    @Mock
    IAccessibilityManager mAccessibilityService;

    private NotificationManagerService mService;
    private String mPkg = "com.android.server.notification";
@@ -111,17 +122,25 @@ public class BuzzBeepBlinkTest extends NotificationTestCase {
    private static final int MAX_VIBRATION_DELAY = 1000;

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

        when(mAudioManager.isAudioFocusExclusive()).thenReturn(false);
        when(mAudioManager.getRingtonePlayer()).thenReturn(mRingtonePlayer);
        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);

        when(mUsageStats.isAlertRateLimited(any())).thenReturn(false);

        mService = new NotificationManagerService(getContext());
        long serviceReturnValue = IntPair.of(
                AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED,
                AccessibilityEvent.TYPES_ALL_MASK);
        when(mAccessibilityService.addClient(any(), anyInt())).thenReturn(serviceReturnValue);
        AccessibilityManager accessibilityManager =
                new AccessibilityManager(Handler.getMain(), mAccessibilityService, 0);
        verify(mAccessibilityService).addClient(any(IAccessibilityManagerClient.class), anyInt());
        assertTrue(accessibilityManager.isEnabled());

        mService = spy(new NotificationManagerService(getContext()));
        mService.setAudioManager(mAudioManager);
        mService.setVibrator(mVibrator);
        mService.setSystemReady(true);
@@ -130,6 +149,7 @@ public class BuzzBeepBlinkTest extends NotificationTestCase {
        mService.setScreenOn(false);
        mService.setFallbackVibrationPattern(FALLBACK_VIBRATION_PATTERN);
        mService.setUsageStats(mUsageStats);
        mService.setAccessibilityManager(accessibilityManager);
    }

    //
@@ -381,6 +401,7 @@ public class BuzzBeepBlinkTest extends NotificationTestCase {

        verifyBeepLooped();
        verifyNeverVibrate();
        verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
    }

    @Test
@@ -435,6 +456,7 @@ public class BuzzBeepBlinkTest extends NotificationTestCase {
        r.isUpdate = true;
        mService.buzzBeepBlinkLocked(r);
        verifyBeepLooped();
        verify(mAccessibilityService, times(2)).sendAccessibilityEvent(any(), anyInt());
    }

    @Test
@@ -450,6 +472,7 @@ public class BuzzBeepBlinkTest extends NotificationTestCase {
        // update should not beep
        mService.buzzBeepBlinkLocked(s);
        verifyNeverBeep();
        verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
    }

    @Test
@@ -547,7 +570,7 @@ public class BuzzBeepBlinkTest extends NotificationTestCase {
        mService.mInCall = true;
        mService.buzzBeepBlinkLocked(r);

        //verify(mService, times(1)).playInCallNotification();
        verify(mService, times(1)).playInCallNotification();
        verifyNeverBeep(); // doesn't play normal beep
    }

@@ -842,7 +865,6 @@ public class BuzzBeepBlinkTest extends NotificationTestCase {
        mService.addNotification(r);

        mService.buzzBeepBlinkLocked(r);

        verifyNeverBeep();
    }

@@ -870,7 +892,6 @@ public class BuzzBeepBlinkTest extends NotificationTestCase {
        summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;

        mService.buzzBeepBlinkLocked(summary);

        verify(mUsageStats, never()).isAlertRateLimited(any());
    }

@@ -889,6 +910,30 @@ public class BuzzBeepBlinkTest extends NotificationTestCase {
        verifyNeverBeep();
    }

    @Test
    public void testA11yMinInitialPost() throws Exception {
        NotificationRecord r = getQuietNotification();
        r.setImportance(IMPORTANCE_MIN, "");
        mService.buzzBeepBlinkLocked(r);
        verify(mAccessibilityService, never()).sendAccessibilityEvent(any(), anyInt());
    }

    @Test
    public void testA11yQuietInitialPost() throws Exception {
        NotificationRecord r = getQuietNotification();
        mService.buzzBeepBlinkLocked(r);
        verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
    }

    @Test
    public void testA11yQuietUpdate() throws Exception {
        NotificationRecord r = getQuietNotification();
        mService.buzzBeepBlinkLocked(r);
        r.isUpdate = true;
        mService.buzzBeepBlinkLocked(r);
        verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
    }

    static class VibrateRepeatMatcher implements ArgumentMatcher<VibrationEffect> {
        private final int mRepeatIndex;

Loading