Home | History | Annotate | Download | only in audioquality
      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
     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
    141     public void onResume() {
    142         super.onResume();
    143         mAdapter.notifyDataSetChanged(); // Update List UI
    144         setVolumeControlStream(AudioManager.STREAM_MUSIC);
    145         checkNotSilent();
    146     }
    147 
    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
    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
    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.
    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:
    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 
    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> {
    239         TwoColumnAdapter(Context context) {
    240             super(context, R.layout.aq_row);
    241         }
    242 
    243         @Override
    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 
    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 
    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
    283     public String getTestDetails() {
    284         return genReport();
    285     }
    286 
    287     @Override
    288     protected void onDestroy() {
    289         super.onDestroy();
    290         unregisterReceiver(mReceiver);
    291     }
    292 }
    293