Prevent notification vibration when the user is on the earpiece.

When the earpiece route is activated, if the user has not already enabled
a notification interruption filter, we will set it to alarms-only.  This
ensures that notifications don't cause the phone to vibrate while in
earpiece mode.

If the user changes the interruption filter during the call we will keep
their new chosen filter when the earpiece route is disabled.

This notification filtering only takes place for the earpiece route.

Bug: 29962221
Change-Id: Ia332a988f10427a2a0f8315af9f31d854836db9f
diff --git a/src/com/android/server/telecom/CallAudioRouteStateMachine.java b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
index a501dca..773e29a 100644
--- a/src/com/android/server/telecom/CallAudioRouteStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
@@ -18,7 +18,11 @@
 
 
 import android.app.ActivityManagerNative;
+import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.UserInfo;
 import android.media.AudioManager;
 import android.media.IAudioService;
@@ -147,6 +151,34 @@
         put(RUN_RUNNABLE, "RUN_RUNNABLE");
     }};
 
+    /**
+     * BroadcastReceiver used to track changes in the notification interruption filter.  This
+     * ensures changes to the notification interruption filter made by the user during a call are
+     * respected when restoring the notification interruption filter state.
+     */
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Log.startSession("CARSM.oR");
+            try {
+                String action = intent.getAction();
+
+                if (action.equals(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED)) {
+                    if (mAreNotificationSuppressed) {
+                        // If we've already set the interruption filter, and the user changes it to
+                        // something other than INTERRUPTION_FILTER_ALARMS, assume we will no longer
+                        // try to change it back if the audio route changes.
+                        mAreNotificationSuppressed =
+                                mInterruptionFilterProxy.getCurrentInterruptionFilter()
+                                        == NotificationManager.INTERRUPTION_FILTER_ALARMS;
+                    }
+                }
+            } finally {
+                Log.endSession();
+            }
+        }
+    };
+
     private static final String ACTIVE_EARPIECE_ROUTE_NAME = "ActiveEarpieceRoute";
     private static final String ACTIVE_BLUETOOTH_ROUTE_NAME = "ActiveBluetoothRoute";
     private static final String ACTIVE_SPEAKER_ROUTE_NAME = "ActiveSpeakerRoute";
@@ -250,6 +282,7 @@
             super.enter();
             setSpeakerphoneOn(false);
             setBluetoothOn(false);
+            setNotificationsSuppressed(true);
             CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_EARPIECE,
                     mAvailableRoutes);
             setSystemAudioState(newState);
@@ -257,6 +290,12 @@
         }
 
         @Override
