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