1 /* 2 * Copyright (C) 2020 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 com.android.cts.verifier.audio; 18 19 import static com.android.cts.verifier.TestListActivity.sCurrentDisplayMode; 20 import static com.android.cts.verifier.TestListAdapter.setTestNameSuffix; 21 22 import android.content.BroadcastReceiver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.media.AudioDeviceCallback; 27 import android.media.AudioDeviceInfo; 28 import android.media.AudioManager; 29 import android.os.Bundle; 30 import android.os.Handler; 31 import android.util.Log; 32 import android.widget.TextView; 33 34 import com.android.compatibility.common.util.CddTest; 35 import com.android.compatibility.common.util.ResultType; 36 import com.android.compatibility.common.util.ResultUnit; 37 import com.android.cts.verifier.CtsVerifierReportLog; 38 import com.android.cts.verifier.PassFailButtons; 39 import com.android.cts.verifier.R; // needed to access resource in CTSVerifier project namespace. 40 41 @CddTest(requirement = "7.8.2.2/H-2-1,H-3-1,H-4-2,H-4-3,H-4-4,H-4-5") 42 public class USBAudioPeripheralNotificationsTest extends PassFailButtons.Activity { 43 private static final String 44 TAG = USBAudioPeripheralNotificationsTest.class.getSimpleName(); 45 46 private AudioManager mAudioManager; 47 48 private TextView mHeadsetInName; 49 private TextView mHeadsetOutName; 50 private TextView mUsbDeviceInName; 51 private TextView mUsbDeviceOutName; 52 53 // private TextView mHeadsetPlugText; 54 private TextView mHeadsetPlugMessage; 55 56 // Intents 57 private HeadsetPlugReceiver mHeadsetPlugReceiver; 58 private boolean mPlugIntentReceived; 59 60 // Device 61 private AudioDeviceInfo mUsbHeadsetInInfo; 62 private AudioDeviceInfo mUsbHeadsetOutInfo; 63 private AudioDeviceInfo mUsbDeviceInInfo; 64 private AudioDeviceInfo mUsbDeviceOutInfo; 65 66 private boolean mUsbHeadsetInReceived; 67 private boolean mUsbHeadsetOutReceived; 68 private boolean mUsbDeviceInReceived; 69 private boolean mUsbDeviceOutReceived; 70 71 @Override onCreate(Bundle savedInstanceState)72 protected void onCreate(Bundle savedInstanceState) { 73 super.onCreate(savedInstanceState); 74 setContentView(R.layout.uap_notifications_layout); 75 76 mHeadsetInName = (TextView)findViewById(R.id.uap_messages_headset_in_name); 77 mHeadsetOutName = (TextView)findViewById(R.id.uap_messages_headset_out_name); 78 79 mUsbDeviceInName = (TextView)findViewById(R.id.uap_messages_usb_device_in_name); 80 mUsbDeviceOutName = (TextView)findViewById(R.id.uap_messages_usb_device__out_name); 81 82 mHeadsetPlugMessage = (TextView)findViewById(R.id.uap_messages_plug_message); 83 84 mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE); 85 mAudioManager.registerAudioDeviceCallback(new ConnectListener(), new Handler()); 86 87 mHeadsetPlugReceiver = new HeadsetPlugReceiver(); 88 IntentFilter filter = new IntentFilter(); 89 filter.addAction(Intent.ACTION_HEADSET_PLUG); 90 registerReceiver(mHeadsetPlugReceiver, filter); 91 92 setInfoResources(R.string.audio_uap_notifications_test, R.string.uapNotificationsTestInfo, 93 -1); 94 95 setPassFailButtonClickListeners(); 96 getPassButton().setEnabled(false); 97 } 98 99 // 100 // UI 101 // showConnectedDevices()102 private void showConnectedDevices() { 103 if (mUsbHeadsetInInfo != null) { 104 mHeadsetInName.setText( 105 "Headset INPUT Connected " + mUsbHeadsetInInfo.getProductName()); 106 } else { 107 mHeadsetInName.setText(""); 108 } 109 110 if (mUsbHeadsetOutInfo != null) { 111 mHeadsetOutName.setText( 112 "Headset OUTPUT Connected " + mUsbHeadsetOutInfo.getProductName()); 113 } else { 114 mHeadsetOutName.setText(""); 115 } 116 117 if (mUsbDeviceInInfo != null) { 118 mUsbDeviceInName.setText( 119 "USB DEVICE INPUT Connected " + mUsbDeviceInInfo.getProductName()); 120 } else { 121 mUsbDeviceInName.setText(""); 122 } 123 124 if (mUsbDeviceOutInfo != null) { 125 mUsbDeviceOutName.setText( 126 "USB DEVICE OUTPUT Connected " + mUsbDeviceOutInfo.getProductName()); 127 } else { 128 mUsbDeviceOutName.setText(""); 129 } 130 } 131 132 @Override requiresReportLog()133 public boolean requiresReportLog() { 134 return true; 135 } 136 137 @Override getReportFileName()138 public String getReportFileName() { 139 return PassFailButtons.AUDIO_TESTS_REPORT_LOG_NAME; 140 } 141 142 @Override getReportSectionName()143 public final String getReportSectionName() { 144 return setTestNameSuffix(sCurrentDisplayMode, SECTION_USBDEVICENOTIFICATIONS); 145 } 146 147 // ReportLog Schema 148 private static final String SECTION_USBDEVICENOTIFICATIONS = 149 "usb_audio_peripheral_notifications_activity"; 150 151 private static final String KEY_HEADSET_IN = "headset_in_received"; 152 private static final String KEY_HEADSET_OUT = "headset_out_received"; 153 private static final String KEY_DEVICE_IN = "device_in_received"; 154 private static final String KEY_DEVICE_OUT = "device_out_received"; 155 156 @Override recordTestResults()157 public void recordTestResults() { 158 CtsVerifierReportLog reportLog = getReportLog(); 159 160 reportLog.addValue( 161 KEY_HEADSET_IN, 162 mUsbHeadsetInReceived, 163 ResultType.NEUTRAL, 164 ResultUnit.NONE); 165 166 reportLog.addValue( 167 KEY_HEADSET_OUT, 168 mUsbHeadsetOutReceived, 169 ResultType.NEUTRAL, 170 ResultUnit.NONE); 171 172 reportLog.addValue( 173 KEY_DEVICE_IN, 174 mUsbDeviceInReceived, 175 ResultType.NEUTRAL, 176 ResultUnit.NONE); 177 178 reportLog.addValue( 179 KEY_DEVICE_OUT, 180 mUsbDeviceOutReceived, 181 ResultType.NEUTRAL, 182 ResultUnit.NONE); 183 184 reportLog.submit(); 185 } 186 reportPlugIntent(Intent intent)187 private void reportPlugIntent(Intent intent) { 188 // [ 7.8 .2.2/H-2-1] MUST broadcast Intent ACTION_HEADSET_PLUG with "microphone" extra 189 // set to 0 when the USB audio terminal types 0x0302 is detected. 190 // [ 7.8 .2.2/H-3-1] MUST broadcast Intent ACTION_HEADSET_PLUG with "microphone" extra 191 // set to 1 when the USB audio terminal types 0x0402 is detected, they: 192 mPlugIntentReceived = true; 193 194 // state - 0 for unplugged, 1 for plugged. 195 // name - Headset type, human readable string 196 // microphone - 1 if headset has a microphone, 0 otherwise 197 int state = intent.getIntExtra("state", -1); 198 if (state != -1) { 199 200 StringBuilder sb = new StringBuilder(); 201 sb.append("ACTION_HEADSET_PLUG received - " + (state == 0 ? "Unplugged" : "Plugged")); 202 203 String name = intent.getStringExtra("name"); 204 if (name != null) { 205 sb.append(" - " + name); 206 } 207 208 int hasMic = intent.getIntExtra("microphone", 0); 209 if (hasMic == 1) { 210 sb.append(" [mic]"); 211 } 212 213 mHeadsetPlugMessage.setText(sb.toString()); 214 } 215 216 getPassButton().setEnabled(calculatePass()); 217 } 218 219 // 220 // Test Status 221 // calculatePass()222 private boolean calculatePass() { 223 return isReportLogOkToPass() 224 && mUsbHeadsetInReceived && mUsbHeadsetOutReceived 225 && mUsbDeviceInReceived && mUsbDeviceOutReceived 226 && mPlugIntentReceived; 227 } 228 229 // 230 // Devices 231 // scanDevices(AudioDeviceInfo[] devices)232 private void scanDevices(AudioDeviceInfo[] devices) { 233 mUsbHeadsetInInfo = mUsbHeadsetOutInfo = 234 mUsbDeviceInInfo = mUsbDeviceOutInfo = null; 235 236 for (AudioDeviceInfo devInfo : devices) { 237 if (devInfo.getType() == AudioDeviceInfo.TYPE_USB_HEADSET) { 238 if (devInfo.isSource()) { 239 // [ 7.8 .2.2/H-4-3] MUST list a device of type AudioDeviceInfo.TYPE_USB_HEADSET 240 // and role isSource() if the USB audio terminal type field is 0x0402. 241 mUsbHeadsetInReceived = true; 242 mUsbHeadsetInInfo = devInfo; 243 } else if (devInfo.isSink()) { 244 // [ 7.8 .2.2/H-4-2] MUST list a device of type AudioDeviceInfo.TYPE_USB_HEADSET 245 // and role isSink() if the USB audio terminal type field is 0x0402. 246 mUsbHeadsetOutReceived = true; 247 mUsbHeadsetOutInfo = devInfo; 248 } 249 } else if (devInfo.getType() == AudioDeviceInfo.TYPE_USB_DEVICE) { 250 if (devInfo.isSource()) { 251 // [ 7.8 .2.2/H-4-5] MUST list a device of type AudioDeviceInfo.TYPE_USB_DEVICE 252 // and role isSource() if the USB audio terminal type field is 0x604. 253 mUsbDeviceInReceived = true; 254 mUsbDeviceInInfo = devInfo; 255 } else if (devInfo.isSink()) { 256 // [ 7.8 .2.2/H-4-4] MUST list a device of type AudioDeviceInfo.TYPE_USB_DEVICE 257 // and role isSink() if the USB audio terminal type field is 0x603. 258 mUsbDeviceOutReceived = true; 259 mUsbDeviceOutInfo = devInfo; 260 } 261 } 262 263 if (mUsbHeadsetInInfo != null && 264 mUsbHeadsetOutInfo != null && 265 mUsbDeviceInInfo != null && 266 mUsbDeviceOutInfo != null) { 267 break; 268 } 269 } 270 271 272 showConnectedDevices(); 273 getPassButton().setEnabled(calculatePass()); 274 } 275 276 private class ConnectListener extends AudioDeviceCallback { ConnectListener()277 /*package*/ ConnectListener() {} 278 279 // 280 // AudioDevicesManager.OnDeviceConnectionListener 281 // 282 @Override onAudioDevicesAdded(AudioDeviceInfo[] addedDevices)283 public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) { 284 Log.i(TAG, "onAudioDevicesAdded() num:" + addedDevices.length); 285 286 scanDevices(mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL)); 287 } 288 289 @Override onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices)290 public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) { 291 Log.i(TAG, "onAudioDevicesRemoved() num:" + removedDevices.length); 292 293 scanDevices(mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL)); 294 } 295 } 296 297 // Intents 298 private class HeadsetPlugReceiver extends BroadcastReceiver { 299 @Override onReceive(Context context, Intent intent)300 public void onReceive(Context context, Intent intent) { 301 reportPlugIntent(intent); 302 } 303 } 304 305 } 306