+        public void exit() {
+            super.exit();
+            setNotificationsSuppressed(false);
+        }
+
+        @Override
         public void updateSystemAudioState() {
             updateInternalCallAudioState();
             setSystemAudioState(mCurrentCallAudioState);
@@ -1071,6 +1110,7 @@
     private int mAudioFocusType;
     private boolean mWasOnSpeaker;
     private boolean mIsMuted;
+    private boolean mAreNotificationSuppressed = false;
 
     private final Context mContext;
     private final CallsManager mCallsManager;
@@ -1079,6 +1119,7 @@
     private final WiredHeadsetManager mWiredHeadsetManager;
     private final StatusBarNotifier mStatusBarNotifier;
     private final CallAudioManager.AudioServiceFactory mAudioServiceFactory;
+    private final InterruptionFilterProxy mInterruptionFilterProxy;
     private final boolean mDoesDeviceSupportEarpieceRoute;
     private boolean mHasUserExplicitlyLeftBluetooth = false;
 
@@ -1097,6 +1138,7 @@
             WiredHeadsetManager wiredHeadsetManager,
             StatusBarNotifier statusBarNotifier,
             CallAudioManager.AudioServiceFactory audioServiceFactory,
+            InterruptionFilterProxy interruptionFilterProxy,
             boolean doesDeviceSupportEarpieceRoute) {
         super(NAME);
         addState(mActiveEarpieceRoute);
@@ -1116,6 +1158,11 @@
         mWiredHeadsetManager = wiredHeadsetManager;
         mStatusBarNotifier = statusBarNotifier;
         mAudioServiceFactory = audioServiceFactory;
+        mInterruptionFilterProxy = interruptionFilterProxy;
+        // Register for misc other intent broadcasts.
+        IntentFilter intentFilter =
+                new IntentFilter(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
+        context.registerReceiver(mReceiver, intentFilter);
         mDoesDeviceSupportEarpieceRoute = doesDeviceSupportEarpieceRoute;
 
         mStateNameToRouteCode = new HashMap<>(8);
@@ -1222,6 +1269,45 @@
         quitNow();
     }
 
+    /**
+     * Sets whether notifications should be suppressed or not.  Used when in a call to ensure the
+     * device will not vibrate due to notifications.
+     * Alarm-only filtering is activated when
+     *
+     * @param on {@code true} when notification suppression should be activated, {@code false} when
+     *                       it should be deactivated.
+     */
+    private void setNotificationsSuppressed(boolean on) {
+        if (mInterruptionFilterProxy == null) {
+            return;
+        }
+
+        if (on) {
+            // Enabling suppression of notifications.
+            int interruptionFilter = mInterruptionFilterProxy.getCurrentInterruptionFilter();
+            if (interruptionFilter == NotificationManager.INTERRUPTION_FILTER_ALL) {
+                // No interruption filter is specified, so suppress notifications by setting the
+                // current filter to alarms-only.
+                mAreNotificationSuppressed = true;
+                mInterruptionFilterProxy.setInterruptionFilter(
+                        NotificationManager.INTERRUPTION_FILTER_ALARMS);
+            } else {
+                // Interruption filter is already chosen by the user, so do not attempt to change
+                // it.
+                mAreNotificationSuppressed = false;
+            }
+        } else {
+            // Disabling suppression of notifications.
+            if (mAreNotificationSuppressed) {
+                // We have implemented the alarms-only policy and the user has not changed it since
+                // we originally set it, so reset the notification filter.
+                mInterruptionFilterProxy.setInterruptionFilter(
+                        NotificationManager.INTERRUPTION_FILTER_ALL);
+            }
+            mAreNotificationSuppressed = false;
+        }
+    }
+
     private void setSpeakerphoneOn(boolean on) {
         if (mAudioManager.isSpeakerphoneOn() != on) {
             Log.i(this, "turning speaker phone %s", on);
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index b60f70b..4afa2b8 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -17,6 +17,7 @@
 package com.android.server.telecom;
 
 import android.app.ActivityManager;
+import android.app.NotificationManager;
 import android.content.Context;
 import android.content.pm.UserInfo;
 import android.content.Intent;
@@ -193,6 +194,7 @@
     private final DefaultDialerManagerAdapter mDefaultDialerManagerAdapter;
     private final Timeouts.Adapter mTimeoutsAdapter;
     private final PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter;
+    private final NotificationManager mNotificationManager;
     private final Set<Call> mLocallyDisconnectingCalls = new HashSet<>();
     private final Set<Call> mPendingCallsToDisconnect = new HashSet<>();
     /* Handler tied to thread in which CallManager was initialized. */
@@ -224,7 +226,8 @@
             DefaultDialerManagerAdapter defaultDialerAdapter,
             Timeouts.Adapter timeoutsAdapter,
             AsyncRingtonePlayer asyncRingtonePlayer,
-            PhoneNumberUtilsAdapter phoneNumberUtilsAdapter) {
+            PhoneNumberUtilsAdapter phoneNumberUtilsAdapter,
+            InterruptionFilterProxy interruptionFilterProxy) {
         mContext = context;
         mLock = lock;
         mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter;
@@ -242,6 +245,8 @@
                 mContactsAsyncHelper, mLock);
 
         mDtmfLocalTonePlayer = new DtmfLocalTonePlayer();
+        mNotificationManager = (NotificationManager) context.getSystemService(
+                Context.NOTIFICATION_SERVICE);
         CallAudioRouteStateMachine callAudioRouteStateMachine = new CallAudioRouteStateMachine(
                 context,
                 this,
@@ -249,6 +254,7 @@
                 wiredHeadsetManager,
                 statusBarNotifier,
                 audioServiceFactory,
+                interruptionFilterProxy,
                 CallAudioRouteStateMachine.doesDeviceSupportEarpieceRoute()
         );
         callAudioRouteStateMachine.initialize();
diff --git a/src/com/android/server/telecom/InterruptionFilterProxy.java b/src/com/android/server/telecom/InterruptionFilterProxy.java
new file mode 100644
index 0000000..434c341
--- /dev/null
+++ b/src/com/android/server/telecom/InterruptionFilterProxy.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 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.telecom;
+
+/**
+ * Defines common functionality used by {@link CallAudioRouteStateMachine} to control the current
+ * interruption filter for notifications while in a call.  Used to ensure that this functionality
+ * can be mocked out in unit tests.
+ */
+public interface InterruptionFilterProxy {
+    void setInterruptionFilter(int interruptionFilter);
+    int getCurrentInterruptionFilter();
+}
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index 9ed612a..24d925d 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -155,7 +155,8 @@
                     bluetoothPhoneServiceImplFactory,
             Timeouts.Adapter timeoutsAdapter,
             AsyncRingtonePlayer asyncRingtonePlayer,
-            PhoneNumberUtilsAdapter phoneNumberUtilsAdapter) {
+            PhoneNumberUtilsAdapter phoneNumberUtilsAdapter,
+            InterruptionFilterProxy interruptionFilterProxy) {
         mContext = context.getApplicationContext();
         Log.setContext(mContext);
         Log.initMd5Sum();
@@ -199,7 +200,8 @@
                 defaultDialerAdapter,
                 timeoutsAdapter,
                 asyncRingtonePlayer,
-                phoneNumberUtilsAdapter);
+                phoneNumberUtilsAdapter,
+                interruptionFilterProxy);
 
         mRespondViaSmsManager = new RespondViaSmsManager(mCallsManager, mLock);
         mCallsManager.setRespondViaSmsManager(mRespondViaSmsManager);
