Merge "Return/notify a power policy containing all components' state in CPMS" into sc-dev
diff --git a/car_product/build/car_base.mk b/car_product/build/car_base.mk
index d3e22cb..41408eb 100644
--- a/car_product/build/car_base.mk
+++ b/car_product/build/car_base.mk
@@ -90,7 +90,6 @@
 
 # Default permission grant exceptions
 PRODUCT_COPY_FILES += \
-    packages/services/Car/car_product/build/default-car-permissions.xml:system/etc/default-permissions/default-car-permissions.xml \
     packages/services/Car/car_product/build/preinstalled-packages-product-car-base.xml:system/etc/sysconfig/preinstalled-packages-product-car-base.xml
 
 $(call inherit-product, $(SRC_TARGET_DIR)/product/core_minimal.mk)
diff --git a/car_product/build/default-car-permissions.xml b/car_product/build/default-car-permissions.xml
deleted file mode 100644
index 6e1a8c3..0000000
--- a/car_product/build/default-car-permissions.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
-
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!--
-    This file contains permissions to be granted by default. Default
-    permissions are granted to special platform components and to apps
-    that are approved to get default grants. The special components
-    are apps that are expected tto work out-of-the-box as they provide
-    core use cases such as default dialer, default email, etc. These
-    grants are managed by the platform. The apps that are additionally
-    approved for default grants are ones that provide carrier specific
-    functionality, ones legally required at some location, ones providing
-    alternative disclosure and opt-out UI, ones providing highlight features
-    of a dedicated device, etc. This file contains only the latter exceptions.
-    Fixed permissions cannot be controlled by the user and need a special
-    approval. Typically these are to ensure either legally mandated functions
-    or the app is considered a part of the OS.
--->
-
-<exceptions>
-
-    <!-- This is an example of an exception:
-    <exception
-        package="foo.bar.permission"
-      <permission name="android.permission.READ_CONTACTS" fixed="true"/>
-      <permission name="android.permission.READ_CALENDAR" fixed="false"/>
-    </exception>
-    -->
-
-    <exception
-            package="android.car.cluster">
-        <permission name="android.car.permission.CAR_ENERGY" fixed="false"/>
-        <permission name="android.car.permission.CAR_SPEED" fixed="false"/>
-    </exception>
-
-</exceptions>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/config.xml b/car_product/overlay/frameworks/base/core/res/res/values/config.xml
index 14043ec..52739bf 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/config.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/config.xml
@@ -143,4 +143,7 @@
     <string name="config_customResolverActivity" translatable="false"
         >com.android.car.activityresolver/.CarResolverActivity</string>
 
+    <!-- The name of the package that will hold the system cluster service role. -->
+    <string name="config_systemAutomotiveCluster" translatable="false">android.car.cluster</string>
+
 </resources>
diff --git a/service/AndroidManifest.xml b/service/AndroidManifest.xml
index 1b02d73..bb462ca 100644
--- a/service/AndroidManifest.xml
+++ b/service/AndroidManifest.xml
@@ -869,6 +869,9 @@
     <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
     <uses-permission android:name="android.permission.BLUETOOTH"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
     <uses-permission android:name="android.permission.MANAGE_APP_OPS_MODES"/>
     <uses-permission android:name="android.permission.MANAGE_USERS"/>
     <uses-permission android:name="android.permission.LOCATION_HARDWARE"/>
diff --git a/service/src/com/android/car/audio/CarAudioPolicyVolumeCallback.java b/service/src/com/android/car/audio/CarAudioPolicyVolumeCallback.java
index dd09903..fa58203 100644
--- a/service/src/com/android/car/audio/CarAudioPolicyVolumeCallback.java
+++ b/service/src/com/android/car/audio/CarAudioPolicyVolumeCallback.java
@@ -16,19 +16,20 @@
 
 package com.android.car.audio;
 
+import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
 import static android.util.Log.DEBUG;
 import static android.util.Log.VERBOSE;
 
 import static com.android.car.CarLog.TAG_AUDIO;
 
 import android.annotation.NonNull;
-import android.car.media.CarAudioManager;
 import android.media.AudioManager;
 import android.media.audiopolicy.AudioPolicy;
 import android.media.audiopolicy.AudioPolicy.Builder;
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.car.audio.CarAudioContext.AudioContext;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.Objects;
@@ -36,13 +37,15 @@
 final class CarAudioPolicyVolumeCallback extends AudioPolicy.AudioPolicyVolumeCallback{
     private final CarAudioService mCarAudioService;
     private final AudioManager mAudioManager;
+    private final boolean mUseCarVolumeGroupMuting;
 
     static void addVolumeCallbackToPolicy(@NonNull Builder policyBuilder,
             @NonNull CarAudioService carAudioService,
-            @NonNull AudioManager audioManager) {
+            @NonNull AudioManager audioManager, boolean useCarVolumeGroupMuting) {
         Objects.requireNonNull(policyBuilder, "AudioPolicy.Builder cannot be null");
         policyBuilder.setAudioPolicyVolumeCallback(
-                new CarAudioPolicyVolumeCallback(carAudioService, audioManager));
+                new CarAudioPolicyVolumeCallback(carAudioService, audioManager,
+                        useCarVolumeGroupMuting));
         if (Log.isLoggable(TAG_AUDIO, DEBUG)) {
             Slog.d(TAG_AUDIO, "Registered car audio policy volume callback");
         }
@@ -50,19 +53,18 @@
 
     @VisibleForTesting
     CarAudioPolicyVolumeCallback(@NonNull CarAudioService carAudioService,
-            @NonNull AudioManager audioManager) {
-        Objects.requireNonNull(carAudioService, "CarAudioService cannot be null");
-        Objects.requireNonNull(audioManager, "AudioManager cannot be null");
-        mCarAudioService = carAudioService;
-        mAudioManager = audioManager;
+            @NonNull AudioManager audioManager, boolean useCarVolumeGroupMuting) {
+        mCarAudioService = Objects.requireNonNull(carAudioService,
+                "CarAudioService cannot be null");
+        mAudioManager = Objects.requireNonNull(audioManager, "AudioManager cannot be null");
+        mUseCarVolumeGroupMuting = useCarVolumeGroupMuting;
     }
 
     @Override
     public void onVolumeAdjustment(int adjustment) {
-        @CarAudioContext.AudioContext int suggestedContext =
-                mCarAudioService.getSuggestedAudioContextForPrimaryZone();
+        @AudioContext int suggestedContext = getSuggestedContextForAdjustment(adjustment);
 
-        int zoneId = CarAudioManager.PRIMARY_AUDIO_ZONE;
+        int zoneId = PRIMARY_AUDIO_ZONE;
         int groupId = mCarAudioService.getVolumeGroupIdForAudioContext(zoneId, suggestedContext);
 
         if (Log.isLoggable(TAG_AUDIO, VERBOSE)) {
@@ -87,10 +89,10 @@
                 break;
             case AudioManager.ADJUST_MUTE:
             case AudioManager.ADJUST_UNMUTE:
-                setMute(adjustment == AudioManager.ADJUST_MUTE, flags);
+                setMute(adjustment == AudioManager.ADJUST_MUTE, groupId, flags);
                 break;
             case AudioManager.ADJUST_TOGGLE_MUTE:
-                toggleMute(flags);
+                toggleMute(groupId, flags);
                 break;
             case AudioManager.ADJUST_SAME:
             default:
@@ -98,11 +100,41 @@
         }
     }
 
-    private void toggleMute(int flags) {
-        setMute(!mAudioManager.isMasterMute(), flags);
+    private @AudioContext int getSuggestedContextForAdjustment(int adjustment) {
+        if (mUseCarVolumeGroupMuting && isMuteAdjustment(adjustment)) {
+            return mCarAudioService.getSuggestedMuteContextForPrimaryZone();
+        }
+        return mCarAudioService.getSuggestedVolumeContextForPrimaryZone();
     }
 
-    private void setMute(boolean mute, int flags) {
+    private boolean isMuteAdjustment(int adjustment) {
+        switch (adjustment) {
+            case AudioManager.ADJUST_MUTE:
+            case AudioManager.ADJUST_UNMUTE:
+            case AudioManager.ADJUST_TOGGLE_MUTE:
+                return true;
+            case AudioManager.ADJUST_LOWER:
+            case AudioManager.ADJUST_RAISE:
+            case AudioManager.ADJUST_SAME:
+            default:
+                return false;
+        }
+    }
+
+    private void toggleMute(int groupId, int flags) {
+        if (mUseCarVolumeGroupMuting) {
+            setMute(!mCarAudioService.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, groupId), groupId,
+                    flags);
+            return;
+        }
+        setMute(!mAudioManager.isMasterMute(), groupId, flags);
+    }
+
+    private void setMute(boolean mute, int groupId, int flags) {
+        if (mUseCarVolumeGroupMuting) {
+            mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, groupId, mute, flags);
+            return;
+        }
         mCarAudioService.setMasterMute(mute, flags);
     }
 }
