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