Home | History | Annotate | Download | only in musicfx
      1 /*
      2  * Copyright (C) 2010-2011 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.musicfx;
     18 
     19 import com.android.audiofx.OpenSLESConstants;
     20 import com.android.musicfx.seekbar.SeekBar;
     21 import com.android.musicfx.seekbar.SeekBar.OnSeekBarChangeListener;
     22 
     23 import android.app.ActionBar;
     24 import android.app.Activity;
     25 import android.app.AlertDialog;
     26 import android.app.Dialog;
     27 import android.bluetooth.BluetoothClass;
     28 import android.bluetooth.BluetoothDevice;
     29 import android.content.BroadcastReceiver;
     30 import android.content.Context;
     31 import android.content.DialogInterface;
     32 import android.content.DialogInterface.OnCancelListener;
     33 import android.content.Intent;
     34 import android.content.IntentFilter;
     35 import android.media.AudioManager;
     36 import android.media.audiofx.AudioEffect;
     37 import android.media.audiofx.AudioEffect.Descriptor;
     38 import android.os.Bundle;
     39 import android.util.Log;
     40 import android.view.Gravity;
     41 import android.view.LayoutInflater;
     42 import android.view.MotionEvent;
     43 import android.view.View;
     44 import android.view.View.OnClickListener;
     45 import android.view.View.OnTouchListener;
     46 import android.view.ViewGroup;
     47 import android.widget.AdapterView;
     48 import android.widget.AdapterView.OnItemSelectedListener;
     49 import android.widget.ArrayAdapter;
     50 import android.widget.CompoundButton;
     51 import android.widget.CompoundButton.OnCheckedChangeListener;
     52 import android.widget.LinearLayout;
     53 import android.widget.ListView;
     54 import android.widget.RelativeLayout;
     55 import android.widget.Spinner;
     56 import android.widget.Switch;
     57 import android.widget.TextView;
     58 import android.widget.Toast;
     59 
     60 import java.util.Formatter;
     61 import java.util.Locale;
     62 
     63 /**
     64  *
     65  */
     66 public class ActivityMusic extends Activity implements OnSeekBarChangeListener {
     67     private final static String TAG = "MusicFXActivityMusic";
     68 
     69     /**
     70      * Max number of EQ bands supported
     71      */
     72     private final static int EQUALIZER_MAX_BANDS = 32;
     73 
     74     /**
     75      * Indicates if Virtualizer effect is supported.
     76      */
     77     private boolean mVirtualizerSupported;
     78     /**
     79      * Indicates if BassBoost effect is supported.
     80      */
     81     private boolean mBassBoostSupported;
     82     /**
     83      * Indicates if Equalizer effect is supported.
     84      */
     85     private boolean mEqualizerSupported;
     86     /**
     87      * Indicates if Preset Reverb effect is supported.
     88      */
     89     private boolean mPresetReverbSupported;
     90 
     91     // Equalizer fields
     92     private final SeekBar[] mEqualizerSeekBar = new SeekBar[EQUALIZER_MAX_BANDS];
     93     private int mNumberEqualizerBands;
     94     private int mEqualizerMinBandLevel;
     95     private int mEQPresetUserPos = 1;
     96     private int mEQPreset;
     97     private int mEQPresetPrevious;
     98     private int[] mEQPresetUserBandLevelsPrev;
     99     private String[] mEQPresetNames;
    100 
    101     private int mPRPreset;
    102     private int mPRPresetPrevious;
    103 
    104     private boolean mIsHeadsetOn = false;
    105     private CompoundButton mToggleSwitch;
    106 
    107     private StringBuilder mFormatBuilder = new StringBuilder();
    108     private Formatter mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
    109 
    110     /**
    111      * Mapping for the EQ widget ids per band
    112      */
    113     private static final int[][] EQViewElementIds = {
    114             { R.id.EQBand0TextView, R.id.EQBand0SeekBar },
    115             { R.id.EQBand1TextView, R.id.EQBand1SeekBar },
    116             { R.id.EQBand2TextView, R.id.EQBand2SeekBar },
    117             { R.id.EQBand3TextView, R.id.EQBand3SeekBar },
    118             { R.id.EQBand4TextView, R.id.EQBand4SeekBar },
    119             { R.id.EQBand5TextView, R.id.EQBand5SeekBar },
    120             { R.id.EQBand6TextView, R.id.EQBand6SeekBar },
    121             { R.id.EQBand7TextView, R.id.EQBand7SeekBar },
    122             { R.id.EQBand8TextView, R.id.EQBand8SeekBar },
    123             { R.id.EQBand9TextView, R.id.EQBand9SeekBar },
    124             { R.id.EQBand10TextView, R.id.EQBand10SeekBar },
    125             { R.id.EQBand11TextView, R.id.EQBand11SeekBar },
    126             { R.id.EQBand12TextView, R.id.EQBand12SeekBar },
    127             { R.id.EQBand13TextView, R.id.EQBand13SeekBar },
    128             { R.id.EQBand14TextView, R.id.EQBand14SeekBar },
    129             { R.id.EQBand15TextView, R.id.EQBand15SeekBar },
    130             { R.id.EQBand16TextView, R.id.EQBand16SeekBar },
    131             { R.id.EQBand17TextView, R.id.EQBand17SeekBar },
    132             { R.id.EQBand18TextView, R.id.EQBand18SeekBar },
    133             { R.id.EQBand19TextView, R.id.EQBand19SeekBar },
    134             { R.id.EQBand20TextView, R.id.EQBand20SeekBar },
    135             { R.id.EQBand21TextView, R.id.EQBand21SeekBar },
    136             { R.id.EQBand22TextView, R.id.EQBand22SeekBar },
    137             { R.id.EQBand23TextView, R.id.EQBand23SeekBar },
    138             { R.id.EQBand24TextView, R.id.EQBand24SeekBar },
    139             { R.id.EQBand25TextView, R.id.EQBand25SeekBar },
    140             { R.id.EQBand26TextView, R.id.EQBand26SeekBar },
    141             { R.id.EQBand27TextView, R.id.EQBand27SeekBar },
    142             { R.id.EQBand28TextView, R.id.EQBand28SeekBar },
    143             { R.id.EQBand29TextView, R.id.EQBand29SeekBar },
    144             { R.id.EQBand30TextView, R.id.EQBand30SeekBar },
    145             { R.id.EQBand31TextView, R.id.EQBand31SeekBar } };
    146 
    147     // Preset Reverb fields
    148     /**
    149      * Array containing the PR preset names.
    150      */
    151     private static final String[] PRESETREVERBPRESETSTRINGS = { "None", "SmallRoom", "MediumRoom",
    152             "LargeRoom", "MediumHall", "LargeHall", "Plate" };
    153 
    154     /**
    155      * Context field
    156      */
    157     private Context mContext;
    158 
    159     /**
    160      * Calling package name field
    161      */
    162     private String mCallingPackageName = "empty";
    163 
    164     /**
    165      * Audio session field
    166      */
    167     private int mAudioSession = AudioEffect.ERROR_BAD_VALUE;
    168 
    169     // Broadcast receiver to handle wired and Bluetooth A2dp headset events
    170     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    171         @Override
    172         public void onReceive(final Context context, final Intent intent) {
    173             final String action = intent.getAction();
    174             final boolean isHeadsetOnPrev = mIsHeadsetOn;
    175             final AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
    176             if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
    177                 mIsHeadsetOn = (intent.getIntExtra("state", 0) == 1)
    178                         || audioManager.isBluetoothA2dpOn();
    179             } else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
    180                 final int deviceClass = ((BluetoothDevice) intent
    181                         .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)).getBluetoothClass()
    182                         .getDeviceClass();
    183                 if ((deviceClass == BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES)
    184                         || (deviceClass == BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET)) {
    185                     mIsHeadsetOn = true;
    186                 }
    187             } else if (action.equals(AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
    188                 mIsHeadsetOn = audioManager.isBluetoothA2dpOn() || audioManager.isWiredHeadsetOn();
    189             } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
    190                 final int deviceClass = ((BluetoothDevice) intent
    191                         .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)).getBluetoothClass()
    192                         .getDeviceClass();
    193                 if ((deviceClass == BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES)
    194                         || (deviceClass == BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET)) {
    195                     mIsHeadsetOn = audioManager.isWiredHeadsetOn();
    196                 }
    197             }
    198             if (isHeadsetOnPrev != mIsHeadsetOn) {
    199                 updateUIHeadset();
    200             }
    201         }
    202     };
    203 
    204     /*
    205      * Declares and initializes all objects and widgets in the layouts and the CheckBox and SeekBar
    206      * onchange methods on creation.
    207      *
    208      * (non-Javadoc)
    209      *
    210      * @see android.app.ActivityGroup#onCreate(android.os.Bundle)
    211      */
    212     @Override
    213     public void onCreate(final Bundle savedInstanceState) {
    214         super.onCreate(savedInstanceState);
    215 
    216         // Init context to be used in listeners
    217         mContext = this;
    218 
    219         // Receive intent
    220         // get calling intent
    221         final Intent intent = getIntent();
    222         mAudioSession = intent.getIntExtra(AudioEffect.EXTRA_AUDIO_SESSION,
    223                 AudioEffect.ERROR_BAD_VALUE);
    224         Log.v(TAG, "audio session: " + mAudioSession);
    225 
    226         mCallingPackageName = getCallingPackage();
    227 
    228         // check for errors
    229         if (mCallingPackageName == null) {
    230             Log.e(TAG, "Package name is null");
    231             setResult(RESULT_CANCELED);
    232             finish();
    233             return;
    234         }
    235         setResult(RESULT_OK);
    236 
    237         Log.v(TAG, mCallingPackageName + " (" + mAudioSession + ")");
    238 
    239         ControlPanelEffect.initEffectsPreferences(mContext, mCallingPackageName, mAudioSession);
    240 
    241         // query available effects
    242         final Descriptor[] effects = AudioEffect.queryEffects();
    243 
    244         // Determine available/supported effects
    245         Log.v(TAG, "Available effects:");
    246         for (final Descriptor effect : effects) {
    247             Log.v(TAG, effect.name.toString() + ", type: " + effect.type.toString());
    248 
    249             if (effect.type.equals(AudioEffect.EFFECT_TYPE_VIRTUALIZER)) {
    250                 mVirtualizerSupported = true;
    251             } else if (effect.type.equals(AudioEffect.EFFECT_TYPE_BASS_BOOST)) {
    252                 mBassBoostSupported = true;
    253             } else if (effect.type.equals(AudioEffect.EFFECT_TYPE_EQUALIZER)) {
    254                 mEqualizerSupported = true;
    255             } else if (effect.type.equals(AudioEffect.EFFECT_TYPE_PRESET_REVERB)) {
    256                 mPresetReverbSupported = true;
    257             }
    258         }
    259 
    260         setContentView(R.layout.music_main);
    261         final ViewGroup viewGroup = (ViewGroup) findViewById(R.id.contentSoundEffects);
    262 
    263         // Fill array with presets from AudioEffects call.
    264         // allocate a space for 2 extra strings (CI Extreme & User)
    265         final int numPresets = ControlPanelEffect.getParameterInt(mContext, mCallingPackageName,
    266                 mAudioSession, ControlPanelEffect.Key.eq_num_presets);
    267         mEQPresetNames = new String[numPresets + 2];
    268         for (short i = 0; i < numPresets; i++) {
    269             mEQPresetNames[i] = ControlPanelEffect.getParameterString(mContext,
    270                     mCallingPackageName, mAudioSession, ControlPanelEffect.Key.eq_preset_name, i);
    271         }
    272         mEQPresetNames[numPresets] = getString(R.string.ci_extreme);
    273         mEQPresetNames[numPresets + 1] = getString(R.string.user);
    274         mEQPresetUserPos = numPresets + 1;
    275 
    276         // Watch for button clicks and initialization.
    277         if ((mVirtualizerSupported) || (mBassBoostSupported) || (mEqualizerSupported)
    278                 || (mPresetReverbSupported)) {
    279             // Set the listener for the main enhancements toggle button.
    280             // Depending on the state enable the supported effects if they were
    281             // checked in the setup tab.
    282             mToggleSwitch = new Switch(this);
    283             mToggleSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
    284                 @Override
    285                 public void onCheckedChanged(final CompoundButton buttonView,
    286                         final boolean isChecked) {
    287 
    288                     // set parameter and state
    289                     ControlPanelEffect.setParameterBoolean(mContext, mCallingPackageName,
    290                             mAudioSession, ControlPanelEffect.Key.global_enabled, isChecked);
    291                     // Enable Linear layout (in scroll layout) view with all
    292                     // effect contents depending on checked state
    293                     setEnabledAllChildren(viewGroup, isChecked);
    294                     // update UI according to headset state
    295                     updateUIHeadset();
    296                 }
    297             });
    298 
    299             // Initialize the Virtualizer elements.
    300             // Set the SeekBar listener.
    301             if (mVirtualizerSupported) {
    302                 // Show msg when disabled slider (layout) is touched
    303                 findViewById(R.id.vILayout).setOnTouchListener(new OnTouchListener() {
    304 
    305                     @Override
    306                     public boolean onTouch(final View v, final MotionEvent event) {
    307                         if (event.getAction() == MotionEvent.ACTION_UP) {
    308                             showHeadsetMsg();
    309                         }
    310                         return false;
    311                     }
    312                 });
    313 
    314                 final SeekBar seekbar = (SeekBar) findViewById(R.id.vIStrengthSeekBar);
    315                 seekbar.setMax(OpenSLESConstants.VIRTUALIZER_MAX_STRENGTH
    316                         - OpenSLESConstants.VIRTUALIZER_MIN_STRENGTH);
    317 
    318                 seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
    319                     // Update the parameters while SeekBar changes and set the
    320                     // effect parameter.
    321 
    322                     @Override
    323                     public void onProgressChanged(final SeekBar seekBar, final int progress,
    324                             final boolean fromUser) {
    325                         // set parameter and state
    326                         ControlPanelEffect.setParameterInt(mContext, mCallingPackageName,
    327                                 mAudioSession, ControlPanelEffect.Key.virt_strength, progress);
    328                     }
    329 
    330                     // If slider pos was 0 when starting re-enable effect
    331                     @Override
    332                     public void onStartTrackingTouch(final SeekBar seekBar) {
    333                         if (seekBar.getProgress() == 0) {
    334                             ControlPanelEffect.setParameterBoolean(mContext, mCallingPackageName,
    335                                     mAudioSession, ControlPanelEffect.Key.virt_enabled, true);
    336                         }
    337                     }
    338 
    339                     // If slider pos = 0 when stopping disable effect
    340                     @Override
    341                     public void onStopTrackingTouch(final SeekBar seekBar) {
    342                         if (seekBar.getProgress() == 0) {
    343                             // disable
    344                             ControlPanelEffect.setParameterBoolean(mContext, mCallingPackageName,
    345                                     mAudioSession, ControlPanelEffect.Key.virt_enabled, false);
    346                         }
    347                     }
    348                 });
    349             }
    350 
    351             // Initialize the Bass Boost elements.
    352             // Set the SeekBar listener.
    353             if (mBassBoostSupported) {
    354                 // Show msg when disabled slider (layout) is touched
    355                 findViewById(R.id.bBLayout).setOnTouchListener(new OnTouchListener() {
    356 
    357                     @Override
    358                     public boolean onTouch(final View v, final MotionEvent event) {
    359                         if (event.getAction() == MotionEvent.ACTION_UP) {
    360                             showHeadsetMsg();
    361                         }
    362                         return false;
    363                     }
    364                 });
    365 
    366                 final SeekBar seekbar = (SeekBar) findViewById(R.id.bBStrengthSeekBar);
    367                 seekbar.setMax(OpenSLESConstants.BASSBOOST_MAX_STRENGTH
    368                         - OpenSLESConstants.BASSBOOST_MIN_STRENGTH);
    369 
    370                 seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
    371                     // Update the parameters while SeekBar changes and set the
    372                     // effect parameter.
    373 
    374                     @Override
    375                     public void onProgressChanged(final SeekBar seekBar, final int progress,
    376                             final boolean fromUser) {
    377                         // set parameter and state
    378                         ControlPanelEffect.setParameterInt(mContext, mCallingPackageName,
    379                                 mAudioSession, ControlPanelEffect.Key.bb_strength, progress);
    380                     }
    381 
    382                     // If slider pos was 0 when starting re-enable effect
    383                     @Override
    384                     public void onStartTrackingTouch(final SeekBar seekBar) {
    385                         if (seekBar.getProgress() == 0) {
    386                             ControlPanelEffect.setParameterBoolean(mContext, mCallingPackageName,
    387                                     mAudioSession, ControlPanelEffect.Key.bb_enabled, true);
    388                         }
    389                     }
    390 
    391                     // If slider pos = 0 when stopping disable effect
    392                     @Override
    393                     public void onStopTrackingTouch(final SeekBar seekBar) {
    394                         if (seekBar.getProgress() == 0) {
    395                             // disable
    396                             ControlPanelEffect.setParameterBoolean(mContext, mCallingPackageName,
    397                                     mAudioSession, ControlPanelEffect.Key.bb_enabled, false);
    398                         }
    399 
    400                     }
    401                 });
    402             }
    403 
    404             // Initialize the Equalizer elements.
    405             if (mEqualizerSupported) {
    406                 mEQPreset = ControlPanelEffect.getParameterInt(mContext, mCallingPackageName,
    407                         mAudioSession, ControlPanelEffect.Key.eq_current_preset);
    408                 if (mEQPreset >= mEQPresetNames.length) {
    409                     mEQPreset = 0;
    410                 }
    411                 mEQPresetPrevious = mEQPreset;
    412                 equalizerSpinnerInit((Spinner)findViewById(R.id.eqSpinner));
    413                 equalizerBandsInit(findViewById(R.id.eqcontainer));
    414             }
    415 
    416             // Initialize the Preset Reverb elements.
    417             // Set Spinner listeners.
    418             if (mPresetReverbSupported) {
    419                 mPRPreset = ControlPanelEffect.getParameterInt(mContext, mCallingPackageName,
    420                         mAudioSession, ControlPanelEffect.Key.pr_current_preset);
    421                 mPRPresetPrevious = mPRPreset;
    422                 reverbSpinnerInit((Spinner)findViewById(R.id.prSpinner));
    423             }
    424 
    425         } else {
    426             viewGroup.setVisibility(View.GONE);
    427             ((TextView) findViewById(R.id.noEffectsTextView)).setVisibility(View.VISIBLE);
    428         }
    429 
    430         ActionBar ab = getActionBar();
    431         final int padding = getResources().getDimensionPixelSize(
    432                 R.dimen.action_bar_switch_padding);
    433         mToggleSwitch.setPadding(0,0, padding, 0);
    434         ab.setCustomView(mToggleSwitch, new ActionBar.LayoutParams(
    435                 ActionBar.LayoutParams.WRAP_CONTENT,
    436                 ActionBar.LayoutParams.WRAP_CONTENT,
    437                 Gravity.CENTER_VERTICAL | Gravity.RIGHT));
    438         ab.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
    439     }
    440 
    441     /*
    442      * (non-Javadoc)
    443      *
    444      * @see android.app.Activity#onResume()
    445      */
    446     @Override
    447     protected void onResume() {
    448         super.onResume();
    449         if ((mVirtualizerSupported) || (mBassBoostSupported) || (mEqualizerSupported)
    450                 || (mPresetReverbSupported)) {
    451             // Listen for broadcast intents that might affect the onscreen UI for headset.
    452             final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
    453             intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
    454             intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
    455             intentFilter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
    456             registerReceiver(mReceiver, intentFilter);
    457 
    458             // Check if wired or Bluetooth headset is connected/on
    459             final AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
    460             mIsHeadsetOn = (audioManager.isWiredHeadsetOn() || audioManager.isBluetoothA2dpOn());
    461             Log.v(TAG, "onResume: mIsHeadsetOn : " + mIsHeadsetOn);
    462 
    463             // Update UI
    464             updateUI();
    465         }
    466     }
    467 
    468     /*
    469      * (non-Javadoc)
    470      *
    471      * @see android.app.Activity#onPause()
    472      */
    473     @Override
    474     protected void onPause() {
    475         super.onPause();
    476 
    477         // Unregister for broadcast intents. (These affect the visible UI,
    478         // so we only care about them while we're in the foreground.)
    479         unregisterReceiver(mReceiver);
    480     }
    481 
    482     private void reverbSpinnerInit(Spinner spinner) {
    483         ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
    484                 android.R.layout.simple_spinner_item, PRESETREVERBPRESETSTRINGS);
    485         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    486         spinner.setAdapter(adapter);
    487         spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
    488 
    489             @Override
    490             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
    491                 if (position != mPRPresetPrevious) {
    492                     presetReverbSetPreset(position);
    493                 }
    494                 mPRPresetPrevious = position;
    495             }
    496 
    497             @Override
    498             public void onNothingSelected(AdapterView<?> parent) {
    499             }
    500         });
    501         spinner.setSelection(mPRPreset);
    502     }
    503 
    504     private void equalizerSpinnerInit(Spinner spinner) {
    505         ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
    506                 android.R.layout.simple_spinner_item, mEQPresetNames);
    507         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    508         spinner.setAdapter(adapter);
    509         spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
    510 
    511             @Override
    512             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
    513                 if (position != mEQPresetPrevious) {
    514                     equalizerSetPreset(position);
    515                 }
    516                 mEQPresetPrevious = position;
    517             }
    518 
    519             @Override
    520             public void onNothingSelected(AdapterView<?> parent) {
    521             }
    522         });
    523         spinner.setSelection(mEQPreset);
    524     }
    525 
    526 
    527     /**
    528      * En/disables all children for a given view. For linear and relative layout children do this
    529      * recursively
    530      *
    531      * @param viewGroup
    532      * @param enabled
    533      */
    534     private void setEnabledAllChildren(final ViewGroup viewGroup, final boolean enabled) {
    535         final int count = viewGroup.getChildCount();
    536         for (int i = 0; i < count; i++) {
    537             final View view = viewGroup.getChildAt(i);
    538             if ((view instanceof LinearLayout) || (view instanceof RelativeLayout)) {
    539                 final ViewGroup vg = (ViewGroup) view;
    540                 setEnabledAllChildren(vg, enabled);
    541             }
    542             view.setEnabled(enabled);
    543         }
    544     }
    545 
    546     /**
    547      * Updates UI (checkbox, seekbars, enabled states) according to the current stored preferences.
    548      */
    549     private void updateUI() {
    550         final boolean isEnabled = ControlPanelEffect.getParameterBoolean(mContext,
    551                 mCallingPackageName, mAudioSession, ControlPanelEffect.Key.global_enabled);
    552         mToggleSwitch.setChecked(isEnabled);
    553         setEnabledAllChildren((ViewGroup) findViewById(R.id.contentSoundEffects), isEnabled);
    554         updateUIHeadset();
    555 
    556         if (mVirtualizerSupported) {
    557             ((SeekBar) findViewById(R.id.vIStrengthSeekBar)).setProgress(ControlPanelEffect
    558                     .getParameterInt(mContext, mCallingPackageName, mAudioSession,
    559                             ControlPanelEffect.Key.virt_strength));
    560         }
    561         if (mBassBoostSupported) {
    562             ((SeekBar) findViewById(R.id.bBStrengthSeekBar)).setProgress(ControlPanelEffect
    563                     .getParameterInt(mContext, mCallingPackageName, mAudioSession,
    564                             ControlPanelEffect.Key.bb_strength));
    565         }
    566         if (mEqualizerSupported) {
    567             equalizerUpdateDisplay();
    568         }
    569         if (mPresetReverbSupported) {
    570             int reverb = ControlPanelEffect.getParameterInt(
    571                                     mContext, mCallingPackageName, mAudioSession,
    572                                     ControlPanelEffect.Key.pr_current_preset);
    573             ((Spinner)findViewById(R.id.prSpinner)).setSelection(reverb);
    574         }
    575     }
    576 
    577     /**
    578      * Updates UI for headset mode. En/disable VI and BB controls depending on headset state
    579      * (on/off) if effects are on. Do the inverse for their layouts so they can take over
    580      * control/events.
    581      */
    582     private void updateUIHeadset() {
    583         if (mToggleSwitch.isChecked()) {
    584             ((TextView) findViewById(R.id.vIStrengthText)).setEnabled(mIsHeadsetOn);
    585             ((SeekBar) findViewById(R.id.vIStrengthSeekBar)).setEnabled(mIsHeadsetOn);
    586             findViewById(R.id.vILayout).setEnabled(!mIsHeadsetOn);
    587             ((TextView) findViewById(R.id.bBStrengthText)).setEnabled(mIsHeadsetOn);
    588             ((SeekBar) findViewById(R.id.bBStrengthSeekBar)).setEnabled(mIsHeadsetOn);
    589             findViewById(R.id.bBLayout).setEnabled(!mIsHeadsetOn);
    590         }
    591     }
    592 
    593     /**
    594      * Initializes the equalizer elements. Set the SeekBars and Spinner listeners.
    595      */
    596     private void equalizerBandsInit(View eqcontainer) {
    597         // Initialize the N-Band Equalizer elements.
    598         mNumberEqualizerBands = ControlPanelEffect.getParameterInt(mContext, mCallingPackageName,
    599                 mAudioSession, ControlPanelEffect.Key.eq_num_bands);
    600         mEQPresetUserBandLevelsPrev = ControlPanelEffect.getParameterIntArray(mContext,
    601                 mCallingPackageName, mAudioSession,
    602                 ControlPanelEffect.Key.eq_preset_user_band_level);
    603         final int[] centerFreqs = ControlPanelEffect.getParameterIntArray(mContext,
    604                 mCallingPackageName, mAudioSession, ControlPanelEffect.Key.eq_center_freq);
    605         final int[] bandLevelRange = ControlPanelEffect.getParameterIntArray(mContext,
    606                 mCallingPackageName, mAudioSession, ControlPanelEffect.Key.eq_level_range);
    607         mEqualizerMinBandLevel = bandLevelRange[0];
    608         final int mEqualizerMaxBandLevel = bandLevelRange[1];
    609 
    610         for (int band = 0; band < mNumberEqualizerBands; band++) {
    611             // Unit conversion from mHz to Hz and use k prefix if necessary to display
    612             final int centerFreq = centerFreqs[band] / 1000;
    613             float centerFreqHz = centerFreq;
    614             String unitPrefix = "";
    615             if (centerFreqHz >= 1000) {
    616                 centerFreqHz = centerFreqHz / 1000;
    617                 unitPrefix = "k";
    618             }
    619             ((TextView) eqcontainer.findViewById(EQViewElementIds[band][0])).setText(
    620                     format("%.0f ", centerFreqHz) + unitPrefix + "Hz");
    621             mEqualizerSeekBar[band] = (SeekBar) eqcontainer
    622                     .findViewById(EQViewElementIds[band][1]);
    623             mEqualizerSeekBar[band].setMax(mEqualizerMaxBandLevel - mEqualizerMinBandLevel);
    624             mEqualizerSeekBar[band].setOnSeekBarChangeListener(this);
    625         }
    626 
    627         // Hide the inactive Equalizer bands.
    628         for (int band = mNumberEqualizerBands; band < EQUALIZER_MAX_BANDS; band++) {
    629             // CenterFreq text
    630             eqcontainer.findViewById(EQViewElementIds[band][0]).setVisibility(View.GONE);
    631             // SeekBar
    632             eqcontainer.findViewById(EQViewElementIds[band][1]).setVisibility(View.GONE);
    633         }
    634 
    635         // TODO: get the actual values from somewhere
    636         TextView tv = (TextView) findViewById(R.id.maxLevelText);
    637         tv.setText("+15 dB");
    638         tv = (TextView) findViewById(R.id.centerLevelText);
    639         tv.setText("0 dB");
    640         tv = (TextView) findViewById(R.id.minLevelText);
    641         tv.setText("-15 dB");
    642         equalizerUpdateDisplay();
    643     }
    644 
    645     private String format(String format, Object... args) {
    646         mFormatBuilder.setLength(0);
    647         mFormatter.format(format, args);
    648         return mFormatBuilder.toString();
    649     }
    650 
    651     /*
    652      * For the EQ Band SeekBars
    653      *
    654      * (non-Javadoc)
    655      *
    656      * @see android.widget.SeekBar.OnSeekBarChangeListener#onProgressChanged(android
    657      * .widget.SeekBar, int, boolean)
    658      */
    659 
    660     @Override
    661     public void onProgressChanged(final SeekBar seekbar, final int progress, final boolean fromUser) {
    662         final int id = seekbar.getId();
    663 
    664         for (short band = 0; band < mNumberEqualizerBands; band++) {
    665             if (id == EQViewElementIds[band][1]) {
    666                 final short level = (short) (progress + mEqualizerMinBandLevel);
    667                 if (fromUser) {
    668                     equalizerBandUpdate(band, level);
    669                 }
    670                 break;
    671             }
    672         }
    673     }
    674 
    675     /*
    676      * (non-Javadoc)
    677      *
    678      * @see android.widget.SeekBar.OnSeekBarChangeListener#onStartTrackingTouch(android
    679      * .widget.SeekBar)
    680      */
    681 
    682     @Override
    683     public void onStartTrackingTouch(final SeekBar seekbar) {
    684         // get current levels
    685         final int[] bandLevels = ControlPanelEffect.getParameterIntArray(mContext,
    686                 mCallingPackageName, mAudioSession, ControlPanelEffect.Key.eq_band_level);
    687         // copy current levels to user preset
    688         for (short band = 0; band < mNumberEqualizerBands; band++) {
    689             equalizerBandUpdate(band, bandLevels[band]);
    690         }
    691         equalizerSetPreset(mEQPresetUserPos);
    692         ((Spinner)findViewById(R.id.eqSpinner)).setSelection(mEQPresetUserPos);
    693     }
    694 
    695     /*
    696      * Updates the EQ display when the user stops changing.
    697      *
    698      * (non-Javadoc)
    699      *
    700      * @see android.widget.SeekBar.OnSeekBarChangeListener#onStopTrackingTouch(android
    701      * .widget.SeekBar)
    702      */
    703 
    704     @Override
    705     public void onStopTrackingTouch(final SeekBar seekbar) {
    706         equalizerUpdateDisplay();
    707     }
    708 
    709     /**
    710      * Updates the EQ by getting the parameters.
    711      */
    712     private void equalizerUpdateDisplay() {
    713         // Update and show the active N-Band Equalizer bands.
    714         final int[] bandLevels = ControlPanelEffect.getParameterIntArray(mContext,
    715                 mCallingPackageName, mAudioSession, ControlPanelEffect.Key.eq_band_level);
    716         for (short band = 0; band < mNumberEqualizerBands; band++) {
    717             final int level = bandLevels[band];
    718             final int progress = level - mEqualizerMinBandLevel;
    719             mEqualizerSeekBar[band].setProgress(progress);
    720         }
    721     }
    722 
    723     /**
    724      * Updates/sets a given EQ band level.
    725      *
    726      * @param band
    727      *            Band id
    728      * @param level
    729      *            EQ band level
    730      */
    731     private void equalizerBandUpdate(final int band, final int level) {
    732         ControlPanelEffect.setParameterInt(mContext, mCallingPackageName, mAudioSession,
    733                 ControlPanelEffect.Key.eq_band_level, level, band);
    734     }
    735 
    736     /**
    737      * Sets the given EQ preset.
    738      *
    739      * @param preset
    740      *            EQ preset id.
    741      */
    742     private void equalizerSetPreset(final int preset) {
    743         ControlPanelEffect.setParameterInt(mContext, mCallingPackageName, mAudioSession,
    744                 ControlPanelEffect.Key.eq_current_preset, preset);
    745         equalizerUpdateDisplay();
    746     }
    747 
    748     /**
    749      * Sets the given PR preset.
    750      *
    751      * @param preset
    752      *            PR preset id.
    753      */
    754     private void presetReverbSetPreset(final int preset) {
    755         ControlPanelEffect.setParameterInt(mContext, mCallingPackageName, mAudioSession,
    756                 ControlPanelEffect.Key.pr_current_preset, preset);
    757     }
    758 
    759     /**
    760      * Show msg that headset needs to be plugged.
    761      */
    762     private void showHeadsetMsg() {
    763         final Context context = getApplicationContext();
    764         final int duration = Toast.LENGTH_SHORT;
    765 
    766         final Toast toast = Toast.makeText(context, getString(R.string.headset_plug), duration);
    767         toast.setGravity(Gravity.CENTER, toast.getXOffset() / 2, toast.getYOffset() / 2);
    768         toast.show();
    769     }
    770 }
    771