• 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.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
onCreate(final Bundle savedInstanceState)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
onResume()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
onPause()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 
reverbSpinnerInit(Spinner spinner)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 
equalizerSpinnerInit(Spinner spinner)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      */
setEnabledAllChildren(final ViewGroup viewGroup, final boolean enabled)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      */
updateUI()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      */
updateUIHeadset()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      */
equalizerBandsInit(View eqcontainer)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 
format(String format, Object... args)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
onProgressChanged(final SeekBar seekbar, final int progress, final boolean fromUser)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
onStartTrackingTouch(final SeekBar seekbar)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
onStopTrackingTouch(final SeekBar seekbar)698     public void onStopTrackingTouch(final SeekBar seekbar) {
699         equalizerUpdateDisplay();
700     }
701 
702     /**
703      * Updates the EQ by getting the parameters.
704      */
equalizerUpdateDisplay()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      */
equalizerBandUpdate(final int band, final int level)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      */
equalizerSetPreset(final int preset)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      */
presetReverbSetPreset(final int preset)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      */
showHeadsetMsg()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