1 /* 2 * Copyright (C) 2017 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.app.AlertDialog; 20 import android.media.AudioDeviceCallback; 21 import android.media.AudioDeviceInfo; 22 import android.media.AudioManager; 23 import android.os.Bundle; 24 import android.util.Log; 25 import android.view.View; 26 import android.view.View.OnClickListener; 27 import android.widget.TextView; 28 29 import com.android.compatibility.common.util.ResultType; 30 import com.android.compatibility.common.util.ResultUnit; 31 import com.android.cts.verifier.PassFailButtons; 32 import com.android.cts.verifier.R; 33 import com.android.cts.verifier.audio.peripheralprofile.PeripheralProfile; 34 import com.android.cts.verifier.audio.peripheralprofile.ProfileManager; 35 36 public abstract class USBAudioPeripheralActivity extends PassFailButtons.Activity { 37 private static final String TAG = "USBAudioPeripheralActivity"; 38 private static final boolean DEBUG = false; 39 40 // Host Mode Support 41 protected boolean mHasHostMode; 42 43 // Record if pass the test 44 protected boolean mHasPassedTest; 45 46 // Profile 47 protected ProfileManager mProfileManager = new ProfileManager(); 48 protected PeripheralProfile mSelectedProfile; 49 50 // Peripheral 51 private AudioManager mAudioManager; 52 private ConnectListener mConnectionListener; 53 54 protected boolean mIsPeripheralAttached; 55 protected AudioDeviceInfo mOutputDevInfo; 56 protected AudioDeviceInfo mInputDevInfo; 57 58 protected final boolean mIsMandatedRequired; 59 60 // Widgets 61 private TextView mProfileNameTx; 62 private TextView mProfileDescriptionTx; 63 64 private TextView mPeripheralNameTx; 65 66 private OnBtnClickListener mBtnClickListener = new OnBtnClickListener(); 67 68 // ReportLog Schema 69 private static final String KEY_CLAIMS_HOST = "claims_host_mode"; 70 71 // 72 // Common UI Handling 73 // connectUSBPeripheralUI()74 protected void connectUSBPeripheralUI() { 75 findViewById(R.id.uap_tests_yes_btn).setOnClickListener(mBtnClickListener); 76 findViewById(R.id.uap_tests_no_btn).setOnClickListener(mBtnClickListener); 77 findViewById(R.id.uap_test_info_btn).setOnClickListener(mBtnClickListener); 78 79 // Leave the default state in tact 80 // enableTestUI(false); 81 } 82 showUAPInfoDialog()83 private void showUAPInfoDialog() { 84 new AlertDialog.Builder(this) 85 .setTitle(R.string.uap_test_hostmode_info_caption) 86 .setMessage(R.string.uap_test_hostmode_info_text) 87 .setPositiveButton(R.string.audio_general_ok, null) 88 .show(); 89 } 90 91 private class OnBtnClickListener implements OnClickListener { 92 @Override onClick(View v)93 public void onClick(View v) { 94 int id = v.getId(); 95 if (id == R.id.uap_tests_yes_btn) { 96 mHasHostMode = true; 97 setUsbAudioStatus(mHasHostMode); 98 } else if (id == R.id.uap_tests_no_btn) { 99 mHasHostMode = false; 100 // If the device doesn't support USB host mode, no test need to run. 101 // In that case, the test should always be passed. 102 mHasPassedTest = true; 103 setUsbAudioStatus(mHasHostMode); 104 } else if (id == R.id.uap_test_info_btn) { 105 showUAPInfoDialog(); 106 } 107 } 108 } 109 110 @Override requiresReportLog()111 public boolean requiresReportLog() { 112 return true; 113 } 114 115 @Override getReportFileName()116 public String getReportFileName() { 117 return PassFailButtons.AUDIO_TESTS_REPORT_LOG_NAME; 118 } 119 recordUSBAudioStatus(boolean has)120 private void recordUSBAudioStatus(boolean has) { 121 getReportLog().addValue( 122 KEY_CLAIMS_HOST, 123 has, 124 ResultType.NEUTRAL, 125 ResultUnit.NONE); 126 } 127 setUsbAudioStatus(boolean has)128 protected void setUsbAudioStatus(boolean has) { 129 // ReportLog 130 recordUSBAudioStatus(has); 131 132 // UI & Pass/Fail status 133 getPassButton().setEnabled(!mHasHostMode || mHasPassedTest); 134 findViewById(R.id.uap_tests_yes_btn).setEnabled(mHasHostMode); 135 findViewById(R.id.uap_tests_no_btn).setEnabled(!mHasHostMode); 136 } 137 USBAudioPeripheralActivity(boolean mandatedRequired)138 public USBAudioPeripheralActivity(boolean mandatedRequired) { 139 // determine if to show "UNSUPPORTED" if the mandated peripheral is required. 140 mIsMandatedRequired = mandatedRequired; 141 142 mProfileManager.loadProfiles(); 143 } 144 145 @Override onCreate(Bundle savedInstanceState)146 protected void onCreate(Bundle savedInstanceState) { 147 super.onCreate(savedInstanceState); 148 149 mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE); 150 mConnectionListener = new ConnectListener(); 151 } 152 153 @Override onStart()154 public void onStart() { 155 super.onStart(); 156 mAudioManager.registerAudioDeviceCallback(mConnectionListener, null); 157 } 158 159 @Override onStop()160 public void onStop() { 161 mAudioManager.unregisterAudioDeviceCallback(mConnectionListener); 162 super.onStop(); 163 } 164 connectPeripheralStatusWidgets()165 protected void connectPeripheralStatusWidgets() { 166 mProfileNameTx = (TextView)findViewById(R.id.uap_profileNameTx); 167 mProfileDescriptionTx = 168 (TextView)findViewById(R.id.uap_profileDescriptionTx); 169 mPeripheralNameTx = (TextView)findViewById(R.id.uap_peripheralNameTx); 170 } 171 showProfileStatus()172 private void showProfileStatus() { 173 if (DEBUG) { 174 Log.d(TAG, "showProfileStatus()" + (mSelectedProfile != null)); 175 } 176 if (mSelectedProfile != null) { 177 mProfileNameTx.setText(mSelectedProfile.getName()); 178 mProfileDescriptionTx.setText(mSelectedProfile.getDescription()); 179 } else { 180 mProfileNameTx.setText(""); 181 mProfileDescriptionTx.setText(""); 182 } 183 } 184 showPeripheralStatus()185 private void showPeripheralStatus() { 186 if (mIsPeripheralAttached) { 187 String productName = ""; 188 if (mOutputDevInfo != null) { 189 productName = mOutputDevInfo.getProductName().toString(); 190 } else if (mInputDevInfo != null) { 191 productName = mInputDevInfo.getProductName().toString(); 192 } 193 String ctrlText; 194 if (mSelectedProfile == null && mIsMandatedRequired) { 195 ctrlText = productName + " - UNSUPPORTED"; 196 } else { 197 ctrlText = productName; 198 } 199 mPeripheralNameTx.setText(ctrlText); 200 } else { 201 mPeripheralNameTx.setText("Disconnected"); 202 } 203 } 204 scanPeripheralList(AudioDeviceInfo[] devices)205 private void scanPeripheralList(AudioDeviceInfo[] devices) { 206 // Can't just use the first record because then we will only get 207 // Source OR sink, not both even on devices that are both. 208 mOutputDevInfo = null; 209 mInputDevInfo = null; 210 211 // Any valid peripherals 212 for(AudioDeviceInfo devInfo : devices) { 213 if (devInfo.getType() == AudioDeviceInfo.TYPE_USB_DEVICE || 214 devInfo.getType() == AudioDeviceInfo.TYPE_USB_HEADSET) { 215 if (devInfo.isSink()) { 216 mOutputDevInfo = devInfo; 217 } 218 if (devInfo.isSource()) { 219 mInputDevInfo = devInfo; 220 } 221 } 222 } 223 mIsPeripheralAttached = mOutputDevInfo != null || mInputDevInfo != null; 224 if (DEBUG) { 225 Log.d(TAG, "mIsPeripheralAttached: " + mIsPeripheralAttached); 226 } 227 228 // any associated profiles? 229 if (mIsPeripheralAttached) { 230 if (mOutputDevInfo != null) { 231 mSelectedProfile = 232 mProfileManager.getProfile(mOutputDevInfo.getProductName().toString()); 233 } else if (mInputDevInfo != null) { 234 mSelectedProfile = 235 mProfileManager.getProfile(mInputDevInfo.getProductName().toString()); 236 } 237 } else { 238 mSelectedProfile = null; 239 } 240 } 241 242 private class ConnectListener extends AudioDeviceCallback { ConnectListener()243 /*package*/ ConnectListener() {} 244 245 // 246 // AudioDevicesManager.OnDeviceConnectionListener 247 // 248 @Override onAudioDevicesAdded(AudioDeviceInfo[] addedDevices)249 public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) { 250 // Log.i(TAG, "onAudioDevicesAdded() num:" + addedDevices.length); 251 252 scanPeripheralList(mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL)); 253 254 showProfileStatus(); 255 showPeripheralStatus(); 256 updateConnectStatus(); 257 } 258 259 @Override onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices)260 public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) { 261 // Log.i(TAG, "onAudioDevicesRemoved() num:" + removedDevices.length); 262 263 scanPeripheralList(mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL)); 264 265 showProfileStatus(); 266 showPeripheralStatus(); 267 updateConnectStatus(); 268 } 269 } 270 updateConnectStatus()271 abstract public void updateConnectStatus(); 272 } 273 274