1 /* 2 * Copyright (C) 2018 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.content.DialogInterface; 21 import android.content.pm.PackageManager; 22 import android.content.res.Resources; 23 import android.media.AudioDeviceInfo; 24 import android.media.AudioFormat; 25 import android.os.Bundle; 26 import android.util.Log; 27 import android.view.View; 28 import android.widget.CheckBox; 29 import android.widget.TextView; 30 31 import com.android.compatibility.common.util.ResultType; 32 import com.android.compatibility.common.util.ResultUnit; 33 import com.android.cts.verifier.audio.audiolib.AudioSystemFlags; 34 import com.android.cts.verifier.CtsVerifierReportLog; 35 import com.android.cts.verifier.PassFailButtons; 36 import com.android.cts.verifier.R; 37 38 import static com.android.cts.verifier.TestListActivity.sCurrentDisplayMode; 39 import static com.android.cts.verifier.TestListAdapter.setTestNameSuffix; 40 41 public class ProAudioActivity 42 extends PassFailButtons.Activity 43 implements View.OnClickListener { 44 private static final String TAG = ProAudioActivity.class.getSimpleName(); 45 private static final boolean DEBUG = false; 46 47 // Flags 48 private boolean mClaimsProAudio; 49 private boolean mClaimsLowLatencyAudio; // CDD ProAudio section C-1-1 50 private boolean mClaimsMIDI; // CDD ProAudio section C-1-4 51 private boolean mClaimsUSBHostMode; // CDD ProAudio section C-1-3 52 private boolean mClaimsUSBPeripheralMode; // CDD ProAudio section C-1-3 53 private boolean mClaimsHDMI; // CDD ProAudio section C-1-3 54 55 AudioDeviceInfo mHDMIDeviceInfo; 56 57 // Widgets 58 TextView mHDMISupportLbl; 59 60 CheckBox mClaimsHDMICheckBox; 61 62 TextView mTestStatusLbl; 63 64 // Borrowed from PassFailButtons.java 65 private static final int INFO_DIALOG_ID = 1337; 66 private static final String INFO_DIALOG_TITLE_ID = "infoDialogTitleId"; 67 private static final String INFO_DIALOG_MESSAGE_ID = "infoDialogMessageId"; 68 69 // ReportLog Schema 70 private static final String KEY_CLAIMS_PRO = "claims_pro_audio"; 71 private static final String KEY_CLAIMS_LOW_LATENCY = "claims_low_latency_audio"; 72 private static final String KEY_CLAIMS_MIDI = "claims_midi"; 73 private static final String KEY_CLAIMS_USB_HOST = "claims_usb_host"; 74 private static final String KEY_CLAIMS_USB_PERIPHERAL = "claims_usb_peripheral"; 75 private static final String KEY_CLAIMS_HDMI = "claims_hdmi"; 76 ProAudioActivity()77 public ProAudioActivity() { 78 super(); 79 } 80 81 // HDMI Stuff isHDMIValid()82 private boolean isHDMIValid() { 83 if (mHDMIDeviceInfo == null) { 84 return false; 85 } 86 87 // MUST support output in stereo and eight channels... 88 boolean has2Chans = false; 89 boolean has8Chans = false; 90 int[] channelCounts = mHDMIDeviceInfo.getChannelCounts(); 91 for (int count : channelCounts) { 92 if (count == 2) { 93 has2Chans = true; 94 } else if (count == 8) { 95 has8Chans = true; 96 } 97 } 98 if (!has2Chans || !has8Chans) { 99 return false; 100 } 101 102 // at 20-bit or 24-bit depth 103 boolean hasFloatEncoding = false; 104 int[] encodings = mHDMIDeviceInfo.getEncodings(); 105 for (int encoding : encodings) { 106 if (encoding == AudioFormat.ENCODING_PCM_FLOAT) { 107 hasFloatEncoding = true; 108 break; 109 } 110 } 111 if (!hasFloatEncoding) { 112 return false; 113 } 114 115 // and 192 kHz 116 boolean has192K = false; 117 int[] sampleRates = mHDMIDeviceInfo.getSampleRates(); 118 for (int rate : sampleRates) { 119 if (rate >= 192000) { 120 has192K = true; 121 } 122 } 123 if (!has192K) { 124 return false; 125 } 126 127 // without bit-depth loss or resampling (hmmmmm....). 128 129 return true; 130 } 131 handleDeviceConnection(AudioDeviceInfo devInfo)132 protected void handleDeviceConnection(AudioDeviceInfo devInfo) { 133 mHDMIDeviceInfo = null; 134 135 if (devInfo.isSink() && devInfo.getType() == AudioDeviceInfo.TYPE_HDMI) { 136 mHDMIDeviceInfo = devInfo; 137 } 138 139 if (mHDMIDeviceInfo != null) { 140 mClaimsHDMICheckBox.setChecked(true); 141 mHDMISupportLbl.setText(getResources().getString( 142 isHDMIValid() ? R.string.pass_button_text : R.string.fail_button_text)); 143 } 144 mHDMISupportLbl.setText(getResources().getString(R.string.audio_proaudio_NA)); 145 146 calculatePass(); 147 } 148 calculatePass()149 private boolean calculatePass() { 150 boolean usbOK = mClaimsUSBHostMode && mClaimsUSBPeripheralMode; 151 boolean hdmiOK = !mClaimsHDMI || isHDMIValid(); 152 153 boolean hasPassed = !mClaimsProAudio || 154 (mClaimsLowLatencyAudio && 155 mClaimsMIDI && 156 usbOK && 157 hdmiOK); 158 159 getPassButton().setEnabled(hasPassed); 160 return hasPassed; 161 } 162 displayTestResults()163 private void displayTestResults() { 164 boolean hasPassed = calculatePass(); 165 166 Resources strings = getResources(); 167 if (hasPassed) { 168 mTestStatusLbl.setText(strings.getString(R.string.audio_proaudio_pass)); 169 } else if (!mClaimsMIDI) { 170 mTestStatusLbl.setText(strings.getString(R.string.audio_proaudio_midinotreported)); 171 } else if (!mClaimsUSBHostMode) { 172 mTestStatusLbl.setText(strings.getString(R.string.audio_proaudio_usbhostnotreported)); 173 } else if (!mClaimsUSBPeripheralMode) { 174 mTestStatusLbl.setText(strings.getString( 175 R.string.audio_proaudio_usbperipheralnotreported)); 176 } else if (mClaimsHDMI && isHDMIValid()) { 177 mTestStatusLbl.setText(strings.getString(R.string.audio_proaudio_hdminotvalid)); 178 } 179 } 180 181 @Override onCreate(Bundle savedInstanceState)182 protected void onCreate(Bundle savedInstanceState) { 183 setContentView(R.layout.pro_audio); 184 185 super.onCreate(savedInstanceState); 186 187 setPassFailButtonClickListeners(); 188 setInfoResources(R.string.proaudio_test, R.string.proaudio_info, -1); 189 190 mClaimsProAudio = AudioSystemFlags.claimsProAudio(this); 191 ((TextView)findViewById(R.id.proAudioHasProAudioLbl)).setText("" + mClaimsProAudio); 192 193 if (!mClaimsProAudio) { 194 Bundle args = new Bundle(); 195 args.putInt(INFO_DIALOG_TITLE_ID, R.string.pro_audio_latency_test); 196 args.putInt(INFO_DIALOG_MESSAGE_ID, R.string.audio_proaudio_nopa_message); 197 showDialog(INFO_DIALOG_ID, args); 198 } 199 200 mClaimsLowLatencyAudio = AudioSystemFlags.claimsLowLatencyAudio(this); 201 ((TextView)findViewById(R.id.proAudioHasLLALbl)).setText("" + mClaimsLowLatencyAudio); 202 203 mClaimsMIDI = AudioSystemFlags.claimsMIDI(this); 204 ((TextView)findViewById(R.id.proAudioHasMIDILbl)).setText("" + mClaimsMIDI); 205 206 mClaimsUSBHostMode = AudioSystemFlags.claimsUSBHostMode(this); 207 ((TextView)findViewById(R.id.proAudioMidiHasUSBHostLbl)).setText("" + mClaimsUSBHostMode); 208 209 mClaimsUSBPeripheralMode = AudioSystemFlags.claimsUSBPeripheralMode(this); 210 ((TextView)findViewById( 211 R.id.proAudioMidiHasUSBPeripheralLbl)).setText("" + mClaimsUSBPeripheralMode); 212 213 // HDMI 214 mHDMISupportLbl = (TextView)findViewById(R.id.proAudioHDMISupportLbl); 215 mClaimsHDMICheckBox = (CheckBox)findViewById(R.id.proAudioHasHDMICheckBox); 216 mClaimsHDMICheckBox.setOnClickListener(this); 217 218 mTestStatusLbl = (TextView)findViewById(R.id.proAudioTestStatusLbl); 219 220 calculatePass(); 221 } 222 223 /** 224 * Store test results in log 225 */ 226 @Override getTestId()227 public String getTestId() { 228 return setTestNameSuffix(sCurrentDisplayMode, getClass().getName()); 229 } 230 231 // 232 // PassFailButtons Overrides 233 // 234 @Override recordTestResults()235 public void recordTestResults() { 236 237 CtsVerifierReportLog reportLog = getReportLog(); 238 reportLog.addValue( 239 KEY_CLAIMS_PRO, 240 mClaimsProAudio, 241 ResultType.NEUTRAL, 242 ResultUnit.NONE); 243 244 reportLog.addValue( 245 KEY_CLAIMS_LOW_LATENCY, 246 mClaimsLowLatencyAudio, 247 ResultType.NEUTRAL, 248 ResultUnit.NONE); 249 250 reportLog.addValue( 251 KEY_CLAIMS_MIDI, 252 mClaimsMIDI, 253 ResultType.NEUTRAL, 254 ResultUnit.NONE); 255 256 reportLog.addValue( 257 KEY_CLAIMS_USB_HOST, 258 mClaimsUSBHostMode, 259 ResultType.NEUTRAL, 260 ResultUnit.NONE); 261 262 reportLog.addValue( 263 KEY_CLAIMS_USB_PERIPHERAL, 264 mClaimsUSBPeripheralMode, 265 ResultType.NEUTRAL, 266 ResultUnit.NONE); 267 268 reportLog.addValue( 269 KEY_CLAIMS_HDMI, 270 mClaimsHDMI, 271 ResultType.NEUTRAL, 272 ResultUnit.NONE); 273 274 reportLog.submit(); 275 } 276 277 @Override onClick(View view)278 public void onClick(View view) { 279 switch (view.getId()) { 280 case R.id.proAudioHasHDMICheckBox: 281 if (mClaimsHDMICheckBox.isChecked()) { 282 AlertDialog.Builder builder = 283 new AlertDialog.Builder(this, android.R.style.Theme_Material_Dialog_Alert); 284 builder.setTitle(getResources().getString(R.string.proaudio_hdmi_infotitle)); 285 builder.setMessage(getResources().getString(R.string.proaudio_hdmi_message)); 286 builder.setPositiveButton(android.R.string.yes, 287 new DialogInterface.OnClickListener() { 288 public void onClick(DialogInterface dialog, int which) {} 289 }); 290 builder.setIcon(android.R.drawable.ic_dialog_alert); 291 builder.show(); 292 293 mClaimsHDMI = true; 294 mHDMISupportLbl.setText(getResources().getString(R.string.audio_proaudio_pending)); 295 } else { 296 mClaimsHDMI = false; 297 mHDMISupportLbl.setText(getResources().getString(R.string.audio_proaudio_NA)); 298 } 299 calculatePass(); 300 break; 301 } 302 } 303 } 304