diff --git a/src/com/android/server/telecom/components/TelecomService.java b/src/com/android/server/telecom/components/TelecomService.java
index 9d846f3..f36a892 100644
--- a/src/com/android/server/telecom/components/TelecomService.java
+++ b/src/com/android/server/telecom/components/TelecomService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.telecom.components;
 
+import android.app.Notification;
+import android.app.NotificationManager;
 import android.app.Service;
 import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
@@ -35,6 +37,7 @@
 import com.android.server.telecom.HeadsetMediaButtonFactory;
 import com.android.server.telecom.InCallWakeLockControllerFactory;
 import com.android.server.telecom.CallAudioManager;
+import com.android.server.telecom.InterruptionFilterProxy;
 import com.android.server.telecom.PhoneAccountRegistrar;
 import com.android.server.telecom.PhoneNumberUtilsAdapter;
 import com.android.server.telecom.PhoneNumberUtilsAdapterImpl;
@@ -73,6 +76,9 @@
      */
     static void initializeTelecomSystem(Context context) {
         if (TelecomSystem.getInstance() == null) {
+            final NotificationManager notificationManager =
+                    (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+
             TelecomSystem.setInstance(
                     new TelecomSystem(
                             context,
@@ -152,7 +158,18 @@
                             },
                             new Timeouts.Adapter(),
                             new AsyncRingtonePlayer(),
-                            new PhoneNumberUtilsAdapterImpl()
+                            new PhoneNumberUtilsAdapterImpl(),
+                            new InterruptionFilterProxy() {
+                                @Override
+                                public void setInterruptionFilter(int interruptionFilter) {
+                                    notificationManager.setInterruptionFilter(interruptionFilter);
+                                }
+
+                                @Override
+                                public int getCurrentInterruptionFilter() {
+                                    return notificationManager.getCurrentInterruptionFilter();
+                                }
+                            }
                     ));
         }
         if (BluetoothAdapter.getDefaultAdapter() != null) {
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
index 615fd0e..8b40d47 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.telecom.tests;
 
+import android.app.NotificationManager;
 import android.content.Context;
 import android.media.AudioManager;
 import android.media.IAudioService;
@@ -31,6 +32,7 @@
 import com.android.server.telecom.CallsManager;
 import com.android.server.telecom.ConnectionServiceWrapper;
 import com.android.server.telecom.CallAudioManager;
+import com.android.server.telecom.InterruptionFilterProxy;
 import com.android.server.telecom.StatusBarNotifier;
 import com.android.server.telecom.WiredHeadsetManager;
 
@@ -42,11 +44,16 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.same;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.timeout;
@@ -64,27 +71,37 @@
     static class RoutingTestParameters extends TestParameters {
         public String name;
         public int initialRoute;
+        public int initialNotificationFilter;
         public int availableRoutes; // may excl. speakerphone, because that's always available
         public int speakerInteraction; // one of NONE, ON, or OFF
         public int bluetoothInteraction; // one of NONE, ON, or OFF
         public int action;
         public int expectedRoute;
         public int expectedAvailableRoutes; // also may exclude the speakerphone.
+        public int expectedNotificationFilter; // expected end notification filter.
+        public boolean isNotificationChangeExpected; // indicates whether we expect the notification
+                                                     // filter to change during the process of the
+                                                     // test.
         public boolean doesDeviceSupportEarpiece; // set to false in the case of Wear devices
         public boolean shouldRunWithFocus;
 
-        public RoutingTestParameters(String name, int initialRoute, int availableRoutes, int
-                speakerInteraction, int bluetoothInteraction, int action, int expectedRoute, int
-                expectedAvailableRoutes, boolean doesDeviceSupportEarpiece,
+        public RoutingTestParameters(String name, int initialRoute,
+                int initialNotificationFilter, int availableRoutes, int speakerInteraction,
+                int bluetoothInteraction, int action, int expectedRoute,
+                int expectedAvailableRoutes, int expectedNotificationFilter,
+                boolean isNotificationChangeExpected, boolean doesDeviceSupportEarpiece,
                 boolean shouldRunWithFocus) {
             this.name = name;
             this.initialRoute = initialRoute;
+            this.initialNotificationFilter = initialNotificationFilter;
             this.availableRoutes = availableRoutes;
             this.speakerInteraction = speakerInteraction;
             this.bluetoothInteraction = bluetoothInteraction;
             this.action = action;
             this.expectedRoute = expectedRoute;
             this.expectedAvailableRoutes = expectedAvailableRoutes;
+            this.expectedNotificationFilter = expectedNotificationFilter;
+            this.isNotificationChangeExpected = isNotificationChangeExpected;
             this.doesDeviceSupportEarpiece = doesDeviceSupportEarpiece;
             this.shouldRunWithFocus = shouldRunWithFocus;
         }
@@ -94,12 +111,15 @@
             return "RoutingTestParameters{" +
                     "name='" + name + '\'' +
                     ", initialRoute=" + initialRoute +
+                    ", initialNotificationFilter=" + initialNotificationFilter +
                     ", availableRoutes=" + availableRoutes +
                     ", speakerInteraction=" + speakerInteraction +
                     ", bluetoothInteraction=" + bluetoothInteraction +
                     ", action=" + action +
                     ", expectedRoute=" + expectedRoute +
                     ", expectedAvailableRoutes=" + expectedAvailableRoutes +
+                    ", expectedNotificationFilter= " + expectedNotificationFilter +
+                    ", isNotificationChangeExpected=" + isNotificationChangeExpected +
                     ", doesDeviceSupportEarpiece=" + doesDeviceSupportEarpiece +
                     ", shouldRunWithFocus=" + shouldRunWithFocus +
                     '}';
@@ -113,6 +133,7 @@
     @Mock WiredHeadsetManager mockWiredHeadsetManager;
     @Mock StatusBarNotifier mockStatusBarNotifier;
     @Mock Call fakeCall;
+    @Mock InterruptionFilterProxy mMockInterruptionFilterProxy;
 
     private CallAudioManager.AudioServiceFactory mAudioServiceFactory;
     private static final int TEST_TIMEOUT = 500;
@@ -135,10 +156,29 @@
         when(mockCallsManager.getForegroundCall()).thenReturn(fakeCall);
         when(fakeCall.getConnectionService()).thenReturn(mockConnectionServiceWrapper);
         when(fakeCall.isAlive()).thenReturn(true);
+        setupInterruptionFilterMocks();
+
         doNothing().when(mockConnectionServiceWrapper).onCallAudioStateChanged(any(Call.class),
                 any(CallAudioState.class));
     }
 
+    private void setupInterruptionFilterMocks() {
+        // These mock implementations keep track of when the caller sets the current notification
+        // filter, and ensures the same value is returned via getCurrentInterruptionFilter.
+        final int objId = Objects.hashCode(mMockInterruptionFilterProxy);
+        when(mMockInterruptionFilterProxy.getCurrentInterruptionFilter()).thenReturn(
+                NotificationManager.INTERRUPTION_FILTER_ALL);
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock i) {
+                int requestedFilter = (int) i.getArguments()[0];
+                when(mMockInterruptionFilterProxy.getCurrentInterruptionFilter()).thenReturn(
+                        requestedFilter);
+                return null;
+            }
+        }).when(mMockInterruptionFilterProxy).setInterruptionFilter(anyInt());
+    }
+
     @LargeTest
     public void testStateMachineTransitionsWithFocus() throws Throwable {
         List<RoutingTestParameters> paramList = generateTransitionTests(true);
@@ -160,6 +200,7 @@
                 mockWiredHeadsetManager,
                 mockStatusBarNotifier,
                 mAudioServiceFactory,
+                mMockInterruptionFilterProxy,
                 true);
 
         when(mockBluetoothManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
@@ -200,11 +241,13 @@
                 mockWiredHeadsetManager,
                 mockStatusBarNotifier,
                 mAudioServiceFactory,
+                mMockInterruptionFilterProxy,
                 true);
 
         when(mockBluetoothManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
         when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(true);
         when(mockAudioManager.isSpeakerphoneOn()).thenReturn(true);
+
         CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH,
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH);
         stateMachine.initialize(initState);
