1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.media.audio.cts; 18 19 import android.content.pm.PackageManager; 20 import android.media.AudioManager; 21 import android.os.SystemClock; 22 import android.platform.test.annotations.AppModeFull; 23 import android.util.Log; 24 25 import androidx.test.filters.SdkSuppress; 26 27 import com.android.compatibility.common.util.CtsAndroidTestCase; 28 import com.android.internal.annotations.GuardedBy; 29 30 import java.util.concurrent.Executors; 31 32 33 34 @SdkSuppress(minSdkVersion = 31, codeName = "S") 35 public class AudioModeListenerTest extends CtsAndroidTestCase { 36 private final static String TAG = "AudioModeListenerTest"; 37 38 private AudioManager mAudioManager; 39 40 @Override setUp()41 protected void setUp() throws Exception { 42 super.setUp(); 43 mAudioManager = getInstrumentation().getContext().getSystemService(AudioManager.class); 44 } 45 46 static class MyOnModeChangedListener implements AudioManager.OnModeChangedListener { 47 48 private final Object mCbLock = new Object(); 49 @GuardedBy("mCbLock") 50 private boolean mCalled; 51 @GuardedBy("mCbLock") 52 private int mMode; 53 54 private static final int LISTENER_WAIT_TIMEOUT_MS = 3000; reset()55 void reset() { 56 synchronized (mCbLock) { 57 mCalled = false; 58 mMode = -1977; // magic value that doesn't match any mode 59 } 60 } 61 wasCalled()62 boolean wasCalled() { 63 synchronized (mCbLock) { 64 return mCalled; 65 } 66 } 67 waitForModeUpdate()68 int waitForModeUpdate() { 69 synchronized (mCbLock) { 70 long endTimeMillis = SystemClock.uptimeMillis() + LISTENER_WAIT_TIMEOUT_MS; 71 long waiTimeMillis = endTimeMillis - SystemClock.uptimeMillis(); 72 while (!mCalled && waiTimeMillis > 0) { 73 try { 74 mCbLock.wait(waiTimeMillis); 75 } catch (InterruptedException e) { 76 } 77 waiTimeMillis = endTimeMillis - SystemClock.uptimeMillis(); 78 } 79 return mMode; 80 } 81 } 82 getMode()83 int getMode() { 84 synchronized (mCbLock) { 85 return mMode; 86 } 87 } 88 MyOnModeChangedListener()89 MyOnModeChangedListener() { 90 reset(); 91 } 92 93 @Override onModeChanged(int mode)94 public void onModeChanged(int mode) { 95 synchronized (mCbLock) { 96 mCalled = true; 97 mMode = mode; 98 mCbLock.notifyAll(); 99 } 100 } 101 } 102 103 @AppModeFull(reason = "Instant apps don't have MODIFY_AUDIO_SETTINGS") testModeListener()104 public void testModeListener() throws Exception { 105 if (!isValidPlatform("testModeListener")) return; 106 107 MyOnModeChangedListener listener = new MyOnModeChangedListener(); 108 109 try { 110 mAudioManager.addOnModeChangedListener(null, listener); 111 fail("addOnModeChangedListener should fail with null executor"); 112 } catch (Exception e) { 113 } 114 115 try { 116 mAudioManager.addOnModeChangedListener( 117 Executors.newSingleThreadExecutor(), null); 118 fail("addOnModeChangedListener should fail with null listener"); 119 } catch (Exception e) { 120 } 121 122 try { 123 mAudioManager.removeOnModeChangedListener(null); 124 fail("removeOnModeChangedListener should fail with null listener"); 125 } catch (Exception e) { 126 } 127 128 try { 129 mAudioManager.addOnModeChangedListener( 130 Executors.newSingleThreadExecutor(), listener); 131 } catch (Exception e) { 132 fail("addOnModeChangedListener failed with exception: " + e); 133 } 134 135 try { 136 mAudioManager.addOnModeChangedListener( 137 Executors.newSingleThreadExecutor(), listener); 138 fail("addOnCommunicationDeviceChangedListener succeeded for same listener"); 139 } catch (Exception e) { 140 } 141 142 int originalMode = mAudioManager.getMode(); 143 int testMode = (originalMode == AudioManager.MODE_NORMAL) 144 ? AudioManager.MODE_RINGTONE : AudioManager.MODE_NORMAL; 145 146 mAudioManager.setMode(testMode); 147 int dispatchedMode = listener.waitForModeUpdate(); 148 assertTrue("listener wasn't called", listener.wasCalled()); 149 assertEquals("Mode not updated correctly", testMode, dispatchedMode); 150 151 listener.reset(); 152 153 if (originalMode == AudioManager.MODE_NORMAL) { 154 mAudioManager.setMode(originalMode); 155 156 dispatchedMode = listener.waitForModeUpdate(); 157 assertTrue("listener wasn't called for mode restore", listener.wasCalled()); 158 assertEquals("Mode not updated correctly for mode restore", 159 originalMode, dispatchedMode); 160 } 161 162 try { 163 mAudioManager.removeOnModeChangedListener(listener); 164 } catch (Exception e) { 165 fail("removeOnModeChangedListener failed with exception: " + e); 166 } 167 } 168 isValidPlatform(String testName)169 private boolean isValidPlatform(String testName) { 170 PackageManager pm = getInstrumentation().getContext().getPackageManager(); 171 if (!pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT) 172 || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY) 173 || !pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { 174 Log.i(TAG,"Skipping test " + testName 175 + " : device has no audio output or is a TV or does not support telephony"); 176 return false; 177 } 178 return true; 179 } 180 } 181