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