@@ -219,15 +262,16 @@
 
         waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
         verifyNewSystemCallAudioState(initState, expectedEndState);
+        // Expecting to end up in earpiece, so we expect notifications to be filtered.
+        assertEquals(NotificationManager.INTERRUPTION_FILTER_ALARMS,
+                mMockInterruptionFilterProxy.getCurrentInterruptionFilter());
         resetMocks();
-
         stateMachine.sendMessageWithSessionInfo(
                 CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH);
         stateMachine.sendMessageWithSessionInfo(
                 CallAudioRouteStateMachine.CONNECT_BLUETOOTH);
 
         waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
-
         assertEquals(expectedEndState, stateMachine.getCurrentCallAudioState());
     }
 
@@ -240,11 +284,13 @@
                 mockWiredHeadsetManager,
                 mockStatusBarNotifier,
                 mAudioServiceFactory,
+                mMockInterruptionFilterProxy,
                 true);
 
         when(mockBluetoothManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
         when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(true);
         when(mockAudioManager.isSpeakerphoneOn()).thenReturn(false);
+
         CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH,
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH);
         stateMachine.initialize(initState);
@@ -254,6 +300,9 @@
         waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
 
         verify(mockBluetoothManager, never()).connectBluetoothAudio();
+        // Shouldn't change interruption filter when in bluetooth route.
+        assertEquals(NotificationManager.INTERRUPTION_FILTER_ALL,
+                mMockInterruptionFilterProxy.getCurrentInterruptionFilter());
 
         stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
                 CallAudioRouteStateMachine.ACTIVE_FOCUS);