diff --git a/service/src/com/android/car/audio/CarAudioService.java b/service/src/com/android/car/audio/CarAudioService.java
index da21ebb..c2128f4 100644
--- a/service/src/com/android/car/audio/CarAudioService.java
+++ b/service/src/com/android/car/audio/CarAudioService.java
@@ -575,7 +575,8 @@
 
         // Attach the {@link AudioPolicyVolumeCallback}
         CarAudioPolicyVolumeCallback
-                .addVolumeCallbackToPolicy(builder, this, mAudioManager);
+                .addVolumeCallbackToPolicy(builder, this, mAudioManager,
+                        mUseCarVolumeGroupMuting);
 
 
         AudioControlWrapper audioControlWrapper = getAudioControlWrapperLocked();
@@ -1246,9 +1247,16 @@
         return group.getAudioDevicePortForContext(CarAudioContext.getContextForUsage(usage));
     }
 
-    @AudioContext int getSuggestedAudioContextForPrimaryZone() {
+    @AudioContext int getSuggestedMuteContextForPrimaryZone() {
         int zoneId = PRIMARY_AUDIO_ZONE;
-        return mCarVolume.getSuggestedAudioContextAndSaveIfFound(
+        return mCarVolume.getSuggestedMuteContextAndSaveIfFound(
+                getAllActiveContextsForPrimaryZone(), getCallStateForZone(zoneId),
+                getActiveHalUsagesForZone(zoneId));
+    }
+
+    @AudioContext int getSuggestedVolumeContextForPrimaryZone() {
+        int zoneId = PRIMARY_AUDIO_ZONE;
+        return mCarVolume.getSuggestedVolumeContextAndSaveIfFound(
                 getAllActiveContextsForPrimaryZone(), getCallStateForZone(zoneId),
                 getActiveHalUsagesForZone(zoneId));
     }
diff --git a/service/src/com/android/car/audio/CarVolume.java b/service/src/com/android/car/audio/CarVolume.java
index 21e27cb..4ff014a 100644
--- a/service/src/com/android/car/audio/CarVolume.java
+++ b/service/src/com/android/car/audio/CarVolume.java
@@ -73,7 +73,14 @@
             CarAudioContext.VOICE_COMMAND,
     };
 
+    static final int[] AUDIO_CONTEXT_MUTE_PRIORITY = {
+            CarAudioContext.MUSIC,
+            CarAudioContext.CALL,
+            CarAudioContext.ANNOUNCEMENT,
+    };
+
     private final SparseIntArray mVolumePriorityByAudioContext = new SparseIntArray();
+    private final SparseIntArray mVolumeMutePriorityByAudioContext = new SparseIntArray();
     private final SystemClockWrapper mClock;
     private final Object mLock = new Object();
     private final int mVolumeKeyEventTimeoutMs;
@@ -83,7 +90,6 @@
     @GuardedBy("mLock")
     private long mLastActiveContextStartTime;
 
-
     /**
      * Creates car volume for management of volume priority and last selected audio context.
      * @param clockWrapper time keeper for expiration of last selected context.
@@ -95,21 +101,35 @@
     CarVolume(@NonNull SystemClockWrapper clockWrapper,
             @CarVolumeListVersion int audioVolumeAdjustmentContextsVersion,
             int volumeKeyEventTimeoutMs) {
-        Preconditions.checkArgumentInRange(audioVolumeAdjustmentContextsVersion, 1, 2,
-                "audioVolumeAdjustmentContextsVersion");
-        mClock = Objects.requireNonNull(clockWrapper);
+        mClock = Objects.requireNonNull(clockWrapper, "Clock must not be null.");
         mVolumeKeyEventTimeoutMs = Preconditions.checkArgumentNonnegative(volumeKeyEventTimeoutMs);
         mLastActiveContext = CarAudioContext.INVALID;
         mLastActiveContextStartTime = mClock.uptimeMillis();
-        @AudioContext int[] contextVolumePriority = AUDIO_CONTEXT_VOLUME_PRIORITY_V1;
-        if (audioVolumeAdjustmentContextsVersion == VERSION_TWO) {
-            contextVolumePriority = AUDIO_CONTEXT_VOLUME_PRIORITY_V2;
-        }
+        @AudioContext int[] contextVolumePriority =
+                getContextPriorityList(audioVolumeAdjustmentContextsVersion);
+
         for (int priority = CONTEXT_HIGHEST_PRIORITY;
                 priority < contextVolumePriority.length; priority++) {
             mVolumePriorityByAudioContext.append(contextVolumePriority[priority], priority);
         }
+
+        for (int mutePriority = CONTEXT_HIGHEST_PRIORITY;
+                mutePriority < AUDIO_CONTEXT_MUTE_PRIORITY.length; mutePriority++) {
+            mVolumeMutePriorityByAudioContext.append(contextVolumePriority[mutePriority],
+                    mutePriority);
+        }
+
         mLowestPriority = CONTEXT_HIGHEST_PRIORITY + mVolumePriorityByAudioContext.size();
+
+    }
+
+    private static int[] getContextPriorityList(int audioVolumeAdjustmentContextsVersion) {
+        Preconditions.checkArgumentInRange(audioVolumeAdjustmentContextsVersion, 1, 2,
+                "audioVolumeAdjustmentContextsVersion");
+        if (audioVolumeAdjustmentContextsVersion == VERSION_TWO) {
+            return AUDIO_CONTEXT_VOLUME_PRIORITY_V2;
+        }
+        return AUDIO_CONTEXT_VOLUME_PRIORITY_V1;
     }
 
     /**
@@ -117,11 +137,37 @@
      * {@link AudioPlaybackConfiguration}s, {@link CallState}, and active HAL usages. If an active
      * context is found it be will saved and retrieved later on.
      */
-    @AudioContext int getSuggestedAudioContextAndSaveIfFound(
+    @AudioContext int getSuggestedVolumeContextAndSaveIfFound(
             @NonNull List<Integer> activePlaybackContexts, @CallState int callState,
             @NonNull @AttributeUsage int[] activeHalUsages) {
+        return getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts,
+                callState, activeHalUsages, mVolumePriorityByAudioContext);
+    }
 
-        int activeContext = getAudioContextStillActive();
+    /**
+     * Finds a {@link AudioContext} that should be muted based on the current
+     * {@link AudioPlaybackConfiguration}s, {@link CallState}, and active HAL usages. If an active
+     * context is found it be will saved and retrieved later on.
+     */
+    @AudioContext int getSuggestedMuteContextAndSaveIfFound(
+            @NonNull List<Integer> activePlaybackContexts, @CallState int callState,
+            @NonNull @AttributeUsage int[] activeHalUsages) {
+        return getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts,
+                callState, activeHalUsages, mVolumeMutePriorityByAudioContext);
+    }
+
+    /**
+     * @see {@link CarAudioService#resetSelectedVolumeContext()}
+     */
+    public void resetSelectedVolumeContext() {
+        setAudioContextStillActive(CarAudioContext.INVALID);
+    }
+
+    private @AudioContext int getSuggestedAudioContextAndSaveIfFound(
+            @NonNull List<Integer> activePlaybackContexts, @CallState int callState,
+            @NonNull @AttributeUsage int[] activeHalUsages, SparseIntArray contextPriorities) {
+
+        int activeContext = getAudioContextStillActive(contextPriorities);
         if (activeContext != CarAudioContext.INVALID) {
             setAudioContextStillActive(activeContext);
             return activeContext;
@@ -132,27 +178,20 @@
 
 
         @AudioContext int context =
-                findActiveContextWithHighestPriority(activeContexts);
+                findActiveContextWithHighestPriority(activeContexts, contextPriorities);
 
         setAudioContextStillActive(context);
 
         return context;
     }
 
-    /**
-     * @see {@link CarAudioService#resetSelectedVolumeContext()}
-     */
-    public void resetSelectedVolumeContext() {
-        setAudioContextStillActive(CarAudioContext.INVALID);
-    }
-
     private @AudioContext int findActiveContextWithHighestPriority(
-            Set<Integer> activeContexts) {
+            Set<Integer> activeContexts, SparseIntArray contextPriorities) {
         int currentContext = DEFAULT_AUDIO_CONTEXT;
         int currentPriority = mLowestPriority;
 
         for (@AudioContext int context : activeContexts) {
-            int priority = mVolumePriorityByAudioContext.get(context, CONTEXT_NOT_PRIORITIZED);
+            int priority = contextPriorities.get(context, CONTEXT_NOT_PRIORITIZED);
             if (priority == CONTEXT_NOT_PRIORITIZED) {
                 continue;
             }
@@ -213,7 +252,7 @@
         return contexts;
     }
 
-    private @AudioContext int getAudioContextStillActive() {
+    private @AudioContext int getAudioContextStillActive(SparseIntArray contextPriorities) {
         @AudioContext int context;
         long contextStartTime;
         synchronized (mLock) {
@@ -225,6 +264,11 @@
             return CarAudioContext.INVALID;
         }
 
+        if (contextPriorities
+                .get(mLastActiveContext, CONTEXT_NOT_PRIORITIZED) == CONTEXT_NOT_PRIORITIZED) {
+            return CarAudioContext.INVALID;
+        }
+
         if (hasExpired(contextStartTime, mClock.uptimeMillis(), mVolumeKeyEventTimeoutMs)) {
             return CarAudioContext.INVALID;
         }
diff --git a/service/src/com/android/car/audio/CarVolumeGroupMuting.java b/service/src/com/android/car/audio/CarVolumeGroupMuting.java
index a51e657..f6d2ce9 100644
--- a/service/src/com/android/car/audio/CarVolumeGroupMuting.java
+++ b/service/src/com/android/car/audio/CarVolumeGroupMuting.java
@@ -123,7 +123,7 @@
 
         writer.println("Un-muted Devices:");
         writer.increaseIndent();
-        dumpDeviceAddresses(writer, info.deviceAddressesToMute);
+        dumpDeviceAddresses(writer, info.deviceAddressesToUnmute);
         writer.decreaseIndent();
     }
 
diff --git a/service/src/com/android/car/pm/CarPackageManagerService.java b/service/src/com/android/car/pm/CarPackageManagerService.java
index 6013371..5d80f38 100644
--- a/service/src/com/android/car/pm/CarPackageManagerService.java
+++ b/service/src/com/android/car/pm/CarPackageManagerService.java
@@ -276,7 +276,7 @@
 
     @Override
     public boolean isActivityDistractionOptimized(String packageName, String className) {
-        checkQueryPermission(packageName);
+        if (!callerCanQueryPackage(packageName)) return false;
         assertPackageAndClassName(packageName, className);
         synchronized (mLock) {
             if (DBG_POLICY_CHECK) {
@@ -312,22 +312,24 @@
     }
 
     @VisibleForTesting
-    void checkQueryPermission(String packageName) {
+    boolean callerCanQueryPackage(String packageName) {
         int callingUid = Binder.getCallingUid();
         if (hasPermissionGranted(QUERY_ALL_PACKAGES, callingUid)) {
-            return;
+            return true;
         }
         String[] packages = mPackageManager.getPackagesForUid(callingUid);
         if (packages != null && packages.length > 0) {
             for (int i = 0; i < packages.length; i++) {
                 if (Objects.equals(packageName, packages[i])) {
-                    return;
+                    return true;
                 }
             }
         }
 
-        throw new SecurityException(QUERY_ALL_PACKAGES
-                + " permission is needed to query other packages.");
+        Slog.w(CarLog.TAG_PACKAGE,
+                QUERY_ALL_PACKAGES + " permission is needed to query other packages.");
+
+        return false;
     }
 
     private static boolean hasPermissionGranted(String permission, int uid) {
@@ -347,7 +349,8 @@
 
     @Override
     public boolean isServiceDistractionOptimized(String packageName, String className) {
-        checkQueryPermission(packageName);
+        if (!callerCanQueryPackage(packageName)) return false;
+
         if (packageName == null) {
             throw new IllegalArgumentException("Package name null");
         }
@@ -386,7 +389,8 @@
     @Override
     public boolean isActivityBackedBySafeActivity(ComponentName activityName) {
         if (activityName == null) return false;
-        checkQueryPermission(activityName.getPackageName());
+        if (!callerCanQueryPackage(activityName.getPackageName())) return false;
+
         RootTaskInfo info = mSystemActivityMonitoringService.getFocusedStackForTopActivity(
                 activityName);
         if (info == null) { // not top in focused stack
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/content/pm/CarPackageManagerPermissionTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/content/pm/CarPackageManagerPermissionTest.java
index be47bad..cdbb56d 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/content/pm/CarPackageManagerPermissionTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/content/pm/CarPackageManagerPermissionTest.java
@@ -15,6 +15,8 @@
  */
 package com.android.car;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.testng.Assert.assertThrows;
 
 import android.car.Car;
@@ -64,19 +66,17 @@
 
     @Test
     public void testIsActivityDistractionOptimized() {
-        assertThrows(SecurityException.class,
-                () -> mPm.isActivityDistractionOptimized("blah", "someClass"));
+        assertThat(mPm.isActivityDistractionOptimized("blah", "someClass")).isFalse();
     }
 
     @Test
     public void testIsServiceDistractionOptimized() {
-        assertThrows(SecurityException.class,
-                () -> mPm.isServiceDistractionOptimized("blah", "someClass"));
+        assertThat(mPm.isServiceDistractionOptimized("blah", "someClass")).isFalse();
     }
 
     @Test
     public void testIsActivityBackedBySafeActivity() {
-        assertThrows(SecurityException.class,
-                () -> mPm.isActivityBackedBySafeActivity(new ComponentName("blah", "someClass")));
+        assertThat(mPm.isActivityBackedBySafeActivity(new ComponentName("blah", "someClass")))
+                .isFalse();
     }
 }
diff --git a/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml b/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
index caa7140..c1fe152 100644
--- a/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
+++ b/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
@@ -25,7 +25,6 @@
     <uses-permission android:name="android.car.permission.CAR_DISPLAY_IN_CLUSTER"/>
     <!-- use for CarServiceTest -->
     <uses-permission android:name="android.car.permission.CAR_DRIVING_STATE"/>
-    <uses-permission android:name="android.car.permission.CAR_ENERGY"/>
     <!-- use for AndroidCarApiTest -->
     <uses-permission android:name="android.car.permission.CAR_INFO"/>
     <!-- use for AndroidCarApiTest -->
@@ -39,7 +38,6 @@
     <uses-permission android:name="android.car.permission.CAR_POWER"/>
     <!-- use for CarServiceTest -->
     <uses-permission android:name="android.car.permission.CAR_POWERTRAIN"/>
-    <uses-permission android:name="android.car.permission.CAR_SPEED"/>
      <!-- use for CarServiceTest -->
     <uses-permission android:name="android.car.permission.CAR_TEST_SERVICE"/>
     <!-- use for CarServiceTest -->
@@ -76,6 +74,8 @@
     <uses-permission android:name="android.permission.ACTIVITY_EMBEDDING"/>
     <uses-permission android:name="android.permission.BLUETOOTH"/>
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
     <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED"/>
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
diff --git a/tests/NetworkPreferenceApp/res/values/configs.xml b/tests/NetworkPreferenceApp/res/values/configs.xml
index 4715f58..21e55de 100644
--- a/tests/NetworkPreferenceApp/res/values/configs.xml
+++ b/tests/NetworkPreferenceApp/res/values/configs.xml
@@ -40,7 +40,25 @@
     -->
     <string-array name="config_network_preference_oem_paid_apps" translatable="false">
         <!-- <item>full.package.name</item> -->
+        <item>com.android.vending</item>
+        <item>com.google.android.apps.automotive.inputmethod</item>
         <item>com.google.android.apps.maps</item>
+        <item>com.google.android.car.setupwizard</item>
+        <item>com.google.android.configupdater</item>
+        <item>com.google.android.ext.services</item>
+        <item>com.google.android.ext.shared</item>
+        <item>com.google.android.feedback</item>
+        <item>com.google.android.gms</item>
+        <item>com.google.android.googlequicksearchbox</item>
+        <item>com.google.android.gsf</item>
+        <item>com.google.android.marvin.talkback</item>
+        <item>com.google.android.onetimeinitializer</item>
+        <item>com.google.android.packageinstaller</item>
+        <item>com.google.android.partnersetup</item>
+        <item>com.google.android.permissioncontroller</item>
+        <item>com.google.android.trichromelibrary</item>
+        <item>com.google.android.tts</item>
+        <item>com.google.android.webview</item>
     </string-array>
     <!--
         Preference: OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK
@@ -67,7 +85,6 @@
     -->
     <string-array name="config_network_preference_oem_private_only" translatable="false">
         <!-- <item>full.package.name</item> -->
-        <item>com.android.car</item>
-        <item>com.android.car.bugreport</item>
+        <item>com.google.android.car.netdbug</item>
     </string-array>
 </resources>
diff --git a/tests/carservice_test/AndroidManifest.xml b/tests/carservice_test/AndroidManifest.xml
index 5c88cb0..7133831 100644
--- a/tests/carservice_test/AndroidManifest.xml
+++ b/tests/carservice_test/AndroidManifest.xml
@@ -26,6 +26,7 @@
     <uses-permission android:name="android.car.permission.CONTROL_CAR_MIRRORS"/>
     <uses-permission android:name="android.car.permission.CONTROL_CAR_SEATS"/>
     <uses-permission android:name="android.car.permission.CAR_ENERGY"/>
+    <uses-permission android:name="android.car.permission.CAR_SPEED"/>
     <uses-permission android:name="android.car.permission.CONTROL_APP_BLOCKING"/>
     <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/>
     <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_SETTINGS"/>
diff --git a/tests/carservice_test/src/com/android/car/pm/CarPackageManagerServiceTest.java b/tests/carservice_test/src/com/android/car/pm/CarPackageManagerServiceTest.java
index 40f4353..b99dd24 100644
--- a/tests/carservice_test/src/com/android/car/pm/CarPackageManagerServiceTest.java
+++ b/tests/carservice_test/src/com/android/car/pm/CarPackageManagerServiceTest.java
@@ -18,13 +18,11 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.testng.Assert.assertThrows;
 
 import android.app.ActivityManager;
 import android.car.test.mocks.AbstractExtendedMockitoTestCase;
@@ -77,8 +75,7 @@
 
         mService.parseConfigList(config, map);
 
-        assertTrue(map.get("com.android.test").size() == 1);
-        assertEquals(".TestActivity", map.get("com.android.test").iterator().next());
+        assertThat(map.get("com.android.test")).containsExactly(".TestActivity");
     }
 
     @Test
@@ -88,7 +85,7 @@
 
         mService.parseConfigList(config, map);
 
-        assertTrue(map.get("com.android.test").size() == 0);
+        assertThat(map.get("com.android.test")).isEmpty();
     }
 
     @Test
@@ -98,9 +95,7 @@
 
         mService.parseConfigList(config, map);
 
-        assertTrue(map.get("com.android.test").size() == 2);
-        assertTrue(map.get("com.android.test").contains(".TestActivity0"));
-        assertTrue(map.get("com.android.test").contains(".TestActivity1"));
+        assertThat(map.get("com.android.test")).containsExactly(".TestActivity0", ".TestActivity1");
     }
 
     @Test
@@ -110,31 +105,28 @@
 
         mService.parseConfigList(config, map);
 
-        assertTrue(map.get("com.android.test").size() == 0);
+        assertThat(map.get("com.android.test")).isEmpty();
     }
 
     @Test
     public void test_checkQueryPermission_noPermission() {
         mockQueryPermission(false);
 
-        assertThrows(SecurityException.class,
-                () -> mService.checkQueryPermission("blah"));
+        assertThat(mService.callerCanQueryPackage("blah")).isFalse();
     }
 
     @Test
     public void test_checkQueryPermission_correctPermission() {
         mockQueryPermission(true);
 
-        // call should complete without exception
-        mService.checkQueryPermission("blah");
+        assertThat(mService.callerCanQueryPackage("blah")).isTrue();
     }
 
     @Test
     public void test_checkQueryPermission_samePackage() {
         mockQueryPermission(false);
 
-        // call should complete without exception
-        mService.checkQueryPermission("com.android.car.test");
+        assertThat(mService.callerCanQueryPackage("com.android.car.test")).isTrue();
     }
 
     private void mockQueryPermission(boolean granted) {
@@ -145,5 +137,4 @@
         doReturn(result).when(() -> ActivityManager.checkComponentPermission(any(), anyInt(),
                 anyInt(), anyBoolean()));
     }
-
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioPolicyVolumeCallbackTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioPolicyVolumeCallbackTest.java
index 80a3d60..0279943 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioPolicyVolumeCallbackTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioPolicyVolumeCallbackTest.java
@@ -26,6 +26,7 @@
 import static android.media.AudioManager.FLAG_FROM_KEY;
 import static android.media.AudioManager.FLAG_SHOW_UI;
 
+import static com.android.car.audio.CarAudioContext.MUSIC;
 import static com.android.car.audio.CarAudioContext.VOICE_COMMAND;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -72,9 +73,11 @@
     @Before
     public void setUp() {
         mCarAudioPolicyVolumeCallback =
-                new CarAudioPolicyVolumeCallback(mMockCarAudioService, mMockAudioManager);
-        when(mMockCarAudioService.getSuggestedAudioContextForPrimaryZone())
+                new CarAudioPolicyVolumeCallback(mMockCarAudioService, mMockAudioManager, false);
+        when(mMockCarAudioService.getSuggestedVolumeContextForPrimaryZone())
                 .thenReturn(VOICE_COMMAND);
+        when(mMockCarAudioService.getSuggestedMuteContextForPrimaryZone())
+                .thenReturn(MUSIC);
         when(mMockCarAudioService.getVolumeGroupIdForAudioContext(anyInt(), anyInt()))
                 .thenReturn(TEST_VOLUME_GROUP);
         when(mMockCarAudioService.getGroupMaxVolume(anyInt(), anyInt()))
@@ -87,28 +90,28 @@
     public void addVolumeCallbackToPolicy_withNullPolicyBuilder_fails() {
         assertThrows(NullPointerException.class, () ->
                 CarAudioPolicyVolumeCallback.addVolumeCallbackToPolicy(
-                        null, mMockCarAudioService, mMockAudioManager));
+                        null, mMockCarAudioService, mMockAudioManager, false));
     }
 
     @Test
     public void addVolumeCallbackToPolicy_withNullCarAudioService_fails() {
         assertThrows(NullPointerException.class, () ->
                 CarAudioPolicyVolumeCallback.addVolumeCallbackToPolicy(mMockBuilder,
-                        null, mMockAudioManager));
+                        null, mMockAudioManager, false));
     }
 
     @Test
     public void addVolumeCallbackToPolicy_withNullAudioManager_fails() {
         assertThrows(NullPointerException.class, () ->
                 CarAudioPolicyVolumeCallback.addVolumeCallbackToPolicy(mMockBuilder,
-                        mMockCarAudioService, null));
+                        mMockCarAudioService, null, false));
     }
 
 
     @Test
     public void addVolumeCallbackToPolicy_registersVolumePolicy() {
         CarAudioPolicyVolumeCallback.addVolumeCallbackToPolicy(mMockBuilder,
-                mMockCarAudioService, mMockAudioManager);
+                mMockCarAudioService, mMockAudioManager, false);
 
         verify(mMockBuilder).setAudioPolicyVolumeCallback(any());
     }
