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