Home | History | Annotate | Download | only in loopback
      1 /*
      2  * Copyright (C) 2015 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 org.drrickorang.loopback;
     18 
     19 import android.app.Activity;
     20 import android.content.Intent;
     21 import android.os.Bundle;
     22 import android.util.Log;
     23 import android.view.Gravity;
     24 import android.view.View;
     25 import android.view.ViewGroup;
     26 import android.widget.AdapterView;
     27 import android.widget.AdapterView.OnItemSelectedListener;
     28 import android.widget.ArrayAdapter;
     29 import android.widget.CompoundButton;
     30 import android.widget.PopupWindow;
     31 import android.widget.Spinner;
     32 import android.widget.TextView;
     33 import android.widget.ToggleButton;
     34 
     35 
     36 /**
     37  * This activity displays all settings that can be adjusted by the user.
     38  */
     39 
     40 public class SettingsActivity extends Activity implements OnItemSelectedListener,
     41         ToggleButton.OnCheckedChangeListener {
     42 
     43     private static final String TAG = "SettingsActivity";
     44 
     45     private Spinner      mSpinnerMicSource;
     46     private Spinner      mSpinnerPerformanceMode;
     47     private Spinner      mSpinnerSamplingRate;
     48     private Spinner      mSpinnerAudioThreadType;
     49     private TextView     mTextSettingsInfo;
     50     private Spinner      mSpinnerChannelIndex;
     51     private SettingsPicker mPlayerBufferUI;
     52     private SettingsPicker mRecorderBufferUI;
     53     private SettingsPicker mBufferTestDurationUI;
     54     private SettingsPicker mWavePlotDurationUI;
     55     private SettingsPicker mLoadThreadUI;
     56     private SettingsPicker mNumCapturesUI;
     57     private SettingsPicker mIgnoreFirstFramesUI;
     58     private ToggleButton   mSystraceToggleButton;
     59     private ToggleButton   mBugreportToggleButton;
     60     private ToggleButton   mWavCaptureToggleButton;
     61     private ToggleButton   mSoundLevelCalibrationToggleButton;
     62 
     63     ArrayAdapter<CharSequence> mAdapterSamplingRate;
     64 
     65 
     66     @Override
     67     public void onCreate(Bundle savedInstanceState) {
     68         super.onCreate(savedInstanceState);
     69         // Set the layout for this activity. You can find it
     70         View view = getLayoutInflater().inflate(R.layout.settings_activity, null);
     71         setContentView(view);
     72         mTextSettingsInfo = (TextView) findViewById(R.id.textSettingsInfo);
     73 
     74         int micSource = getApp().getMicSource();
     75         mSpinnerMicSource = (Spinner) findViewById(R.id.spinnerMicSource);
     76         ArrayAdapter<CharSequence> adapterMicSource = ArrayAdapter.createFromResource(this,
     77                 R.array.mic_source_array, android.R.layout.simple_spinner_item);
     78         // Specify the layout to use when the list of choices appears
     79         adapterMicSource.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
     80         // Apply the adapter to the spinner
     81         mSpinnerMicSource.setAdapter(adapterMicSource);
     82         //set current value
     83         mSpinnerMicSource.setSelection(micSource, false);
     84         mSpinnerMicSource.setOnItemSelectedListener(this);
     85 
     86         int performanceMode = getApp().getPerformanceMode();
     87         mSpinnerPerformanceMode = (Spinner) findViewById(R.id.spinnerPerformanceMode);
     88         ArrayAdapter<CharSequence> adapterPerformanceMode = ArrayAdapter.createFromResource(this,
     89                 R.array.performance_mode_array, android.R.layout.simple_spinner_item);
     90         // Specify the layout to use when the list of choices appears
     91         adapterPerformanceMode.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
     92         // Apply the adapter to the spinner
     93         mSpinnerPerformanceMode.setAdapter(adapterPerformanceMode);
     94         //set current value
     95         mSpinnerPerformanceMode.setSelection(performanceMode + 1, false);
     96         mSpinnerPerformanceMode.setOnItemSelectedListener(this);
     97 
     98         int samplingRate = getApp().getSamplingRate();
     99         //init spinner, etc
    100         mSpinnerSamplingRate = (Spinner) findViewById(R.id.spinnerSamplingRate);
    101         mAdapterSamplingRate = ArrayAdapter.createFromResource(this,
    102                 R.array.samplingRate_array, android.R.layout.simple_spinner_item);
    103         // Specify the layout to use when the list of choices appears
    104         mAdapterSamplingRate.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    105         // Apply the adapter to the spinner
    106         mSpinnerSamplingRate.setAdapter(mAdapterSamplingRate);
    107         //set current value
    108         String currentValue = String.valueOf(samplingRate);
    109         int nPosition = mAdapterSamplingRate.getPosition(currentValue);
    110         mSpinnerSamplingRate.setSelection(nPosition, false);
    111         mSpinnerSamplingRate.setOnItemSelectedListener(this);
    112 
    113         //spinner native
    114         int audioThreadType = getApp().getAudioThreadType();
    115         mSpinnerAudioThreadType = (Spinner) findViewById(R.id.spinnerAudioThreadType);
    116         ArrayAdapter<CharSequence> adapter2 = ArrayAdapter.createFromResource(this,
    117                 R.array.audioThreadType_array, android.R.layout.simple_spinner_item);
    118         // Specify the layout to use when the list of choices appears
    119         adapter2.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    120         // Apply the adapter to the spinner
    121         mSpinnerAudioThreadType.setAdapter(adapter2);
    122         //set current value
    123         mSpinnerAudioThreadType.setSelection(audioThreadType, false);
    124         if (!getApp().isSafeToUseSles())
    125             mSpinnerAudioThreadType.setEnabled(false);
    126         mSpinnerAudioThreadType.setOnItemSelectedListener(this);
    127 
    128         mSpinnerChannelIndex = (Spinner) findViewById(R.id.spinnerChannelIndex);
    129         ArrayAdapter<CharSequence> adapter3 = ArrayAdapter.createFromResource(this,
    130                 R.array.channelIndex_array, android.R.layout.simple_spinner_item);
    131         // Specify the layout to use when the list of choices appears
    132         adapter3.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    133         // Apply the adapter to the spinner
    134         mSpinnerChannelIndex.setAdapter(adapter3);
    135         mSpinnerChannelIndex.setOnItemSelectedListener(this);
    136 
    137         // Settings Picker for Buffer Test Duration
    138         mBufferTestDurationUI = (SettingsPicker) findViewById(R.id.bufferTestDurationSetting);
    139         mBufferTestDurationUI.setMinMaxDefault(Constant.BUFFER_TEST_DURATION_SECONDS_MIN,
    140                 Constant.BUFFER_TEST_DURATION_SECONDS_MAX, getApp().getBufferTestDuration());
    141         mBufferTestDurationUI.setTitle(getResources().getString(R.string.labelBufferTestDuration,
    142                 Constant.BUFFER_TEST_DURATION_SECONDS_MAX));
    143         mBufferTestDurationUI.setSettingsChangeListener(new SettingsPicker.SettingChangeListener() {
    144             @Override
    145             public void settingChanged(int seconds) {
    146                 log("buffer test new duration: " + seconds);
    147                 getApp().setBufferTestDuration(seconds);
    148                 setSettingsHaveChanged();
    149             }
    150         });
    151 
    152         // Settings Picker for Wave Plot Duration
    153         mWavePlotDurationUI = (SettingsPicker) findViewById(R.id.wavePlotDurationSetting);
    154         mWavePlotDurationUI.setMinMaxDefault(Constant.BUFFER_TEST_WAVE_PLOT_DURATION_SECONDS_MIN,
    155                 Constant.BUFFER_TEST_WAVE_PLOT_DURATION_SECONDS_MAX,
    156                 getApp().getBufferTestWavePlotDuration());
    157         mWavePlotDurationUI.setTitle(getResources().getString(
    158                 R.string.labelBufferTestWavePlotDuration,
    159                 Constant.BUFFER_TEST_WAVE_PLOT_DURATION_SECONDS_MAX));
    160         mWavePlotDurationUI.setSettingsChangeListener(new SettingsPicker.SettingChangeListener() {
    161             @Override
    162             public void settingChanged(int value) {
    163                 log("buffer test's wave plot new duration:" + value);
    164                 getApp().setBufferTestWavePlotDuration(value);
    165                 setSettingsHaveChanged();
    166             }
    167         });
    168 
    169         // Settings Picker for Player Buffer Period
    170         mPlayerBufferUI = (SettingsPicker) findViewById(R.id.playerBufferSetting);
    171         mPlayerBufferUI.setMinMaxDefault(Constant.PLAYER_BUFFER_FRAMES_MIN,
    172                 Constant.PLAYER_BUFFER_FRAMES_MAX,
    173                 getApp().getPlayerBufferSizeInBytes() / Constant.BYTES_PER_FRAME);
    174         mPlayerBufferUI.setTitle(getResources().getString(
    175                 R.string.labelPlayerBuffer, Constant.PLAYER_BUFFER_FRAMES_MAX));
    176         mPlayerBufferUI.setSettingsChangeListener(new SettingsPicker.SettingChangeListener() {
    177             @Override
    178             public void settingChanged(int value) {
    179                 log("player buffer new size " + value);
    180                 getApp().setPlayerBufferSizeInBytes(value * Constant.BYTES_PER_FRAME);
    181                 int audioThreadType = mSpinnerAudioThreadType.getSelectedItemPosition();
    182                 // in native mode, recorder buffer size = player buffer size
    183                 if (audioThreadType == Constant.AUDIO_THREAD_TYPE_NATIVE) {
    184                     getApp().setRecorderBufferSizeInBytes(value * Constant.BYTES_PER_FRAME);
    185                     mRecorderBufferUI.setValue(value);
    186                 }
    187                 setSettingsHaveChanged();
    188             }
    189         });
    190 
    191         // Settings Picker for Recorder Buffer Period
    192         mRecorderBufferUI = (SettingsPicker) findViewById(R.id.recorderBufferSetting);
    193         mRecorderBufferUI.setMinMaxDefault(Constant.RECORDER_BUFFER_FRAMES_MIN,
    194                 Constant.RECORDER_BUFFER_FRAMES_MAX,
    195                 getApp().getRecorderBufferSizeInBytes() / Constant.BYTES_PER_FRAME);
    196         mRecorderBufferUI.setTitle(getResources().getString(R.string.labelRecorderBuffer,
    197                 Constant.RECORDER_BUFFER_FRAMES_MAX));
    198         mRecorderBufferUI.setSettingsChangeListener(new SettingsPicker.SettingChangeListener() {
    199             @Override
    200             public void settingChanged(int value) {
    201                 log("recorder buffer new size:" + value);
    202                 getApp().setRecorderBufferSizeInBytes(value * Constant.BYTES_PER_FRAME);
    203                 setSettingsHaveChanged();
    204             }
    205         });
    206 
    207         // Settings Picker for Number of Load Threads
    208         mLoadThreadUI = (SettingsPicker) findViewById(R.id.numLoadThreadsSetting);
    209         mLoadThreadUI.setMinMaxDefault(Constant.MIN_NUM_LOAD_THREADS, Constant.MAX_NUM_LOAD_THREADS,
    210                 getApp().getNumberOfLoadThreads());
    211         mLoadThreadUI.setTitle(getResources().getString(R.string.loadThreadsLabel));
    212         mLoadThreadUI.setSettingsChangeListener(new SettingsPicker.SettingChangeListener() {
    213             @Override
    214             public void settingChanged(int value) {
    215                 log("new num load threads:" + value);
    216                 getApp().setNumberOfLoadThreads(value);
    217                 setSettingsHaveChanged();
    218             }
    219         });
    220 
    221         // Settings Picker for Number of Captures
    222         mNumCapturesUI = (SettingsPicker) findViewById(R.id.numCapturesSettingPicker);
    223         mNumCapturesUI.setMinMaxDefault(Constant.MIN_NUM_CAPTURES, Constant.MAX_NUM_CAPTURES,
    224                 getApp().getNumStateCaptures());
    225         mNumCapturesUI.setTitle(getResources().getString(R.string.numCapturesSetting));
    226         mNumCapturesUI.setSettingsChangeListener(new SettingsPicker.SettingChangeListener() {
    227             @Override
    228             public void settingChanged(int value) {
    229                 log("new num captures:" + value);
    230                 getApp().setNumberOfCaptures(value);
    231                 setSettingsHaveChanged();
    232             }
    233         });
    234 
    235         mWavCaptureToggleButton = (ToggleButton) findViewById(R.id.wavSnippetsEnabledToggle);
    236         mWavCaptureToggleButton.setChecked(getApp().isCaptureWavSnippetsEnabled());
    237         mWavCaptureToggleButton.setOnCheckedChangeListener(this);
    238 
    239         mBugreportToggleButton = (ToggleButton) findViewById(R.id.BugreportEnabledToggle);
    240         mBugreportToggleButton.setChecked(getApp().isCaptureBugreportEnabled());
    241         mBugreportToggleButton.setOnCheckedChangeListener(this);
    242 
    243         mSystraceToggleButton = (ToggleButton) findViewById(R.id.SystraceEnabledToggle);
    244         mSystraceToggleButton.setChecked(getApp().isCaptureSysTraceEnabled());
    245         mSystraceToggleButton.setOnCheckedChangeListener(this);
    246 
    247         mSoundLevelCalibrationToggleButton = (ToggleButton)
    248                 findViewById(R.id.soundLevelCalibrationEnabledToggle);
    249         mSoundLevelCalibrationToggleButton.setChecked(getApp().isSoundLevelCalibrationEnabled());
    250         mSoundLevelCalibrationToggleButton.setOnCheckedChangeListener(this);
    251 
    252         // Settings Picker for number of frames to ignore at the beginning
    253         mIgnoreFirstFramesUI = (SettingsPicker) findViewById(R.id.ignoreFirstFramesSettingPicker);
    254         mIgnoreFirstFramesUI.setMinMaxDefault(Constant.MIN_IGNORE_FIRST_FRAMES,
    255                 Constant.MAX_IGNORE_FIRST_FRAMES, getApp().getIgnoreFirstFrames());
    256         mIgnoreFirstFramesUI.setTitle(getResources().getString(R.string.labelIgnoreFirstFrames,
    257                 Constant.MAX_IGNORE_FIRST_FRAMES));
    258         mIgnoreFirstFramesUI.setSettingsChangeListener(new SettingsPicker.SettingChangeListener() {
    259             @Override
    260             public void settingChanged(int frames) {
    261                 log("new number of first frames to ignore: " + frames);
    262                 getApp().setIgnoreFirstFrames(frames);
    263                 setSettingsHaveChanged();
    264             }
    265         });
    266 
    267         refresh();
    268     }
    269 
    270 
    271     public void onDestroy() {
    272         super.onDestroy();
    273     }
    274 
    275 
    276     @Override
    277     public void onBackPressed() {
    278         log("on back pressed");
    279         setSettingsHaveChanged();
    280         finish();
    281     }
    282 
    283 
    284     private void refresh() {
    285         mBufferTestDurationUI.setValue(getApp().getBufferTestDuration());
    286         mWavePlotDurationUI.setValue(getApp().getBufferTestWavePlotDuration());
    287 
    288         mPlayerBufferUI.setValue(getApp().getPlayerBufferSizeInBytes() / Constant.BYTES_PER_FRAME);
    289         mRecorderBufferUI.setValue(
    290                 getApp().getRecorderBufferSizeInBytes() / Constant.BYTES_PER_FRAME);
    291 
    292         mRecorderBufferUI.setEnabled(
    293                 getApp().getAudioThreadType() == Constant.AUDIO_THREAD_TYPE_JAVA);
    294 
    295         int samplingRate = getApp().getSamplingRate();
    296         String currentValue = String.valueOf(samplingRate);
    297         int nPosition = mAdapterSamplingRate.getPosition(currentValue);
    298         mSpinnerSamplingRate.setSelection(nPosition);
    299 
    300 
    301         if (getApp().getAudioThreadType() == Constant.AUDIO_THREAD_TYPE_JAVA) {
    302             mSpinnerChannelIndex.setSelection(getApp().getChannelIndex() + 1, false);
    303             mSpinnerChannelIndex.setEnabled(true);
    304         } else {
    305             mSpinnerChannelIndex.setSelection(0, false);
    306             mSpinnerChannelIndex.setEnabled(false);
    307         }
    308 
    309         mNumCapturesUI.setEnabled(getApp().isCaptureEnabled() ||
    310                 getApp().isCaptureWavSnippetsEnabled());
    311 
    312         String info = getApp().getSystemInfo();
    313         mTextSettingsInfo.setText("SETTINGS - " + info);
    314     }
    315 
    316 
    317     public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
    318         // An item was selected. You can retrieve the selected item using
    319         // parent.getItemAtPosition(pos)
    320         log("item selected!");
    321 
    322         switch (parent.getId()) {
    323         case R.id.spinnerSamplingRate:
    324             String stringValue = mSpinnerSamplingRate.getSelectedItem().toString();
    325             int samplingRate = Integer.parseInt(stringValue);
    326             getApp().setSamplingRate(samplingRate);
    327             setSettingsHaveChanged();
    328             log("Sampling Rate: " + stringValue);
    329             refresh();
    330             break;
    331         case R.id.spinnerAudioThreadType:
    332             int audioThreadType = mSpinnerAudioThreadType.getSelectedItemPosition();
    333             getApp().setAudioThreadType(audioThreadType);
    334             getApp().computeDefaults();
    335             setSettingsHaveChanged();
    336             log("AudioThreadType:" + audioThreadType);
    337             refresh();
    338             break;
    339         case R.id.spinnerChannelIndex:
    340             int channelIndex = mSpinnerChannelIndex.getSelectedItemPosition() - 1;
    341             getApp().setChannelIndex(channelIndex);
    342             setSettingsHaveChanged();
    343             log("channelIndex:" + channelIndex);
    344             refresh();
    345             break;
    346         case R.id.spinnerMicSource:
    347             int micSource = mSpinnerMicSource.getSelectedItemPosition();
    348             getApp().setMicSource(micSource);
    349             setSettingsHaveChanged();
    350             log("mic Source:" + micSource);
    351             refresh();
    352             break;
    353         case R.id.spinnerPerformanceMode:
    354             int performanceMode = mSpinnerPerformanceMode.getSelectedItemPosition() - 1;
    355             getApp().setPerformanceMode(performanceMode);
    356             setSettingsHaveChanged();
    357             log("performanceMode:" + performanceMode);
    358             refresh();
    359             break;
    360         }
    361     }
    362 
    363     @Override
    364     public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    365         if (buttonView.getId() == mWavCaptureToggleButton.getId()){
    366             getApp().setCaptureWavsEnabled(isChecked);
    367         } else if (buttonView.getId() == mSystraceToggleButton.getId()) {
    368             getApp().setCaptureSysTraceEnabled(isChecked);
    369         } else if (buttonView.getId() == mBugreportToggleButton.getId()) {
    370             getApp().setCaptureBugreportEnabled(isChecked);
    371         } else if (buttonView.getId() == mSoundLevelCalibrationToggleButton.getId()) {
    372             getApp().setSoundLevelCalibrationEnabled(isChecked);
    373         }
    374         mNumCapturesUI.setEnabled(getApp().isCaptureEnabled() ||
    375                 getApp().isCaptureWavSnippetsEnabled());
    376     }
    377 
    378     private void setSettingsHaveChanged() {
    379         Intent intent = new Intent();
    380         setResult(RESULT_OK, intent);
    381     }
    382 
    383 
    384     public void onNothingSelected(AdapterView<?> parent) {
    385         // Another interface callback
    386     }
    387 
    388     public void onButtonHelp(View view) {
    389         // Create a PopUpWindow with scrollable TextView
    390         View puLayout = this.getLayoutInflater().inflate(R.layout.report_window, null);
    391         PopupWindow popUp = new PopupWindow(puLayout, ViewGroup.LayoutParams.MATCH_PARENT,
    392                 ViewGroup.LayoutParams.MATCH_PARENT, true);
    393 
    394         TextView helpText =
    395                 (TextView) popUp.getContentView().findViewById(R.id.ReportInfo);
    396         if (view.getId() == R.id.buttonSystraceHelp || view.getId() == R.id.buttonBugreportHelp) {
    397             helpText.setText(getResources().getString(R.string.systraceHelp));
    398         } else if (view.getId() == R.id.buttonCalibrateSoundLevelHelp) {
    399             helpText.setText(getResources().getString(R.string.calibrateSoundLevelHelp));
    400         }
    401 
    402         // display pop up window, dismissible with back button
    403         popUp.showAtLocation(findViewById(R.id.settingsMainLayout), Gravity.TOP, 0, 0);
    404     }
    405 
    406         /** Called when the user clicks the button */
    407     public void onButtonClick(View view) {
    408         getApp().computeDefaults();
    409         refresh();
    410     }
    411 
    412 // Below is work in progress by Ricardo
    413 //    public void onButtonRecordDefault(View view) {
    414 //        int samplingRate = getApp().getSamplingRate();
    415 //
    416 //        int minRecorderBufferSizeInBytes =  AudioRecord.getMinBufferSize(samplingRate,
    417 //                AudioFormat.CHANNEL_IN_MONO,
    418 //                AudioFormat.ENCODING_PCM_16BIT);
    419 //        getApp().setRecorderBufferSizeInBytes(minRecorderBufferSizeInBytes);
    420 //
    421 //        refresh();
    422 //    }
    423 
    424 //    private void computeDefaults() {
    425 //
    426 ////        if (getApp().getAudioThreadType() == LoopbackApplication.AUDIO_THREAD_TYPE_JAVA) {
    427 ////            mNumberPickerRecorderBuffer.setEnabled(true);
    428 ////        else
    429 ////            mNumberPickerRecorderBuffer.setEnabled(false);
    430 //
    431 //        int samplingRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
    432 //        getApp().setSamplingRate(samplingRate);
    433 //        int minPlayerBufferSizeInBytes = AudioTrack.getMinBufferSize(samplingRate,
    434 //                AudioFormat.CHANNEL_OUT_MONO,
    435 //                AudioFormat.ENCODING_PCM_16BIT);
    436 //        getApp().setPlayerBufferSizeInBytes(minPlayerBufferSizeInBytes);
    437 //
    438 //        int minRecorderBufferSizeInBytes =  AudioRecord.getMinBufferSize(samplingRate,
    439 //                AudioFormat.CHANNEL_IN_MONO,
    440 //                AudioFormat.ENCODING_PCM_16BIT);
    441 //        getApp().setRecorderBufferSizeInBytes(minRecorderBufferSizeInBytes);
    442 //        getApp().setRecorderBufferSizeInBytes(minRecorderBufferSizeInBytes);
    443 //
    444 //        log("computed defaults");
    445 //
    446 //    }
    447 
    448     private LoopbackApplication getApp() {
    449         return (LoopbackApplication) this.getApplication();
    450     }
    451 
    452 
    453     private static void log(String msg) {
    454         Log.v(TAG, msg);
    455     }
    456 
    457 
    458 }
    459