1 /* 2 * Copyright (C) 2010 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.audioquality; 18 19 import com.android.cts.verifier.PassFailButtons; 20 import com.android.cts.verifier.R; 21 22 import android.content.BroadcastReceiver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.graphics.Color; 27 import android.graphics.Typeface; 28 import android.media.AudioFormat; 29 import android.media.AudioManager; 30 import android.os.Bundle; 31 import android.util.Log; 32 import android.view.LayoutInflater; 33 import android.view.View; 34 import android.view.ViewGroup; 35 import android.widget.AdapterView; 36 import android.widget.ArrayAdapter; 37 import android.widget.Button; 38 import android.widget.ListView; 39 import android.widget.ProgressBar; 40 import android.widget.TextView; 41 import android.widget.AdapterView.OnItemClickListener; 42 43 import java.util.ArrayList; 44 45 /** 46 * Main UI for the Android Audio Quality Verifier. 47 */ 48 public class AudioQualityVerifierActivity extends PassFailButtons.Activity 49 implements View.OnClickListener, OnItemClickListener { 50 public static final String TAG = "AudioQualityVerifier"; 51 52 public static final int SAMPLE_RATE = 16000; 53 public static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT; 54 public static final int BYTES_PER_SAMPLE = 2; 55 public static final int PLAYBACK_STREAM = AudioManager.STREAM_MUSIC; 56 57 // Intent Extra definitions, which must match those in 58 // com.google.android.voicesearch.speechservice.RecognitionController 59 public static final String EXTRA_RAW_AUDIO = 60 "android.speech.extras.RAW_AUDIO"; 61 62 // Communication with ExperimentService 63 public static final String ACTION_EXP_STARTED = 64 "com.android.cts.verifier.audioquality.EXP_STARTED"; 65 public static final String ACTION_EXP_FINISHED = 66 "com.android.cts.verifier.audioquality.EXP_FINISHED"; 67 public static final String EXTRA_ABORTED = 68 "com.android.cts.verifier.audioquality.ABORTED"; 69 public static final String EXTRA_EXP_ID = 70 "com.android.cts.verifier.audioquality.EXP_ID"; 71 public static final String EXTRA_RUN_ALL = 72 "com.android.cts.verifier.audioquality.RUN_ALL"; 73 74 // Communication with ViewResultsActivity 75 public static final String EXTRA_RESULTS = 76 "com.android.cts.verifier.audioquality.RESULTS"; 77 78 private Button mCalibrateButton; 79 private Button mRunAllButton; 80 private Button mStopButton; 81 private Button mViewResultsButton; 82 private Button mClearButton; 83 84 private ListView mList; 85 private TwoColumnAdapter mAdapter; 86 87 private ProgressBar mProgress; 88 89 private ArrayList<Experiment> mExperiments; 90 91 private boolean mRunningExperiment; 92 93 private BroadcastReceiver mReceiver; 94 95 @Override onCreate(Bundle savedInstanceState)96 public void onCreate(Bundle savedInstanceState) { 97 super.onCreate(savedInstanceState); 98 setContentView(R.layout.aq_verifier_activity); 99 setPassFailButtonClickListeners(); 100 setInfoResources(R.string.aq_verifier, R.string.aq_verifier_info, -1); 101 102 mCalibrateButton = (Button) findViewById(R.id.calibrateButton); 103 mRunAllButton = (Button) findViewById(R.id.runAllButton); 104 mStopButton = (Button) findViewById(R.id.stopButton); 105 mViewResultsButton = (Button) findViewById(R.id.viewResultsButton); 106 mClearButton = (Button) findViewById(R.id.clearButton); 107 108 mCalibrateButton.setOnClickListener(this); 109 mRunAllButton.setOnClickListener(this); 110 mStopButton.setOnClickListener(this); 111 mViewResultsButton.setOnClickListener(this); 112 mClearButton.setOnClickListener(this); 113 114 mStopButton.setEnabled(false); 115 116 mProgress = (ProgressBar) findViewById(R.id.progress); 117 118 mList = (ListView) findViewById(R.id.list); 119 mAdapter = new TwoColumnAdapter(this); 120 121 mExperiments = VerifierExperiments.getExperiments(this); 122 123 mReceiver = new BroadcastReceiver() { 124 @Override 125 public void onReceive(Context context, Intent intent) { 126 experimentReplied(intent); 127 } 128 }; 129 IntentFilter filter = new IntentFilter(); 130 filter.addAction(ACTION_EXP_STARTED); 131 filter.addAction(ACTION_EXP_FINISHED); 132 registerReceiver(mReceiver, filter); 133 134 fillAdapter(); 135 mList.setAdapter(mAdapter); 136 mList.setOnItemClickListener(this); 137 checkNotSilent(); 138 } 139 140 @Override onResume()141 public void onResume() { 142 super.onResume(); 143 mAdapter.notifyDataSetChanged(); // Update List UI 144 setVolumeControlStream(AudioManager.STREAM_MUSIC); 145 checkNotSilent(); 146 } 147 checkNotSilent()148 private void checkNotSilent() { 149 AudioManager mgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 150 mgr.setStreamMute(PLAYBACK_STREAM, false); 151 int volume = mgr.getStreamVolume(PLAYBACK_STREAM); 152 int max = mgr.getStreamMaxVolume(PLAYBACK_STREAM); 153 Log.i(TAG, "Volume " + volume + ", max " + max); 154 if (volume <= max / 10) { 155 // Volume level is silent or very quiet; increase to two-thirds 156 mgr.setStreamVolume(PLAYBACK_STREAM, (max * 2) / 3, AudioManager.FLAG_SHOW_UI); 157 } 158 } 159 160 // Called when an experiment has completed experimentReplied(Intent intent)161 private void experimentReplied(Intent intent) { 162 String action = intent.getAction(); 163 if (ACTION_EXP_STARTED.equals(action)) { 164 mStopButton.setEnabled(true); 165 mRunAllButton.setEnabled(false); 166 } else if (ACTION_EXP_FINISHED.equals(action)) { 167 boolean mRunAll = intent.getBooleanExtra(EXTRA_RUN_ALL, false); 168 boolean aborted = intent.getBooleanExtra(EXTRA_ABORTED, true); 169 int expID = intent.getIntExtra(EXTRA_EXP_ID, -1); 170 if (mRunAll && !aborted) { 171 while (expID < mExperiments.size() - 1) { 172 if (runExperiment(++expID, true)) { 173 // OK, experiment is running 174 mAdapter.notifyDataSetChanged(); 175 return; 176 } 177 // Otherwise, loop back and try the next experiment 178 } 179 } 180 mStopButton.setEnabled(false); 181 mRunAllButton.setEnabled(true); 182 mRunningExperiment = false; 183 mProgress.setVisibility(ProgressBar.INVISIBLE); 184 } 185 mAdapter.notifyDataSetChanged(); 186 } 187 188 // Implements AdapterView.OnItemClickListener onItemClick(AdapterView<?> parent, View view, int position, long id)189 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 190 if (mRunningExperiment) return; 191 runExperiment(position, false); 192 } 193 194 // Begin an experiment. Returns false if the experiment is not enabled. runExperiment(int which, boolean all)195 private boolean runExperiment(int which, boolean all) { 196 Experiment exp = mExperiments.get(which); 197 if (!exp.isEnabled()) return false; 198 Intent intent = new Intent(this, ExperimentService.class); 199 intent.putExtra(EXTRA_EXP_ID, which); 200 intent.putExtra(EXTRA_RUN_ALL, all); 201 startService(intent); 202 mRunningExperiment = true; 203 mAdapter.notifyDataSetChanged(); 204 mProgress.setVisibility(ProgressBar.VISIBLE); 205 return true; 206 } 207 208 // Implements View.OnClickListener: onClick(View v)209 public void onClick(View v) { 210 if (v == mCalibrateButton) { 211 Intent intent = new Intent(this, CalibrateVolumeActivity.class); 212 startActivity(intent); 213 } else if (v == mRunAllButton) { 214 if (mRunningExperiment) return; 215 int expID = -1; 216 while (expID < mExperiments.size() - 1) { 217 if (runExperiment(++expID, true)) break; 218 } 219 } else if (v == mStopButton) { 220 Intent intent = new Intent(this, ExperimentService.class); 221 stopService(intent); 222 } else if (v == mViewResultsButton) { 223 Intent intent = new Intent(this, ViewResultsActivity.class); 224 intent.putExtra(EXTRA_RESULTS, genReport()); 225 startActivity(intent); 226 } else if (v == mClearButton) { 227 clear(); 228 } 229 } 230 fillAdapter()231 private void fillAdapter() { 232 mAdapter.clear(); 233 for (Experiment exp : mExperiments) { 234 mAdapter.add(exp.getName()); 235 } 236 } 237 238 class TwoColumnAdapter extends ArrayAdapter<String> { TwoColumnAdapter(Context context)239 TwoColumnAdapter(Context context) { 240 super(context, R.layout.aq_row); 241 } 242 243 @Override getView(int position, View convertView, ViewGroup parent)244 public View getView(int position, View convertView, ViewGroup parent) { 245 LayoutInflater inflater = getLayoutInflater(); 246 View row = inflater.inflate(R.layout.aq_row, parent, false); 247 TextView nameField = (TextView) row.findViewById(R.id.testName); 248 TextView scoreField = (TextView) row.findViewById(R.id.testScore); 249 Experiment exp = mExperiments.get(position); 250 nameField.setText(exp.getName()); 251 scoreField.setText(exp.getScore()); 252 if (exp.isRunning()) { 253 Typeface tf = nameField.getTypeface(); 254 nameField.setTypeface(tf, 1); 255 } 256 if (!exp.isEnabled()) { 257 nameField.setTextColor(Color.GRAY); 258 } 259 return row; 260 } 261 } 262 genReport()263 private String genReport() { 264 StringBuilder sb = new StringBuilder(); 265 for (Experiment exp : mExperiments) { 266 exp.getReport(sb); 267 } 268 return sb.toString(); 269 } 270 clear()271 private void clear() { 272 if (mRunningExperiment) { 273 Intent intent = new Intent(this, ExperimentService.class); 274 stopService(intent); 275 } 276 for (Experiment exp : mExperiments) { 277 exp.reset(); 278 } 279 mAdapter.notifyDataSetChanged(); 280 } 281 282 @Override getTestDetails()283 public String getTestDetails() { 284 return genReport(); 285 } 286 287 @Override onDestroy()288 protected void onDestroy() { 289 super.onDestroy(); 290 unregisterReceiver(mReceiver); 291 } 292 } 293