@@ -195,6 +198,42 @@
         verify(mMockCarAudioService).setMasterMute(eq(true), eq(TEST_EXPECTED_FLAGS));
     }
 
+    @Test
+    public void onVolumeAdjustment_forGroupMute_withAdjustMute_mutesVolumeGroup() {
+        CarAudioPolicyVolumeCallback callback =
+                new CarAudioPolicyVolumeCallback(mMockCarAudioService, mMockAudioManager, true);
+
+        callback.onVolumeAdjustment(ADJUST_MUTE);
+
+        verify(mMockCarAudioService).setVolumeGroupMute(eq(PRIMARY_AUDIO_ZONE),
+                eq(TEST_VOLUME_GROUP), eq(true), eq(TEST_EXPECTED_FLAGS));
+    }
+
+    @Test
+    public void onVolumeAdjustment_forGroupMute_withAdjustToggleMute_togglesMutesVolumeGroup() {
+        when(mMockCarAudioService.isVolumeGroupMuted(anyInt(), anyInt()))
+                .thenReturn(true);
+        CarAudioPolicyVolumeCallback callback =
+                new CarAudioPolicyVolumeCallback(mMockCarAudioService, mMockAudioManager, true);
+
+        callback.onVolumeAdjustment(ADJUST_TOGGLE_MUTE);
+
+        verify(mMockCarAudioService).setVolumeGroupMute(eq(PRIMARY_AUDIO_ZONE),
+                eq(TEST_VOLUME_GROUP), eq(false), eq(TEST_EXPECTED_FLAGS));
+    }
+
+    @Test
+    public void onVolumeAdjustment_forGroupMute_withAdjustUnMute_UnMutesVolumeGroup() {
+        when(mMockCarAudioService.isVolumeGroupMuted(anyInt(), anyInt())).thenReturn(false);
+        CarAudioPolicyVolumeCallback callback =
+                new CarAudioPolicyVolumeCallback(mMockCarAudioService, mMockAudioManager, true);
+
+        callback.onVolumeAdjustment(ADJUST_UNMUTE);
+
+        verify(mMockCarAudioService).setVolumeGroupMute(eq(PRIMARY_AUDIO_ZONE),
+                eq(TEST_VOLUME_GROUP), eq(false), eq(TEST_EXPECTED_FLAGS));
+    }
+
     private void setGroupVolume(int groupVolume) {
         when(mMockCarAudioService.getGroupVolume(anyInt(), anyInt()))
                 .thenReturn(groupVolume);
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeTest.java
index 1ef2960..83a494f 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarVolumeTest.java
@@ -25,6 +25,7 @@
 import static android.telephony.TelephonyManager.CALL_STATE_RINGING;
 
 import static com.android.car.audio.CarAudioContext.ALARM;
+import static com.android.car.audio.CarAudioContext.ANNOUNCEMENT;
 import static com.android.car.audio.CarAudioContext.CALL;
 import static com.android.car.audio.CarAudioContext.CALL_RING;
 import static com.android.car.audio.CarAudioContext.INVALID;
@@ -36,6 +37,7 @@
 import static com.android.car.audio.CarAudioService.SystemClockWrapper;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.mockito.Mockito.when;
 import static org.testng.Assert.assertThrows;
@@ -82,68 +84,73 @@
     }
 
     @Test