@@ -270,6 +319,7 @@
                 mockWiredHeadsetManager,
                 mockStatusBarNotifier,
                 mAudioServiceFactory,
+                mMockInterruptionFilterProxy,
                 true);
 
         when(mockBluetoothManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
@@ -284,7 +334,6 @@
         when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(true);
         stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.CONNECT_BLUETOOTH);
         waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
-
         verify(mockBluetoothManager, never()).connectBluetoothAudio();
         CallAudioState expectedEndState = new CallAudioState(false,
                 CallAudioState.ROUTE_BLUETOOTH,
@@ -370,6 +419,7 @@
                 mockWiredHeadsetManager,
                 mockStatusBarNotifier,
                 mAudioServiceFactory,
+                mMockInterruptionFilterProxy,
                 doesDeviceSupportEarpiece);
         stateMachine.initialize();
         assertEquals(expectedState, stateMachine.getCurrentCallAudioState());
@@ -380,12 +430,15 @@
         params.add(new RoutingTestParameters(
                 "Connect headset during earpiece", // name
                 CallAudioState.ROUTE_EARPIECE, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE, // availableRoutes
                 NONE, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.CONNECT_WIRED_HEADSET, // action
                 CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute
                 CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -393,12 +446,15 @@
         params.add(new RoutingTestParameters(
                 "Connect headset during bluetooth", // name
                 CallAudioState.ROUTE_BLUETOOTH, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
                 NONE, // speakerInteraction
                 OFF, // bluetoothInteraction
                 CallAudioRouteStateMachine.CONNECT_WIRED_HEADSET, // action
                 CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // expectedAvai
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -406,12 +462,15 @@
         params.add(new RoutingTestParameters(
                 "Connect headset during speakerphone", // name
                 CallAudioState.ROUTE_SPEAKER, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE, // availableRoutes
                 OFF, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.CONNECT_WIRED_HEADSET, // action
                 CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute
                 CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -419,12 +478,15 @@
         params.add(new RoutingTestParameters(
                 "Disconnect headset during headset", // name
                 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
                 NONE, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
                 CallAudioState.ROUTE_EARPIECE, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -432,12 +494,15 @@
         params.add(new RoutingTestParameters(
                 "Disconnect headset during headset with bluetooth available", // name
                 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
                 NONE, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
                 CallAudioState.ROUTE_EARPIECE, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
+                NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -445,12 +510,15 @@
         params.add(new RoutingTestParameters(
                 "Disconnect headset during bluetooth", // name
                 CallAudioState.ROUTE_BLUETOOTH, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
                 NONE, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
                 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -458,12 +526,15 @@
         params.add(new RoutingTestParameters(
                 "Disconnect headset during speakerphone", // name
                 CallAudioState.ROUTE_SPEAKER, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
                 NONE, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
                 CallAudioState.ROUTE_SPEAKER, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -471,12 +542,15 @@
         params.add(new RoutingTestParameters(
                 "Disconnect headset during speakerphone with bluetooth available", // name
                 CallAudioState.ROUTE_SPEAKER, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
                 NONE, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
                 CallAudioState.ROUTE_SPEAKER, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -484,12 +558,15 @@
         params.add(new RoutingTestParameters(
                 "Connect bluetooth during earpiece", // name
                 CallAudioState.ROUTE_EARPIECE, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE, // availableRoutes
                 NONE, // speakerInteraction
                 ON, // bluetoothInteraction
                 CallAudioRouteStateMachine.CONNECT_BLUETOOTH, // action
                 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
                 CallAudioState.ROUTE_BLUETOOTH | CallAudioState.ROUTE_EARPIECE, // expectedAvailable
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -497,12 +574,15 @@
         params.add(new RoutingTestParameters(
                 "Connect bluetooth during wired headset", // name
                 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
                 NONE, // speakerInteraction
                 ON, // bluetoothInteraction
                 CallAudioRouteStateMachine.CONNECT_BLUETOOTH, // action
                 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
                 CallAudioState.ROUTE_BLUETOOTH | CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvai
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -510,12 +590,15 @@
         params.add(new RoutingTestParameters(
                 "Connect bluetooth during speakerphone", // name
                 CallAudioState.ROUTE_SPEAKER, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE, // availableRoutes
                 OFF, // speakerInteraction
                 ON, // bluetoothInteraction
                 CallAudioRouteStateMachine.CONNECT_BLUETOOTH, // action
                 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
                 CallAudioState.ROUTE_BLUETOOTH | CallAudioState.ROUTE_EARPIECE, // expectedAvailable
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -523,12 +606,31 @@
         params.add(new RoutingTestParameters(
                 "Disconnect bluetooth during bluetooth without headset in", // name
                 CallAudioState.ROUTE_BLUETOOTH, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
                 NONE, // speakerInteraction
                 OFF, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
                 CallAudioState.ROUTE_EARPIECE, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
+                true, // doesDeviceSupportEarpiece
+                shouldRunWithFocus
+        ));
+
+        params.add(new RoutingTestParameters(
+                "Disconnect bluetooth during bluetooth without headset in, priority mode ", // name
+                CallAudioState.ROUTE_BLUETOOTH, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_PRIORITY, // initialNotificationFilter
+                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
+                NONE, // speakerInteraction
+                OFF, // bluetoothInteraction
+                CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
+                CallAudioState.ROUTE_EARPIECE, // expectedRoute
+                CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_PRIORITY, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -536,12 +638,15 @@
         params.add(new RoutingTestParameters(
                 "Disconnect bluetooth during bluetooth with headset in", // name
                 CallAudioState.ROUTE_BLUETOOTH, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
                 NONE, // speakerInteraction
                 OFF, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
                 CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute
                 CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -549,12 +654,15 @@
         params.add(new RoutingTestParameters(
                 "Disconnect bluetooth during speakerphone", // name
                 CallAudioState.ROUTE_SPEAKER, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
                 NONE, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
                 CallAudioState.ROUTE_SPEAKER, // expectedRoute
                 CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -562,12 +670,15 @@
         params.add(new RoutingTestParameters(
                 "Disconnect bluetooth during earpiece", // name
                 CallAudioState.ROUTE_EARPIECE, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
                 NONE, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
                 CallAudioState.ROUTE_EARPIECE, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -575,12 +686,15 @@
         params.add(new RoutingTestParameters(
                 "Switch to speakerphone from earpiece", // name
                 CallAudioState.ROUTE_EARPIECE, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE, // availableRoutes
                 ON, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.SWITCH_SPEAKER, // action
                 CallAudioState.ROUTE_SPEAKER, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -588,12 +702,15 @@
         params.add(new RoutingTestParameters(
                 "Switch to speakerphone from headset", // name
                 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
                 ON, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.SWITCH_SPEAKER, // action
                 CallAudioState.ROUTE_SPEAKER, // expectedRoute
                 CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -601,12 +718,15 @@
         params.add(new RoutingTestParameters(
                 "Switch to speakerphone from bluetooth", // name
                 CallAudioState.ROUTE_BLUETOOTH, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
                 ON, // speakerInteraction
                 OFF, // bluetoothInteraction
                 CallAudioRouteStateMachine.SWITCH_SPEAKER, // action
                 CallAudioState.ROUTE_SPEAKER, // expectedRoute
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // expectedAvai
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -614,12 +734,15 @@
         params.add(new RoutingTestParameters(
                 "Switch to earpiece from bluetooth", // name
                 CallAudioState.ROUTE_BLUETOOTH, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
                 NONE, // speakerInteraction
                 OFF, // bluetoothInteraction
                 CallAudioRouteStateMachine.SWITCH_EARPIECE, // action
                 CallAudioState.ROUTE_EARPIECE, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
+                NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -627,12 +750,47 @@
         params.add(new RoutingTestParameters(
                 "Switch to earpiece from speakerphone", // name
                 CallAudioState.ROUTE_SPEAKER, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE, // availableRoutes
                 OFF, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.SWITCH_EARPIECE, // action
                 CallAudioState.ROUTE_EARPIECE, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
+                true, // doesDeviceSupportEarpiece
+                shouldRunWithFocus
+        ));
+
+        params.add(new RoutingTestParameters(
+                "Switch to earpiece from speakerphone, priority notifications", // name
+                CallAudioState.ROUTE_SPEAKER, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_PRIORITY, // initialNotificationFilter
+                CallAudioState.ROUTE_EARPIECE, // availableRoutes
+                OFF, // speakerInteraction
+                NONE, // bluetoothInteraction
+                CallAudioRouteStateMachine.SWITCH_EARPIECE, // action
+                CallAudioState.ROUTE_EARPIECE, // expectedRoute
+                CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_PRIORITY, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
+                true, // doesDeviceSupportEarpiece
+                shouldRunWithFocus
+        ));
+
+        params.add(new RoutingTestParameters(
+                "Switch to earpiece from speakerphone, silent mode", // name
+                CallAudioState.ROUTE_SPEAKER, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_NONE, // initialNotificationFilter
+                CallAudioState.ROUTE_EARPIECE, // availableRoutes
+                OFF, // speakerInteraction
+                NONE, // bluetoothInteraction
+                CallAudioRouteStateMachine.SWITCH_EARPIECE, // action
+                CallAudioState.ROUTE_EARPIECE, // expectedRoute
+                CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_NONE, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -640,12 +798,15 @@
         params.add(new RoutingTestParameters(
                 "Switch to bluetooth from speakerphone", // name
                 CallAudioState.ROUTE_SPEAKER, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
                 OFF, // speakerInteraction
                 ON, // bluetoothInteraction
                 CallAudioRouteStateMachine.SWITCH_BLUETOOTH, // action
                 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -653,12 +814,15 @@
         params.add(new RoutingTestParameters(
                 "Switch to bluetooth from earpiece", // name
                 CallAudioState.ROUTE_EARPIECE, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
                 NONE, // speakerInteraction
                 ON, // bluetoothInteraction
                 CallAudioRouteStateMachine.SWITCH_BLUETOOTH, // action
                 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                true, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -666,12 +830,15 @@
         params.add(new RoutingTestParameters(
                 "Switch to bluetooth from wired headset", // name
                 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
                 NONE, // speakerInteraction
                 ON, // bluetoothInteraction
                 CallAudioRouteStateMachine.SWITCH_BLUETOOTH, // action
                 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
                 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // expectedAvai
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 true, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -679,12 +846,15 @@
         params.add(new RoutingTestParameters(
                 "Switch from bluetooth to wired/earpiece when neither are available", // name
                 CallAudioState.ROUTE_BLUETOOTH, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
                 ON, // speakerInteraction
                 OFF, // bluetoothInteraction
                 CallAudioRouteStateMachine.SWITCH_BASELINE_ROUTE, // action
                 CallAudioState.ROUTE_SPEAKER, // expectedRoute
                 CallAudioState.ROUTE_BLUETOOTH, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 false, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -692,12 +862,15 @@
         params.add(new RoutingTestParameters(
                 "Disconnect wired headset when device does not support earpiece", // name
                 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
+                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
                 CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
                 ON, // speakerInteraction
                 NONE, // bluetoothInteraction
                 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
                 CallAudioState.ROUTE_SPEAKER, // expectedRoute
                 CallAudioState.ROUTE_SPEAKER, // expectedAvailableRoutes
+                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
+                false, // isNotificationChangeExpected
                 false, // doesDeviceSupportEarpiece
                 shouldRunWithFocus
         ));
@@ -718,6 +891,8 @@
     private void runParametrizedTestCaseWithFocus(final RoutingTestParameters params)
             throws Throwable {
         resetMocks();
+        when(mMockInterruptionFilterProxy.getCurrentInterruptionFilter()).thenReturn(
+                params.initialNotificationFilter);
 
         // Construct a fresh state machine on every case
         final CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
@@ -727,6 +902,7 @@
                 mockWiredHeadsetManager,
                 mockStatusBarNotifier,
                 mAudioServiceFactory,
+                mMockInterruptionFilterProxy,
                 params.doesDeviceSupportEarpiece);
 
         // Set up bluetooth and speakerphone state
@@ -735,13 +911,14 @@
         when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(
                 (params.availableRoutes & CallAudioState.ROUTE_BLUETOOTH) != 0
                         || (params.expectedAvailableRoutes & CallAudioState.ROUTE_BLUETOOTH) != 0);
-        when(mockAudioManager.isSpeakerphoneOn()).thenReturn(
-                params.initialRoute == CallAudioState.ROUTE_SPEAKER);
+        doReturn(params.initialRoute == CallAudioState.ROUTE_SPEAKER).when(mockAudioManager).
+                isSpeakerphoneOn();
 
         // Set the initial CallAudioState object
         final CallAudioState initState = new CallAudioState(false,
                 params.initialRoute, (params.availableRoutes | CallAudioState.ROUTE_SPEAKER));
         stateMachine.initialize(initState);
+
         // Make the state machine have focus so that we actually do something
         stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
                 CallAudioRouteStateMachine.ACTIVE_FOCUS);
@@ -749,6 +926,22 @@
 
         waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
 
+        // Capture the changes made to the interruption filter and verify that the last change
+        // made to it matches the expected interruption filter.
+        if (params.isNotificationChangeExpected) {
+            ArgumentCaptor<Integer> interruptionCaptor = ArgumentCaptor.forClass(Integer.class);
+            verify(mMockInterruptionFilterProxy, timeout(TEST_TIMEOUT).atLeastOnce())
+                    .setInterruptionFilter(interruptionCaptor.capture());
+            List<Integer> interruptionFilterValues = interruptionCaptor.getAllValues();
+
+            int lastChange = interruptionFilterValues.get(interruptionFilterValues.size() - 1)
+                    .intValue();
+            assertEquals(params.expectedNotificationFilter, lastChange);
+        } else {
+            Thread.sleep(TEST_TIMEOUT);
+            verify(mMockInterruptionFilterProxy, never()).setInterruptionFilter(anyInt());
+        }
+
         stateMachine.quitStateMachine();
 
         // Verify interactions with the speakerphone and bluetooth systems
@@ -794,6 +987,7 @@
                 mockWiredHeadsetManager,
                 mockStatusBarNotifier,
                 mAudioServiceFactory,
+                mMockInterruptionFilterProxy,
                 params.doesDeviceSupportEarpiece);
 
         // Set up bluetooth and speakerphone state
@@ -854,7 +1048,9 @@
 
     private void resetMocks() {
         reset(mockAudioManager, mockBluetoothManager, mockCallsManager,
-                mockConnectionServiceWrapper);
+                mockConnectionServiceWrapper, mMockInterruptionFilterProxy);
+        mMockInterruptionFilterProxy = mock(InterruptionFilterProxy.class);
+        setupInterruptionFilterMocks();
         when(mockCallsManager.getForegroundCall()).thenReturn(fakeCall);
         doNothing().when(mockConnectionServiceWrapper).onCallAudioStateChanged(any(Call.class),
                 any(CallAudioState.class));
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index c8a1285..62f2440 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -33,6 +33,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.NotificationManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -69,6 +70,7 @@
 import com.android.server.telecom.HeadsetMediaButtonFactory;
 import com.android.server.telecom.InCallWakeLockController;
 import com.android.server.telecom.InCallWakeLockControllerFactory;
+import com.android.server.telecom.InterruptionFilterProxy;
 import com.android.server.telecom.MissedCallNotifier;
 import com.android.server.telecom.PhoneAccountRegistrar;
 import com.android.server.telecom.PhoneNumberUtilsAdapter;
@@ -161,11 +163,26 @@
         }
     }
     PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter = new EmergencyNumberUtilsAdapter();
+
+    public static class MockInterruptionFilterProxy implements InterruptionFilterProxy {
+        private int mInterruptionFilter = NotificationManager.INTERRUPTION_FILTER_ALL;
+        @Override
+        public void setInterruptionFilter(int interruptionFilter) {
+            mInterruptionFilter = interruptionFilter;
+        }
+
+        @Override
+        public int getCurrentInterruptionFilter() {
+            return mInterruptionFilter;
+        }
+    }
+
     @Mock HeadsetMediaButton mHeadsetMediaButton;
     @Mock ProximitySensorManager mProximitySensorManager;
     @Mock InCallWakeLockController mInCallWakeLockController;
     @Mock BluetoothPhoneServiceImpl mBluetoothPhoneServiceImpl;
     @Mock AsyncRingtonePlayer mAsyncRingtonePlayer;
+    @Mock InterruptionFilterProxy mInterruptionFilterProxy;
 
     final ComponentName mInCallServiceComponentNameX =
             new ComponentName(
@@ -197,7 +214,8 @@
                     .addSupportedUriScheme("tel")
                     .setCapabilities(
                             PhoneAccount.CAPABILITY_CALL_PROVIDER |
-                            PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+                                    PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
+                                    PhoneAccount.CAPABILITY_VIDEO_CALLING)
                     .build();
     final PhoneAccount mPhoneAccountA1 =
             PhoneAccount.builder(
@@ -208,7 +226,8 @@
                     .addSupportedUriScheme("tel")
                     .setCapabilities(
                             PhoneAccount.CAPABILITY_CALL_PROVIDER |
-                            PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+                                    PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
+                                    PhoneAccount.CAPABILITY_VIDEO_CALLING)
                     .build();
     final PhoneAccount mPhoneAccountB0 =
             PhoneAccount.builder(
@@ -219,7 +238,8 @@
                     .addSupportedUriScheme("tel")
                     .setCapabilities(
                             PhoneAccount.CAPABILITY_CALL_PROVIDER |
-                            PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+                                    PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
+                                    PhoneAccount.CAPABILITY_VIDEO_CALLING)
                     .build();
     final PhoneAccount mPhoneAccountE0 =
             PhoneAccount.builder(
@@ -231,7 +251,8 @@
                     .setCapabilities(
                             PhoneAccount.CAPABILITY_CALL_PROVIDER |
                                     PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
-                                    PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)
+                                    PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS |
+                                    PhoneAccount.CAPABILITY_VIDEO_CALLING)
                     .build();
 
     final PhoneAccount mPhoneAccountE1 =
@@ -244,7 +265,8 @@
                     .setCapabilities(
                             PhoneAccount.CAPABILITY_CALL_PROVIDER |
                                     PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
-                                    PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)
+                                    PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS |
+                                    PhoneAccount.CAPABILITY_VIDEO_CALLING)
                     .build();
 
     ConnectionServiceFixture mConnectionServiceFixtureA;
@@ -374,7 +396,8 @@
                 },
                 mTimeoutsAdapter,
                 mAsyncRingtonePlayer,
-                mPhoneNumberUtilsAdapter);
+                mPhoneNumberUtilsAdapter,
+                mInterruptionFilterProxy);
 
         mComponentContextFixture.setTelecomManager(new TelecomManager(
                 mComponentContextFixture.getTestDouble(),