blob: 6f9718a39f420db5346e87f3011026743e966c97 [file] [log] [blame]
Marco Nelissen66f2cfe2011-06-23 14:05:10 -07001/*
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
17package com.android.musicfx;
18
Marco Nelissenc4724442011-06-30 12:07:50 -070019import com.android.audiofx.OpenSLESConstants;
20import com.android.musicfx.seekbar.SeekBar;
21import com.android.musicfx.seekbar.SeekBar.OnSeekBarChangeListener;
22
Marco Nelissen709c4152011-10-31 13:45:46 -070023import android.app.ActionBar;
Marco Nelissen66f2cfe2011-06-23 14:05:10 -070024import android.app.Activity;
25import android.app.AlertDialog;
26import android.app.Dialog;
27import android.bluetooth.BluetoothClass;
28import android.bluetooth.BluetoothDevice;
29import android.content.BroadcastReceiver;
30import android.content.Context;
31import android.content.DialogInterface;
32import android.content.DialogInterface.OnCancelListener;
33import android.content.Intent;
34import android.content.IntentFilter;
35import android.media.AudioManager;
36import android.media.audiofx.AudioEffect;
37import android.media.audiofx.AudioEffect.Descriptor;
38import android.os.Bundle;
39import android.util.Log;
40import android.view.Gravity;
41import android.view.LayoutInflater;
Marco Nelissen66f2cfe2011-06-23 14:05:10 -070042import android.view.MotionEvent;
43import android.view.View;
44import android.view.View.OnClickListener;
45import android.view.View.OnTouchListener;
46import android.view.ViewGroup;
Marco Nelissene7de6512011-08-18 11:13:20 -070047import android.widget.AdapterView;
48import android.widget.AdapterView.OnItemSelectedListener;
49import android.widget.ArrayAdapter;
Marco Nelissen66f2cfe2011-06-23 14:05:10 -070050import android.widget.CompoundButton;
51import android.widget.CompoundButton.OnCheckedChangeListener;
52import android.widget.LinearLayout;
53import android.widget.ListView;
54import android.widget.RelativeLayout;
Marco Nelissene7de6512011-08-18 11:13:20 -070055import android.widget.Spinner;
Marco Nelissen709c4152011-10-31 13:45:46 -070056import android.widget.Switch;
Marco Nelissen66f2cfe2011-06-23 14:05:10 -070057import android.widget.TextView;
58import android.widget.Toast;
59
Marco Nelissenf3b27982011-06-28 12:20:14 -070060import java.util.Formatter;
Marco Nelissenf3b27982011-06-28 12:20:14 -070061import java.util.Locale;
Marco Nelissen1c9259e2012-10-11 09:18:45 -070062import java.util.UUID;
Marco Nelissen66f2cfe2011-06-23 14:05:10 -070063
64/**
65 *
66 */
67public 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 /**
Marco Nelissen66f2cfe2011-06-23 14:05:10 -070076 * Indicates if Virtualizer effect is supported.
77 */
78 private boolean mVirtualizerSupported;
Marco Nelissen1c9259e2012-10-11 09:18:45 -070079 private boolean mVirtualizerIsHeadphoneOnly;
Marco Nelissen66f2cfe2011-06-23 14:05:10 -070080 /**
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];
Marco Nelissen66f2cfe2011-06-23 14:05:10 -070095 private int mNumberEqualizerBands;
96 private int mEqualizerMinBandLevel;
97 private int mEQPresetUserPos = 1;
Marco Nelissen66f2cfe2011-06-23 14:05:10 -070098 private int mEQPreset;
99 private int mEQPresetPrevious;
100 private int[] mEQPresetUserBandLevelsPrev;
Marco Nelissenc4724442011-06-30 12:07:50 -0700101 private String[] mEQPresetNames;
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700102
103 private int mPRPreset;
Marco Nelissene7de6512011-08-18 11:13:20 -0700104 private int mPRPresetPrevious;
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700105
106 private boolean mIsHeadsetOn = false;
Marco Nelissen709c4152011-10-31 13:45:46 -0700107 private CompoundButton mToggleSwitch;
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700108
Marco Nelissenf3b27982011-06-28 12:20:14 -0700109 private StringBuilder mFormatBuilder = new StringBuilder();
110 private Formatter mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
111
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700112 /**
113 * Mapping for the EQ widget ids per band
114 */
115 private static final int[][] EQViewElementIds = {
Marco Nelissenc4724442011-06-30 12:07:50 -0700116 { 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 } };
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700148
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
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;
gaoyl199708430a82015-07-14 11:23:08 +0800253 if (effect.uuid.equals(UUID.fromString("1d4033c0-8557-11df-9f2d-0002a5d5c51b"))) {
Marco Nelissen1c9259e2012-10-11 09:18:45 -0700254 mVirtualizerIsHeadphoneOnly = true;
255 }
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700256 } 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);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700267
Marco Nelissenc4724442011-06-30 12:07:50 -0700268 // 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
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700281 // 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.
Marco Nelissen709c4152011-10-31 13:45:46 -0700287 mToggleSwitch = new Switch(this);
288 mToggleSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700289 @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
Marco Nelissen29daf212011-06-30 14:52:07 -0700298 setEnabledAllChildren(viewGroup, isChecked);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700299 // update UI according to headset state
300 updateUIHeadset();
301 }
302 });
303
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700304 // 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) {
Marco Nelissen84c2c6c2011-06-29 13:21:58 -0700312 if (event.getAction() == MotionEvent.ACTION_UP) {
313 showHeadsetMsg();
314 }
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700315 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 });
Marco Nelissenbc778ed2012-10-11 17:37:03 -0700354
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 });
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700364 }
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) {
Marco Nelissen84c2c6c2011-06-29 13:21:58 -0700374 if (event.getAction() == MotionEvent.ACTION_UP) {
375 showHeadsetMsg();
376 }
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700377 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) {
Marco Nelissene7de6512011-08-18 11:13:20 -0700421 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));
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700429 }
430
431 // Initialize the Preset Reverb elements.
432 // Set Spinner listeners.
433 if (mPresetReverbSupported) {
Marco Nelissene7de6512011-08-18 11:13:20 -0700434 mPRPreset = ControlPanelEffect.getParameterInt(mContext, mCallingPackageName,
435 mAudioSession, ControlPanelEffect.Key.pr_current_preset);
436 mPRPresetPrevious = mPRPreset;
437 reverbSpinnerInit((Spinner)findViewById(R.id.prSpinner));
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700438 }
439
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700440 } else {
441 viewGroup.setVisibility(View.GONE);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700442 ((TextView) findViewById(R.id.noEffectsTextView)).setVisibility(View.VISIBLE);
443 }
Marco Nelissen84c2c6c2011-06-29 13:21:58 -0700444
Marco Nelissen709c4152011-10-31 13:45:46 -0700445 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);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700454 }
455
456 /*
457 * (non-Javadoc)
458 *
459 * @see android.app.Activity#onResume()
460 */
461 @Override
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
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
Marco Nelissene7de6512011-08-18 11:13:20 -0700497 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() {
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700503
Marco Nelissene7de6512011-08-18 11:13:20 -0700504 @Override
505 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
506 if (position != mPRPresetPrevious) {
507 presetReverbSetPreset(position);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700508 }
Marco Nelissene7de6512011-08-18 11:13:20 -0700509 mPRPresetPrevious = position;
Marco Nelissen74317202011-07-01 14:00:37 -0700510 }
Marco Nelissene7de6512011-08-18 11:13:20 -0700511
512 @Override
513 public void onNothingSelected(AdapterView<?> parent) {
514 }
515 });
516 spinner.setSelection(mPRPreset);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700517 }
518
Marco Nelissene7de6512011-08-18 11:13:20 -0700519 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
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700542 /**
Marco Nelissen29daf212011-06-30 14:52:07 -0700543 * En/disables all children for a given view. For linear and relative layout children do this
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700544 * recursively
545 *
Marco Nelissen29daf212011-06-30 14:52:07 -0700546 * @param viewGroup
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700547 * @param enabled
548 */
Marco Nelissen29daf212011-06-30 14:52:07 -0700549 private void setEnabledAllChildren(final ViewGroup viewGroup, final boolean enabled) {
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700550 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;
Marco Nelissen29daf212011-06-30 14:52:07 -0700555 setEnabledAllChildren(vg, enabled);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700556 }
557 view.setEnabled(enabled);
558 }
559 }
560
561 /**
562 * Updates UI (checkbox, seekbars, enabled states) according to the current stored preferences.
563 */
564 private void updateUI() {
565 final boolean isEnabled = ControlPanelEffect.getParameterBoolean(mContext,
566 mCallingPackageName, mAudioSession, ControlPanelEffect.Key.global_enabled);
Marco Nelissen709c4152011-10-31 13:45:46 -0700567 mToggleSwitch.setChecked(isEnabled);
Marco Nelissen29daf212011-06-30 14:52:07 -0700568 setEnabledAllChildren((ViewGroup) findViewById(R.id.contentSoundEffects), isEnabled);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700569 updateUIHeadset();
570
571 if (mVirtualizerSupported) {
Marco Nelissenbc778ed2012-10-11 17:37:03 -0700572 SeekBar bar = (SeekBar) findViewById(R.id.vIStrengthSeekBar);
573 Switch sw = (Switch) findViewById(R.id.vIStrengthToggle);
574 int strength = ControlPanelEffect
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700575 .getParameterInt(mContext, mCallingPackageName, mAudioSession,
Marco Nelissenbc778ed2012-10-11 17:37:03 -0700576 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 }
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700587 }
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) {
Marco Nelissen84c2c6c2011-06-29 13:21:58 -0700594 equalizerUpdateDisplay();
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700595 }
596 if (mPresetReverbSupported) {
Marco Nelissene7de6512011-08-18 11:13:20 -0700597 int reverb = ControlPanelEffect.getParameterInt(
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700598 mContext, mCallingPackageName, mAudioSession,
Marco Nelissene7de6512011-08-18 11:13:20 -0700599 ControlPanelEffect.Key.pr_current_preset);
600 ((Spinner)findViewById(R.id.prSpinner)).setSelection(reverb);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700601 }
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 */
609 private void updateUIHeadset() {
Marco Nelissen709c4152011-10-31 13:45:46 -0700610 if (mToggleSwitch.isChecked()) {
Marco Nelissen1c9259e2012-10-11 09:18:45 -0700611 ((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);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700616 ((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 */
Marco Nelissene7de6512011-08-18 11:13:20 -0700625 private void equalizerBandsInit(View eqcontainer) {
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700626 // 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 }
Marco Nelissen84c2c6c2011-06-29 13:21:58 -0700648 ((TextView) eqcontainer.findViewById(EQViewElementIds[band][0])).setText(
Marco Nelissenf3b27982011-06-28 12:20:14 -0700649 format("%.0f ", centerFreqHz) + unitPrefix + "Hz");
Marco Nelissen84c2c6c2011-06-29 13:21:58 -0700650 mEqualizerSeekBar[band] = (SeekBar) eqcontainer
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700651 .findViewById(EQViewElementIds[band][1]);
652 mEqualizerSeekBar[band].setMax(mEqualizerMaxBandLevel - mEqualizerMinBandLevel);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700653 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
Marco Nelissen84c2c6c2011-06-29 13:21:58 -0700659 eqcontainer.findViewById(EQViewElementIds[band][0]).setVisibility(View.GONE);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700660 // SeekBar
Marco Nelissen84c2c6c2011-06-29 13:21:58 -0700661 eqcontainer.findViewById(EQViewElementIds[band][1]).setVisibility(View.GONE);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700662 }
Marco Nelissenc4724442011-06-30 12:07:50 -0700663
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");
Marco Nelissen84c2c6c2011-06-29 13:21:58 -0700671 equalizerUpdateDisplay();
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700672 }
673
Marco Nelissenf3b27982011-06-28 12:20:14 -0700674 private String format(String format, Object... args) {
675 mFormatBuilder.setLength(0);
676 mFormatter.format(format, args);
677 return mFormatBuilder.toString();
678 }
679
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700680 /*
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
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);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700696 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
712 public void onStartTrackingTouch(final SeekBar seekbar) {
Marco Nelissenc4724442011-06-30 12:07:50 -0700713 // 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);
Marco Nelissen9c373072011-10-31 15:09:10 -0700721 ((Spinner)findViewById(R.id.eqSpinner)).setSelection(mEQPresetUserPos);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700722 }
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
734 public void onStopTrackingTouch(final SeekBar seekbar) {
735 equalizerUpdateDisplay();
736 }
737
738 /**
739 * Updates the EQ by getting the parameters.
740 */
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];
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700747 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 */
Marco Nelissenc4724442011-06-30 12:07:50 -0700760 private void equalizerBandUpdate(final int band, final int level) {
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700761 ControlPanelEffect.setParameterInt(mContext, mCallingPackageName, mAudioSession,
762 ControlPanelEffect.Key.eq_band_level, level, band);
763 }
764
765 /**
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700766 * Sets the given EQ preset.
767 *
768 * @param preset
769 * EQ preset id.
770 */
771 private void equalizerSetPreset(final int preset) {
Marco Nelissenc4724442011-06-30 12:07:50 -0700772 ControlPanelEffect.setParameterInt(mContext, mCallingPackageName, mAudioSession,
773 ControlPanelEffect.Key.eq_current_preset, preset);
774 equalizerUpdateDisplay();
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700775 }
776
777 /**
778 * Sets the given PR preset.
779 *
780 * @param preset
781 * PR preset id.
782 */
783 private void presetReverbSetPreset(final int preset) {
Marco Nelissene7de6512011-08-18 11:13:20 -0700784 ControlPanelEffect.setParameterInt(mContext, mCallingPackageName, mAudioSession,
785 ControlPanelEffect.Key.pr_current_preset, preset);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700786 }
787
788 /**
789 * Show msg that headset needs to be plugged.
790 */
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 }
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700799}