-    public void createCarVolume_withVersionLessThanOne_failsTooLow() {
+    public void constructor_withVersionLessThanOne_failsTooLow() {
         IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class, () -> {
             new CarVolume(mMockClock, VERSION_ZERO, KEY_EVENT_TIMEOUT_MS);
         });
 
-        assertThat(thrown).hasMessageThat().contains("too low");
+        assertWithMessage("Constructor Exception")
+                .that(thrown).hasMessageThat().contains("too low");
     }
 
     @Test
-    public void createCarVolume_withVersionGreaterThanTwo_failsTooHigh() {
+    public void constructor_withVersionGreaterThanTwo_failsTooHigh() {
         IllegalArgumentException thrown = expectThrows(IllegalArgumentException.class, () -> {
             new CarVolume(mMockClock, VERSION_THREE, KEY_EVENT_TIMEOUT_MS);
         });
 
-        assertThat(thrown).hasMessageThat().contains("too high");
+        assertWithMessage("Constructor Exception")
+                .that(thrown).hasMessageThat().contains("too high");
     }
 
     @Test
-    public void createCarVolume_withNullSystemClock_fails() {
-        expectThrows(NullPointerException.class, () -> {
+    public void constructor_withNullSystemClock_fails() {
+        NullPointerException thrown = expectThrows(NullPointerException.class, () -> {
             new CarVolume(null, VERSION_ONE, KEY_EVENT_TIMEOUT_MS);
         });
+
+        assertWithMessage("Constructor Exception")
+                .that(thrown).hasMessageThat().contains("Clock");
     }
 
     @Test
-    public void getSuggestedAudioContext_withNullActivePlayback_fails() {
+    public void getSuggestedVolumeContext_withNullActivePlayback_fails() {
         assertThrows(NullPointerException.class,
-                () -> mCarVolume.getSuggestedAudioContextAndSaveIfFound(
+                () -> mCarVolume.getSuggestedVolumeContextAndSaveIfFound(
                 null, CALL_STATE_IDLE, new int[0]));
     }
 
     @Test
-    public void getSuggestedAudioContext_withNullHallUsages_fails() {
+    public void getSuggestedVolumeContext_withNullHallUsages_fails() {
         assertThrows(NullPointerException.class,
-                () -> mCarVolume.getSuggestedAudioContextAndSaveIfFound(
+                () -> mCarVolume.getSuggestedVolumeContextAndSaveIfFound(
                 new ArrayList<>(), CALL_STATE_IDLE, null));
     }
 
     @Test
-    public void getSuggestedAudioContext_withNoActivePlaybackAndIdleTelephony_returnsDefault() {
+    public void getSuggestedVolumeContext_withNoActivePlaybackAndIdleTelephony_returnsDefault() {
         @AudioContext int suggestedContext =
-                mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
+                mCarVolume.getSuggestedVolumeContextAndSaveIfFound(new ArrayList<>(),
                 CALL_STATE_IDLE, new int[0]);
 
         assertThat(suggestedContext).isEqualTo(CarAudioService.DEFAULT_AUDIO_CONTEXT);
     }
 
     @Test
-    public void getSuggestedAudioContext_withOneConfiguration_returnsAssociatedContext() {
+    public void getSuggestedVolumeContext_withOneConfiguration_returnsAssociatedContext() {
         List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
 
         @AudioContext int suggestedContext = mCarVolume
-                .getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
+                .getSuggestedVolumeContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
                         new int[0]);
 
         assertThat(suggestedContext).isEqualTo(VOICE_COMMAND);
     }
 
     @Test
-    public void getSuggestedAudioContext_withCallStateOffHook_returnsCallContext() {
+    public void getSuggestedVolumeContext_withCallStateOffHook_returnsCallContext() {
         @AudioContext int suggestedContext =
-                mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
+                mCarVolume.getSuggestedVolumeContextAndSaveIfFound(new ArrayList<>(),
                         CALL_STATE_OFFHOOK, new int[0]);
 
         assertThat(suggestedContext).isEqualTo(CALL);
@@ -151,152 +158,152 @@
 
     @Test
 
-    public void getSuggestedAudioContext_withV1AndCallStateRinging_returnsCallRingContext() {
+    public void getSuggestedVolumeContext_withV1AndCallStateRinging_returnsCallRingContext() {
         CarVolume carVolume = new CarVolume(mMockClock, VERSION_ONE, KEY_EVENT_TIMEOUT_MS);
 
         @AudioContext int suggestedContext =
-                carVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
+                carVolume.getSuggestedVolumeContextAndSaveIfFound(new ArrayList<>(),
                 CALL_STATE_RINGING, new int[0]);
 
         assertThat(suggestedContext).isEqualTo(CALL_RING);
     }
 
     @Test
-    public void getSuggestedAudioContext_withActivePlayback_returnsHighestPriorityContext() {
+    public void getSuggestedVolumeContext_withActivePlayback_returnsHighestPriorityContext() {
         List<Integer> activePlaybackContexts = ImmutableList.of(ALARM, CALL, NOTIFICATION);
 
         @AudioContext int suggestedContext = mCarVolume
-                .getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
+                .getSuggestedVolumeContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
                         new int[0]);
 
         assertThat(suggestedContext).isEqualTo(CALL);
     }
 
     @Test
-    public void getSuggestedAudioContext_withLowerPriorityActivePlaybackAndCall_returnsCall() {
+    public void getSuggestedVolumeContext_withLowerPriorityActivePlaybackAndCall_returnsCall() {
         List<Integer> activePlaybackContexts = ImmutableList.of(ALARM, NOTIFICATION);
 
         @AudioContext int suggestedContext = mCarVolume
-                .getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_OFFHOOK,
+                .getSuggestedVolumeContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_OFFHOOK,
                         new int[0]);
 
         assertThat(suggestedContext).isEqualTo(CALL);
     }
 
     @Test
-    public void getSuggestedAudioContext_withV1AndNavigationConfigurationAndCall_returnsNav() {
+    public void getSuggestedVolumeContext_withV1AndNavigationConfigurationAndCall_returnsNav() {
         CarVolume carVolume = new CarVolume(mMockClock, VERSION_ONE, KEY_EVENT_TIMEOUT_MS);
         List<Integer> activePlaybackContexts = ImmutableList.of(NAVIGATION);
 
         @AudioContext int suggestedContext = carVolume
-                .getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_OFFHOOK,
+                .getSuggestedVolumeContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_OFFHOOK,
                         new int[0]);
 
         assertThat(suggestedContext).isEqualTo(NAVIGATION);
     }
 
     @Test
-    public void getSuggestedAudioContext_withV2AndNavigationConfigurationAndCall_returnsCall() {
+    public void getSuggestedVolumeContext_withV2AndNavigationConfigurationAndCall_returnsCall() {
         List<Integer> activePlaybackContexts = ImmutableList.of(NAVIGATION);
 
         @AudioContext int suggestedContext = mCarVolume
-                .getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_OFFHOOK,
+                .getSuggestedVolumeContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_OFFHOOK,
                         new int[0]);
 
         assertThat(suggestedContext).isEqualTo(CALL);
     }
 
     @Test
-    public void getSuggestedAudioContext_withUnprioritizedUsage_returnsDefault() {
+    public void getSuggestedVolumeContext_withUnprioritizedUsage_returnsDefault() {
         List<Integer> activePlaybackContexts = ImmutableList.of(INVALID);
 
         @AudioContext int suggestedContext = mCarVolume
-                .getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
+                .getSuggestedVolumeContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
                         new int[0]);
 
         assertThat(suggestedContext).isEqualTo(DEFAULT_AUDIO_CONTEXT);
     }
 
     @Test
-    public void getSuggestedAudioContext_withHalActiveUsage_returnsHalActive() {
+    public void getSuggestedVolumeContext_withHalActiveUsage_returnsHalActive() {
         int[] activeHalUsages = new int[] {USAGE_ASSISTANT};
 
         @AudioContext int suggestedContext =
-                mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
+                mCarVolume.getSuggestedVolumeContextAndSaveIfFound(new ArrayList<>(),
                 CALL_STATE_IDLE, activeHalUsages);
 
         assertThat(suggestedContext).isEqualTo(VOICE_COMMAND);
     }
 
     @Test
-    public void getSuggestedAudioContext_withHalUnprioritizedUsage_returnsDefault() {
+    public void getSuggestedVolumeContext_withHalUnprioritizedUsage_returnsDefault() {
         int[] activeHalUsages = new int[] {USAGE_VIRTUAL_SOURCE};
 
         @AudioContext int suggestedContext =
-                mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
+                mCarVolume.getSuggestedVolumeContextAndSaveIfFound(new ArrayList<>(),
                 CALL_STATE_IDLE, activeHalUsages);
 
         assertThat(suggestedContext).isEqualTo(DEFAULT_AUDIO_CONTEXT);
     }
 
     @Test
-    public void getSuggestedAudioContext_withConfigAndHalActiveUsage_returnsConfigActive() {
+    public void getSuggestedVolumeContext_withConfigAndHalActiveUsage_returnsConfigActive() {
         int[] activeHalUsages = new int[] {USAGE_ASSISTANT};
         List<Integer> activePlaybackContexts = ImmutableList.of(MUSIC);
 
         @AudioContext int suggestedContext = mCarVolume
-                .getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
+                .getSuggestedVolumeContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
                         activeHalUsages);
 
         assertThat(suggestedContext).isEqualTo(MUSIC);
     }
 
     @Test
-    public void getSuggestedAudioContext_withConfigAndHalActiveUsage_returnsHalActive() {
+    public void getSuggestedVolumeContext_withConfigAndHalActiveUsage_returnsHalActive() {
         int[] activeHalUsages = new int[] {USAGE_MEDIA};
         List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
 
         @AudioContext int suggestedContext = mCarVolume
-                .getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
+                .getSuggestedVolumeContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
                         activeHalUsages);
 
         assertThat(suggestedContext).isEqualTo(MUSIC);
     }
 
     @Test
-    public void getSuggestedAudioContext_withHalActiveUsageAndActiveCall_returnsCall() {
+    public void getSuggestedVolumeContext_withHalActiveUsageAndActiveCall_returnsCall() {
         int[] activeHalUsages = new int[] {USAGE_MEDIA};
         List<Integer> activePlaybackContexts = new ArrayList<>();
 
-        @AudioContext int suggestedContext = mCarVolume.getSuggestedAudioContextAndSaveIfFound(
+        @AudioContext int suggestedContext = mCarVolume.getSuggestedVolumeContextAndSaveIfFound(
                 activePlaybackContexts, CALL_STATE_OFFHOOK, activeHalUsages);
 
         assertThat(suggestedContext).isEqualTo(CALL);
     }
 
     @Test
-    public void getSuggestedAudioContext_withMultipleHalActiveUsages_returnsMusic() {
+    public void getSuggestedVolumeContext_withMultipleHalActiveUsages_returnsMusic() {
         int[] activeHalUsages = new int[] {USAGE_MEDIA, USAGE_ANNOUNCEMENT, USAGE_ASSISTANT};
         List<Integer> activePlaybackContexts = new ArrayList<>();
 
         @AudioContext int suggestedContext = mCarVolume
-                .getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
+                .getSuggestedVolumeContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
                         activeHalUsages);
 
         assertThat(suggestedContext).isEqualTo(MUSIC);
     }
 
     @Test
-    public void getSuggestedAudioContext_withStillActiveContext_returnsPrevActiveContext() {
+    public void getSuggestedVolumeContext_withStillActiveContext_returnsPrevActiveContext() {
         List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
 
-        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
+        mCarVolume.getSuggestedVolumeContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
                 new int[0]);
 
         when(mMockClock.uptimeMillis()).thenReturn(START_TIME_ONE_SECOND);
 
         @AudioContext int suggestedContext =
-                mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
+                mCarVolume.getSuggestedVolumeContextAndSaveIfFound(new ArrayList<>(),
                 CALL_STATE_IDLE, new int[0]);
 
         assertThat(suggestedContext).isEqualTo(VOICE_COMMAND);
@@ -304,10 +311,10 @@
 
     @Test
     public void
-            getSuggestedAudioContext_withStillActiveContext_returnPrevActiveContextMultipleTimes() {
+            getSuggestedVolumeContext_withStillActiveContext_retPrevActiveContextMultipleTimes() {
         List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
 
-        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
+        mCarVolume.getSuggestedVolumeContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
                 new int[0]);
 
         long deltaTime = KEY_EVENT_TIMEOUT_MS - 1;
@@ -316,7 +323,7 @@
                     .thenReturn(START_TIME + (volumeCounter * deltaTime));
 
             @AudioContext int suggestedContext =
-                    mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
+                    mCarVolume.getSuggestedVolumeContextAndSaveIfFound(new ArrayList<>(),
                             CALL_STATE_IDLE, new int[0]);
             assertThat(suggestedContext).isEqualTo(VOICE_COMMAND);
         }
@@ -324,32 +331,32 @@
 
     @Test
     public void
-            getSuggestedAudioContext_withActContextAndNewHigherPrioContext_returnPrevActContext() {
+            getSuggestedVolumeContext_withActContextAndNewHigherPrioContext_returnPrevActContext() {
         List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
 
-        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
+        mCarVolume.getSuggestedVolumeContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
                 new int[0]);
 
         when(mMockClock.uptimeMillis()).thenReturn(START_TIME_ONE_SECOND);
 
         @AudioContext int suggestedContext =
-                mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
+                mCarVolume.getSuggestedVolumeContextAndSaveIfFound(new ArrayList<>(),
                 CALL_STATE_OFFHOOK, new int[0]);
 
         assertThat(suggestedContext).isEqualTo(VOICE_COMMAND);
     }
 
     @Test
-    public void getSuggestedAudioContext_afterActiveContextTimeout_returnsDefaultContext() {
+    public void getSuggestedVolumeContext_afterActiveContextTimeout_returnsDefaultContext() {
         List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
 
-        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
+        mCarVolume.getSuggestedVolumeContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
                         new int[0]);
 
         when(mMockClock.uptimeMillis()).thenReturn(START_TIME_FOUR_SECOND);
 
         @AudioContext int suggestedContext =
-                mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
+                mCarVolume.getSuggestedVolumeContextAndSaveIfFound(new ArrayList<>(),
                 CALL_STATE_IDLE, new int[0]);
 
         assertThat(suggestedContext).isEqualTo(DEFAULT_AUDIO_CONTEXT);
@@ -357,16 +364,16 @@
 
     @Test
     public void
-            getSuggestedAudioContext_afterActiveContextTimeoutAndNewContext_returnsNewContext() {
+            getSuggestedVolumeContext_afterActiveContextTimeoutAndNewContext_returnsNewContext() {
         List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
 
-        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
+        mCarVolume.getSuggestedVolumeContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
                 new int[0]);
 
         when(mMockClock.uptimeMillis()).thenReturn(START_TIME_FOUR_SECOND);
 
         @AudioContext int suggestedContext =
-                mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
+                mCarVolume.getSuggestedVolumeContextAndSaveIfFound(new ArrayList<>(),
                 CALL_STATE_OFFHOOK, new int[0]);
 
         assertThat(suggestedContext).isEqualTo(CALL);
@@ -374,10 +381,10 @@
 
     @Test
     public void
-            getSuggestedAudioContext_afterMultipleQueriesAndNewContextCall_returnsNewContext() {
+            getSuggestedVolumeContext_afterMultipleQueriesAndNewContextCall_returnsNewContext() {
         List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
 
-        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
+        mCarVolume.getSuggestedVolumeContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
                 new int[0]);
 
 
@@ -386,7 +393,7 @@
         for (int volumeCounter = 1; volumeCounter < TRIAL_COUNTS; volumeCounter++) {
             when(mMockClock.uptimeMillis()).thenReturn(START_TIME + volumeCounter * deltaTime);
 
-            mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(), CALL_STATE_IDLE,
+            mCarVolume.getSuggestedVolumeContextAndSaveIfFound(new ArrayList<>(), CALL_STATE_IDLE,
                             new int[0]);
         }
 
@@ -394,17 +401,17 @@
                 .thenReturn(START_TIME + (TRIAL_COUNTS * deltaTime) + KEY_EVENT_TIMEOUT_MS);
 
         @AudioContext int newContext =
-                mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
+                mCarVolume.getSuggestedVolumeContextAndSaveIfFound(new ArrayList<>(),
                 CALL_STATE_OFFHOOK, new int[0]);
 
         assertThat(newContext).isEqualTo(CALL);
     }
 
     @Test
-    public void getSuggestedAudioContext_afterResetSelectedVolumeContext_returnsDefaultContext() {
+    public void getSuggestedVolumeContext_afterResetSelectedVolumeContext_returnsDefaultContext() {
         List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
 
-        mCarVolume.getSuggestedAudioContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
+        mCarVolume.getSuggestedVolumeContextAndSaveIfFound(activePlaybackContexts, CALL_STATE_IDLE,
                 new int[0]);
 
         when(mMockClock.uptimeMillis()).thenReturn(START_TIME_ONE_SECOND);
@@ -412,7 +419,7 @@
         mCarVolume.resetSelectedVolumeContext();
 
         @AudioContext int suggestedContext =
-                mCarVolume.getSuggestedAudioContextAndSaveIfFound(new ArrayList<>(),
+                mCarVolume.getSuggestedVolumeContextAndSaveIfFound(new ArrayList<>(),
                         CALL_STATE_IDLE, new int[0]);
 
         assertThat(suggestedContext).isEqualTo(DEFAULT_AUDIO_CONTEXT);
@@ -546,4 +553,73 @@
                 () -> CarVolume.isAnyContextActive(activeContexts,
                         activePlaybackContexts, CALL_STATE_OFFHOOK, activeHalUsages));
     }
+
+    @Test
+    public void
+            getSuggestedMuteContext_withNoActivePlaybackAndIdleTelephony_returnsDefault() {
+        @AudioContext int suggestedContext =
+                mCarVolume.getSuggestedMuteContextAndSaveIfFound(new ArrayList<>(),
+                        CALL_STATE_IDLE, new int[0]);
+
+        assertThat(suggestedContext).isEqualTo(CarAudioService.DEFAULT_AUDIO_CONTEXT);
+    }
+
+    @Test
+    public void getSuggestedMuteContext_withActiveVoicePlayback_returnsDefault() {
+        List<Integer> activePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
+
+        @AudioContext int suggestedContext =
+                mCarVolume.getSuggestedMuteContextAndSaveIfFound(activePlaybackContexts,
+                        CALL_STATE_IDLE, new int[0]);
+
+        assertThat(suggestedContext).isEqualTo(CarAudioService.DEFAULT_AUDIO_CONTEXT);
+    }
+
+    @Test
+    public void getSuggestedMuteContext_withActiveCall_returnsCallContext() {
+        @AudioContext int suggestedContext =
+                mCarVolume.getSuggestedMuteContextAndSaveIfFound(new ArrayList<>(),
+                        CALL_STATE_OFFHOOK, new int[0]);
+
+        assertThat(suggestedContext).isEqualTo(CALL);
+    }
+
+    @Test
+    public void getSuggestedMuteContext_withActiveAnnouncementConfig_returnsAnnouncement() {
+        List<Integer> activePlaybackContexts = ImmutableList.of(ANNOUNCEMENT);
+
+        @AudioContext int suggestedContext =
+                mCarVolume.getSuggestedMuteContextAndSaveIfFound(activePlaybackContexts,
+                        CALL_STATE_IDLE, new int[0]);
+
+        assertThat(suggestedContext).isEqualTo(ANNOUNCEMENT);
+    }
+
+    @Test
+    public void getSuggestedMuteContext_withVoiceLastActiveConfig_returnsAnnouncement() {
+        List<Integer> voiceActivePlaybackContexts = ImmutableList.of(VOICE_COMMAND);
+        mCarVolume.getSuggestedVolumeContextAndSaveIfFound(voiceActivePlaybackContexts,
+                        CALL_STATE_IDLE, new int[0]);
+        List<Integer> activePlaybackContexts = ImmutableList.of(ANNOUNCEMENT);
+
+        @AudioContext int suggestedContext =
+                mCarVolume.getSuggestedMuteContextAndSaveIfFound(activePlaybackContexts,
+                        CALL_STATE_IDLE, new int[0]);
+
+        assertThat(suggestedContext).isEqualTo(ANNOUNCEMENT);
+    }
+
+    @Test
+    public void getSuggestedMuteContext_withMusicLastActiveConfig_returnsMusic() {
+        List<Integer> musicActivePlaybackContexts = ImmutableList.of(MUSIC);
+        mCarVolume.getSuggestedVolumeContextAndSaveIfFound(musicActivePlaybackContexts,
+                CALL_STATE_IDLE, new int[0]);
+        List<Integer> activePlaybackContexts = ImmutableList.of(ANNOUNCEMENT);
+
+        @AudioContext int suggestedContext =
+                mCarVolume.getSuggestedMuteContextAndSaveIfFound(activePlaybackContexts,
+                        CALL_STATE_IDLE, new int[0]);
+
+        assertThat(suggestedContext).isEqualTo(MUSIC);
+    }
 }
diff --git a/tests/obd2_app/AndroidManifest.xml b/tests/obd2_app/AndroidManifest.xml
index b9adf2a..12b9bc6 100644
--- a/tests/obd2_app/AndroidManifest.xml
+++ b/tests/obd2_app/AndroidManifest.xml
@@ -17,6 +17,9 @@
      package="com.google.android.car.obd2app">
 
   <uses-permission android:name="android.permission.BLUETOOTH"/>
+  <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+  <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
+  <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
   <application android:allowBackup="true"
        android:debuggable="true"