blob: 328a9230e01382bf48dddea37a3f0789b81315aa [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;
Marco Nelissenc4724442011-06-30 12:07:50 -070020
Marco Nelissen709c4152011-10-31 13:45:46 -070021import android.app.ActionBar;
Marco Nelissen66f2cfe2011-06-23 14:05:10 -070022import android.app.Activity;
23import android.app.AlertDialog;
24import android.app.Dialog;
25import android.bluetooth.BluetoothClass;
26import android.bluetooth.BluetoothDevice;
27import android.content.BroadcastReceiver;
28import android.content.Context;
29import android.content.DialogInterface;
30import android.content.DialogInterface.OnCancelListener;
31import android.content.Intent;
32import android.content.IntentFilter;
33import android.media.AudioManager;
34import android.media.audiofx.AudioEffect;
35import android.media.audiofx.AudioEffect.Descriptor;
36import android.os.Bundle;
37import android.util.Log;
38import android.view.Gravity;
39import android.view.LayoutInflater;
Marco Nelissen66f2cfe2011-06-23 14:05:10 -070040import android.view.MotionEvent;
41import android.view.View;
42import android.view.View.OnClickListener;
43import android.view.View.OnTouchListener;
44import android.view.ViewGroup;
Marco Nelissene7de6512011-08-18 11:13:20 -070045import android.widget.AdapterView;
46import android.widget.AdapterView.OnItemSelectedListener;
47import android.widget.ArrayAdapter;
Marco Nelissen66f2cfe2011-06-23 14:05:10 -070048import android.widget.CompoundButton;
49import android.widget.CompoundButton.OnCheckedChangeListener;
50import android.widget.LinearLayout;
51import android.widget.ListView;
52import android.widget.RelativeLayout;
Filipe Gonçalves09156c62016-05-31 13:47:09 +010053import android.widget.SeekBar;
54import android.widget.SeekBar.OnSeekBarChangeListener;
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 /**
Filipe Gonçalves09156c62016-05-31 13:47:09 +010076 * Max levels per EQ band in millibels (1 dB = 100 mB)
77 */
78 private final static int EQUALIZER_MAX_LEVEL = 1000;
79
80 /**
81 * Min levels per EQ band in millibels (1 dB = 100 mB)
82 */
83 private final static int EQUALIZER_MIN_LEVEL = -1000;
84
85 /**
Marco Nelissen66f2cfe2011-06-23 14:05:10 -070086 * Indicates if Virtualizer effect is supported.
87 */
88 private boolean mVirtualizerSupported;
Marco Nelissen1c9259e2012-10-11 09:18:45 -070089 private boolean mVirtualizerIsHeadphoneOnly;
Marco Nelissen66f2cfe2011-06-23 14:05:10 -070090 /**
91 * Indicates if BassBoost effect is supported.
92 */
93 private boolean mBassBoostSupported;
94 /**
95 * Indicates if Equalizer effect is supported.
96 */
97 private boolean mEqualizerSupported;
98 /**
99 * Indicates if Preset Reverb effect is supported.
100 */
101 private boolean mPresetReverbSupported;
102
103 // Equalizer fields
104 private final SeekBar[] mEqualizerSeekBar = new SeekBar[EQUALIZER_MAX_BANDS];
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700105 private int mNumberEqualizerBands;
106 private int mEqualizerMinBandLevel;
107 private int mEQPresetUserPos = 1;
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700108 private int mEQPreset;
109 private int mEQPresetPrevious;
110 private int[] mEQPresetUserBandLevelsPrev;
Marco Nelissenc4724442011-06-30 12:07:50 -0700111 private String[] mEQPresetNames;
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700112
113 private int mPRPreset;
Marco Nelissene7de6512011-08-18 11:13:20 -0700114 private int mPRPresetPrevious;
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700115
116 private boolean mIsHeadsetOn = false;
Marco Nelissen709c4152011-10-31 13:45:46 -0700117 private CompoundButton mToggleSwitch;
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700118
Marco Nelissenf3b27982011-06-28 12:20:14 -0700119 private StringBuilder mFormatBuilder = new StringBuilder();
120 private Formatter mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
121
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700122 /**
123 * Mapping for the EQ widget ids per band
124 */
125 private static final int[][] EQViewElementIds = {
Marco Nelissenc4724442011-06-30 12:07:50 -0700126 { R.id.EQBand0TextView, R.id.EQBand0SeekBar },
127 { R.id.EQBand1TextView, R.id.EQBand1SeekBar },
128 { R.id.EQBand2TextView, R.id.EQBand2SeekBar },
129 { R.id.EQBand3TextView, R.id.EQBand3SeekBar },
130 { R.id.EQBand4TextView, R.id.EQBand4SeekBar },
131 { R.id.EQBand5TextView, R.id.EQBand5SeekBar },
132 { R.id.EQBand6TextView, R.id.EQBand6SeekBar },
133 { R.id.EQBand7TextView, R.id.EQBand7SeekBar },
134 { R.id.EQBand8TextView, R.id.EQBand8SeekBar },
135 { R.id.EQBand9TextView, R.id.EQBand9SeekBar },
136 { R.id.EQBand10TextView, R.id.EQBand10SeekBar },
137 { R.id.EQBand11TextView, R.id.EQBand11SeekBar },
138 { R.id.EQBand12TextView, R.id.EQBand12SeekBar },
139 { R.id.EQBand13TextView, R.id.EQBand13SeekBar },
140 { R.id.EQBand14TextView, R.id.EQBand14SeekBar },
141 { R.id.EQBand15TextView, R.id.EQBand15SeekBar },
142 { R.id.EQBand16TextView, R.id.EQBand16SeekBar },
143 { R.id.EQBand17TextView, R.id.EQBand17SeekBar },
144 { R.id.EQBand18TextView, R.id.EQBand18SeekBar },
145 { R.id.EQBand19TextView, R.id.EQBand19SeekBar },
146 { R.id.EQBand20TextView, R.id.EQBand20SeekBar },
147 { R.id.EQBand21TextView, R.id.EQBand21SeekBar },
148 { R.id.EQBand22TextView, R.id.EQBand22SeekBar },
149 { R.id.EQBand23TextView, R.id.EQBand23SeekBar },
150 { R.id.EQBand24TextView, R.id.EQBand24SeekBar },
151 { R.id.EQBand25TextView, R.id.EQBand25SeekBar },
152 { R.id.EQBand26TextView, R.id.EQBand26SeekBar },
153 { R.id.EQBand27TextView, R.id.EQBand27SeekBar },
154 { R.id.EQBand28TextView, R.id.EQBand28SeekBar },
155 { R.id.EQBand29TextView, R.id.EQBand29SeekBar },
156 { R.id.EQBand30TextView, R.id.EQBand30SeekBar },
157 { R.id.EQBand31TextView, R.id.EQBand31SeekBar } };
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700158
159 // Preset Reverb fields
160 /**
161 * Array containing the PR preset names.
162 */
163 private static final String[] PRESETREVERBPRESETSTRINGS = { "None", "SmallRoom", "MediumRoom",
164 "LargeRoom", "MediumHall", "LargeHall", "Plate" };
165
166 /**
167 * Context field
168 */
169 private Context mContext;
170
171 /**
172 * Calling package name field
173 */
174 private String mCallingPackageName = "empty";
175
176 /**
177 * Audio session field
178 */
179 private int mAudioSession = AudioEffect.ERROR_BAD_VALUE;
180
181 // Broadcast receiver to handle wired and Bluetooth A2dp headset events
182 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
183 @Override
184 public void onReceive(final Context context, final Intent intent) {
185 final String action = intent.getAction();
186 final boolean isHeadsetOnPrev = mIsHeadsetOn;
187 final AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
188 if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
189 mIsHeadsetOn = (intent.getIntExtra("state", 0) == 1)
190 || audioManager.isBluetoothA2dpOn();
191 } else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
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 = true;
198 }
199 } else if (action.equals(AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
200 mIsHeadsetOn = audioManager.isBluetoothA2dpOn() || audioManager.isWiredHeadsetOn();
201 } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
202 final int deviceClass = ((BluetoothDevice) intent
203 .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)).getBluetoothClass()
204 .getDeviceClass();
205 if ((deviceClass == BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES)
206 || (deviceClass == BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET)) {
207 mIsHeadsetOn = audioManager.isWiredHeadsetOn();
208 }
209 }
210 if (isHeadsetOnPrev != mIsHeadsetOn) {
211 updateUIHeadset();
212 }
213 }
214 };
215
216 /*
217 * Declares and initializes all objects and widgets in the layouts and the CheckBox and SeekBar
218 * onchange methods on creation.
219 *
220 * (non-Javadoc)
221 *
222 * @see android.app.ActivityGroup#onCreate(android.os.Bundle)
223 */
224 @Override
225 public void onCreate(final Bundle savedInstanceState) {
226 super.onCreate(savedInstanceState);
227
228 // Init context to be used in listeners
229 mContext = this;
230
231 // Receive intent
232 // get calling intent
233 final Intent intent = getIntent();
234 mAudioSession = intent.getIntExtra(AudioEffect.EXTRA_AUDIO_SESSION,
235 AudioEffect.ERROR_BAD_VALUE);
236 Log.v(TAG, "audio session: " + mAudioSession);
237
238 mCallingPackageName = getCallingPackage();
239
240 // check for errors
241 if (mCallingPackageName == null) {
242 Log.e(TAG, "Package name is null");
243 setResult(RESULT_CANCELED);
244 finish();
245 return;
246 }
247 setResult(RESULT_OK);
248
249 Log.v(TAG, mCallingPackageName + " (" + mAudioSession + ")");
250
251 ControlPanelEffect.initEffectsPreferences(mContext, mCallingPackageName, mAudioSession);
252
253 // query available effects
254 final Descriptor[] effects = AudioEffect.queryEffects();
255
256 // Determine available/supported effects
257 Log.v(TAG, "Available effects:");
258 for (final Descriptor effect : effects) {
259 Log.v(TAG, effect.name.toString() + ", type: " + effect.type.toString());
260
261 if (effect.type.equals(AudioEffect.EFFECT_TYPE_VIRTUALIZER)) {
262 mVirtualizerSupported = true;
gaoyl199708430a82015-07-14 11:23:08 +0800263 if (effect.uuid.equals(UUID.fromString("1d4033c0-8557-11df-9f2d-0002a5d5c51b"))) {
Marco Nelissen1c9259e2012-10-11 09:18:45 -0700264 mVirtualizerIsHeadphoneOnly = true;
265 }
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700266 } else if (effect.type.equals(AudioEffect.EFFECT_TYPE_BASS_BOOST)) {
267 mBassBoostSupported = true;
268 } else if (effect.type.equals(AudioEffect.EFFECT_TYPE_EQUALIZER)) {
269 mEqualizerSupported = true;
270 } else if (effect.type.equals(AudioEffect.EFFECT_TYPE_PRESET_REVERB)) {
271 mPresetReverbSupported = true;
272 }
273 }
274
275 setContentView(R.layout.music_main);
276 final ViewGroup viewGroup = (ViewGroup) findViewById(R.id.contentSoundEffects);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700277
Marco Nelissenc4724442011-06-30 12:07:50 -0700278 // Fill array with presets from AudioEffects call.
279 // allocate a space for 2 extra strings (CI Extreme & User)
280 final int numPresets = ControlPanelEffect.getParameterInt(mContext, mCallingPackageName,
281 mAudioSession, ControlPanelEffect.Key.eq_num_presets);
282 mEQPresetNames = new String[numPresets + 2];
283 for (short i = 0; i < numPresets; i++) {
284 mEQPresetNames[i] = ControlPanelEffect.getParameterString(mContext,
285 mCallingPackageName, mAudioSession, ControlPanelEffect.Key.eq_preset_name, i);
286 }
287 mEQPresetNames[numPresets] = getString(R.string.ci_extreme);
288 mEQPresetNames[numPresets + 1] = getString(R.string.user);
289 mEQPresetUserPos = numPresets + 1;
290
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700291 // Watch for button clicks and initialization.
292 if ((mVirtualizerSupported) || (mBassBoostSupported) || (mEqualizerSupported)
293 || (mPresetReverbSupported)) {
294 // Set the listener for the main enhancements toggle button.
295 // Depending on the state enable the supported effects if they were
296 // checked in the setup tab.
Marco Nelissen709c4152011-10-31 13:45:46 -0700297 mToggleSwitch = new Switch(this);
298 mToggleSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700299 @Override
300 public void onCheckedChanged(final CompoundButton buttonView,
301 final boolean isChecked) {
302
303 // set parameter and state
304 ControlPanelEffect.setParameterBoolean(mContext, mCallingPackageName,
305 mAudioSession, ControlPanelEffect.Key.global_enabled, isChecked);
306 // Enable Linear layout (in scroll layout) view with all
307 // effect contents depending on checked state
Marco Nelissen29daf212011-06-30 14:52:07 -0700308 setEnabledAllChildren(viewGroup, isChecked);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700309 // update UI according to headset state
310 updateUIHeadset();
311 }
312 });
313
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700314 // Initialize the Virtualizer elements.
315 // Set the SeekBar listener.
316 if (mVirtualizerSupported) {
317 // Show msg when disabled slider (layout) is touched
318 findViewById(R.id.vILayout).setOnTouchListener(new OnTouchListener() {
319
320 @Override
321 public boolean onTouch(final View v, final MotionEvent event) {
Marco Nelissen84c2c6c2011-06-29 13:21:58 -0700322 if (event.getAction() == MotionEvent.ACTION_UP) {
323 showHeadsetMsg();
324 }
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700325 return false;
326 }
327 });
328
329 final SeekBar seekbar = (SeekBar) findViewById(R.id.vIStrengthSeekBar);
330 seekbar.setMax(OpenSLESConstants.VIRTUALIZER_MAX_STRENGTH
331 - OpenSLESConstants.VIRTUALIZER_MIN_STRENGTH);
332
333 seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
334 // Update the parameters while SeekBar changes and set the
335 // effect parameter.
336
337 @Override
338 public void onProgressChanged(final SeekBar seekBar, final int progress,
339 final boolean fromUser) {
340 // set parameter and state
341 ControlPanelEffect.setParameterInt(mContext, mCallingPackageName,
342 mAudioSession, ControlPanelEffect.Key.virt_strength, progress);
343 }
344
345 // If slider pos was 0 when starting re-enable effect
346 @Override
347 public void onStartTrackingTouch(final SeekBar seekBar) {
348 if (seekBar.getProgress() == 0) {
349 ControlPanelEffect.setParameterBoolean(mContext, mCallingPackageName,
350 mAudioSession, ControlPanelEffect.Key.virt_enabled, true);
351 }
352 }
353
354 // If slider pos = 0 when stopping disable effect
355 @Override
356 public void onStopTrackingTouch(final SeekBar seekBar) {
357 if (seekBar.getProgress() == 0) {
358 // disable
359 ControlPanelEffect.setParameterBoolean(mContext, mCallingPackageName,
360 mAudioSession, ControlPanelEffect.Key.virt_enabled, false);
361 }
362 }
363 });
Marco Nelissenbc778ed2012-10-11 17:37:03 -0700364
365 final Switch sw = (Switch) findViewById(R.id.vIStrengthToggle);
366 sw.setOnCheckedChangeListener(new OnCheckedChangeListener() {
367 @Override
368 public void onCheckedChanged(final CompoundButton buttonView,
369 final boolean isChecked) {
370 ControlPanelEffect.setParameterBoolean(mContext, mCallingPackageName,
371 mAudioSession, ControlPanelEffect.Key.virt_enabled, isChecked);
372 }
373 });
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700374 }
375
376 // Initialize the Bass Boost elements.
377 // Set the SeekBar listener.
378 if (mBassBoostSupported) {
379 // Show msg when disabled slider (layout) is touched
380 findViewById(R.id.bBLayout).setOnTouchListener(new OnTouchListener() {
381
382 @Override
383 public boolean onTouch(final View v, final MotionEvent event) {
Marco Nelissen84c2c6c2011-06-29 13:21:58 -0700384 if (event.getAction() == MotionEvent.ACTION_UP) {
385 showHeadsetMsg();
386 }
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700387 return false;
388 }
389 });
390
391 final SeekBar seekbar = (SeekBar) findViewById(R.id.bBStrengthSeekBar);
392 seekbar.setMax(OpenSLESConstants.BASSBOOST_MAX_STRENGTH
393 - OpenSLESConstants.BASSBOOST_MIN_STRENGTH);
394
395 seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
396 // Update the parameters while SeekBar changes and set the
397 // effect parameter.
398
399 @Override
400 public void onProgressChanged(final SeekBar seekBar, final int progress,
401 final boolean fromUser) {
402 // set parameter and state
403 ControlPanelEffect.setParameterInt(mContext, mCallingPackageName,
404 mAudioSession, ControlPanelEffect.Key.bb_strength, progress);
405 }
406
407 // If slider pos was 0 when starting re-enable effect
408 @Override
409 public void onStartTrackingTouch(final SeekBar seekBar) {
410 if (seekBar.getProgress() == 0) {
411 ControlPanelEffect.setParameterBoolean(mContext, mCallingPackageName,
412 mAudioSession, ControlPanelEffect.Key.bb_enabled, true);
413 }
414 }
415
416 // If slider pos = 0 when stopping disable effect
417 @Override
418 public void onStopTrackingTouch(final SeekBar seekBar) {
419 if (seekBar.getProgress() == 0) {
420 // disable
421 ControlPanelEffect.setParameterBoolean(mContext, mCallingPackageName,
422 mAudioSession, ControlPanelEffect.Key.bb_enabled, false);
423 }
424
425 }
426 });
427 }
428
429 // Initialize the Equalizer elements.
430 if (mEqualizerSupported) {
Marco Nelissene7de6512011-08-18 11:13:20 -0700431 mEQPreset = ControlPanelEffect.getParameterInt(mContext, mCallingPackageName,
432 mAudioSession, ControlPanelEffect.Key.eq_current_preset);
433 if (mEQPreset >= mEQPresetNames.length) {
434 mEQPreset = 0;
435 }
436 mEQPresetPrevious = mEQPreset;
437 equalizerSpinnerInit((Spinner)findViewById(R.id.eqSpinner));
438 equalizerBandsInit(findViewById(R.id.eqcontainer));
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700439 }
440
441 // Initialize the Preset Reverb elements.
442 // Set Spinner listeners.
443 if (mPresetReverbSupported) {
Marco Nelissene7de6512011-08-18 11:13:20 -0700444 mPRPreset = ControlPanelEffect.getParameterInt(mContext, mCallingPackageName,
445 mAudioSession, ControlPanelEffect.Key.pr_current_preset);
446 mPRPresetPrevious = mPRPreset;
447 reverbSpinnerInit((Spinner)findViewById(R.id.prSpinner));
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700448 }
449
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700450 } else {
451 viewGroup.setVisibility(View.GONE);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700452 ((TextView) findViewById(R.id.noEffectsTextView)).setVisibility(View.VISIBLE);
453 }
Marco Nelissen84c2c6c2011-06-29 13:21:58 -0700454
Marco Nelissen709c4152011-10-31 13:45:46 -0700455 ActionBar ab = getActionBar();
456 final int padding = getResources().getDimensionPixelSize(
457 R.dimen.action_bar_switch_padding);
458 mToggleSwitch.setPadding(0,0, padding, 0);
459 ab.setCustomView(mToggleSwitch, new ActionBar.LayoutParams(
460 ActionBar.LayoutParams.WRAP_CONTENT,
461 ActionBar.LayoutParams.WRAP_CONTENT,
462 Gravity.CENTER_VERTICAL | Gravity.RIGHT));
463 ab.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700464 }
465
466 /*
467 * (non-Javadoc)
468 *
469 * @see android.app.Activity#onResume()
470 */
471 @Override
472 protected void onResume() {
473 super.onResume();
474 if ((mVirtualizerSupported) || (mBassBoostSupported) || (mEqualizerSupported)
475 || (mPresetReverbSupported)) {
476 // Listen for broadcast intents that might affect the onscreen UI for headset.
477 final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
478 intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
479 intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
480 intentFilter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
481 registerReceiver(mReceiver, intentFilter);
482
483 // Check if wired or Bluetooth headset is connected/on
484 final AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
485 mIsHeadsetOn = (audioManager.isWiredHeadsetOn() || audioManager.isBluetoothA2dpOn());
486 Log.v(TAG, "onResume: mIsHeadsetOn : " + mIsHeadsetOn);
487
488 // Update UI
489 updateUI();
490 }
491 }
492
493 /*
494 * (non-Javadoc)
495 *
496 * @see android.app.Activity#onPause()
497 */
498 @Override
499 protected void onPause() {
500 super.onPause();
501
502 // Unregister for broadcast intents. (These affect the visible UI,
503 // so we only care about them while we're in the foreground.)
504 unregisterReceiver(mReceiver);
505 }
506
Marco Nelissene7de6512011-08-18 11:13:20 -0700507 private void reverbSpinnerInit(Spinner spinner) {
508 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
509 android.R.layout.simple_spinner_item, PRESETREVERBPRESETSTRINGS);
510 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
511 spinner.setAdapter(adapter);
512 spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700513
Marco Nelissene7de6512011-08-18 11:13:20 -0700514 @Override
515 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
516 if (position != mPRPresetPrevious) {
517 presetReverbSetPreset(position);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700518 }
Marco Nelissene7de6512011-08-18 11:13:20 -0700519 mPRPresetPrevious = position;
Marco Nelissen74317202011-07-01 14:00:37 -0700520 }
Marco Nelissene7de6512011-08-18 11:13:20 -0700521
522 @Override
523 public void onNothingSelected(AdapterView<?> parent) {
524 }
525 });
526 spinner.setSelection(mPRPreset);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700527 }
528
Marco Nelissene7de6512011-08-18 11:13:20 -0700529 private void equalizerSpinnerInit(Spinner spinner) {
530 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
531 android.R.layout.simple_spinner_item, mEQPresetNames);
532 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
533 spinner.setAdapter(adapter);
534 spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
535
536 @Override
537 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
538 if (position != mEQPresetPrevious) {
539 equalizerSetPreset(position);
540 }
541 mEQPresetPrevious = position;
542 }
543
544 @Override
545 public void onNothingSelected(AdapterView<?> parent) {
546 }
547 });
548 spinner.setSelection(mEQPreset);
549 }
550
551
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700552 /**
Marco Nelissen29daf212011-06-30 14:52:07 -0700553 * En/disables all children for a given view. For linear and relative layout children do this
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700554 * recursively
555 *
Marco Nelissen29daf212011-06-30 14:52:07 -0700556 * @param viewGroup
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700557 * @param enabled
558 */
Marco Nelissen29daf212011-06-30 14:52:07 -0700559 private void setEnabledAllChildren(final ViewGroup viewGroup, final boolean enabled) {
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700560 final int count = viewGroup.getChildCount();
561 for (int i = 0; i < count; i++) {
562 final View view = viewGroup.getChildAt(i);
Filipe Gonçalves09156c62016-05-31 13:47:09 +0100563 if ((view instanceof ViewGroup)) {
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700564 final ViewGroup vg = (ViewGroup) view;
Marco Nelissen29daf212011-06-30 14:52:07 -0700565 setEnabledAllChildren(vg, enabled);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700566 }
567 view.setEnabled(enabled);
568 }
569 }
570
571 /**
572 * Updates UI (checkbox, seekbars, enabled states) according to the current stored preferences.
573 */
574 private void updateUI() {
575 final boolean isEnabled = ControlPanelEffect.getParameterBoolean(mContext,
576 mCallingPackageName, mAudioSession, ControlPanelEffect.Key.global_enabled);
Marco Nelissen709c4152011-10-31 13:45:46 -0700577 mToggleSwitch.setChecked(isEnabled);
Marco Nelissen29daf212011-06-30 14:52:07 -0700578 setEnabledAllChildren((ViewGroup) findViewById(R.id.contentSoundEffects), isEnabled);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700579 updateUIHeadset();
580
581 if (mVirtualizerSupported) {
Marco Nelissenbc778ed2012-10-11 17:37:03 -0700582 SeekBar bar = (SeekBar) findViewById(R.id.vIStrengthSeekBar);
583 Switch sw = (Switch) findViewById(R.id.vIStrengthToggle);
584 int strength = ControlPanelEffect
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700585 .getParameterInt(mContext, mCallingPackageName, mAudioSession,
Marco Nelissenbc778ed2012-10-11 17:37:03 -0700586 ControlPanelEffect.Key.virt_strength);
587 bar.setProgress(strength);
588 boolean hasStrength = ControlPanelEffect.getParameterBoolean(mContext,
589 mCallingPackageName, mAudioSession,
590 ControlPanelEffect.Key.virt_strength_supported);
591 if (hasStrength) {
592 sw.setVisibility(View.GONE);
593 } else {
594 bar.setVisibility(View.GONE);
595 sw.setChecked(sw.isEnabled() && strength != 0);
596 }
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700597 }
598 if (mBassBoostSupported) {
599 ((SeekBar) findViewById(R.id.bBStrengthSeekBar)).setProgress(ControlPanelEffect
600 .getParameterInt(mContext, mCallingPackageName, mAudioSession,
601 ControlPanelEffect.Key.bb_strength));
602 }
603 if (mEqualizerSupported) {
Marco Nelissen84c2c6c2011-06-29 13:21:58 -0700604 equalizerUpdateDisplay();
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700605 }
606 if (mPresetReverbSupported) {
Marco Nelissene7de6512011-08-18 11:13:20 -0700607 int reverb = ControlPanelEffect.getParameterInt(
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700608 mContext, mCallingPackageName, mAudioSession,
Marco Nelissene7de6512011-08-18 11:13:20 -0700609 ControlPanelEffect.Key.pr_current_preset);
610 ((Spinner)findViewById(R.id.prSpinner)).setSelection(reverb);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700611 }
612 }
613
614 /**
615 * Updates UI for headset mode. En/disable VI and BB controls depending on headset state
616 * (on/off) if effects are on. Do the inverse for their layouts so they can take over
617 * control/events.
618 */
619 private void updateUIHeadset() {
Marco Nelissen709c4152011-10-31 13:45:46 -0700620 if (mToggleSwitch.isChecked()) {
Marco Nelissen1c9259e2012-10-11 09:18:45 -0700621 ((TextView) findViewById(R.id.vIStrengthText)).setEnabled(
622 mIsHeadsetOn || !mVirtualizerIsHeadphoneOnly);
623 ((SeekBar) findViewById(R.id.vIStrengthSeekBar)).setEnabled(
624 mIsHeadsetOn || !mVirtualizerIsHeadphoneOnly);
625 findViewById(R.id.vILayout).setEnabled(!mIsHeadsetOn || !mVirtualizerIsHeadphoneOnly);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700626 ((TextView) findViewById(R.id.bBStrengthText)).setEnabled(mIsHeadsetOn);
627 ((SeekBar) findViewById(R.id.bBStrengthSeekBar)).setEnabled(mIsHeadsetOn);
628 findViewById(R.id.bBLayout).setEnabled(!mIsHeadsetOn);
629 }
630 }
631
632 /**
633 * Initializes the equalizer elements. Set the SeekBars and Spinner listeners.
634 */
Marco Nelissene7de6512011-08-18 11:13:20 -0700635 private void equalizerBandsInit(View eqcontainer) {
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700636 // Initialize the N-Band Equalizer elements.
637 mNumberEqualizerBands = ControlPanelEffect.getParameterInt(mContext, mCallingPackageName,
638 mAudioSession, ControlPanelEffect.Key.eq_num_bands);
639 mEQPresetUserBandLevelsPrev = ControlPanelEffect.getParameterIntArray(mContext,
640 mCallingPackageName, mAudioSession,
641 ControlPanelEffect.Key.eq_preset_user_band_level);
642 final int[] centerFreqs = ControlPanelEffect.getParameterIntArray(mContext,
643 mCallingPackageName, mAudioSession, ControlPanelEffect.Key.eq_center_freq);
644 final int[] bandLevelRange = ControlPanelEffect.getParameterIntArray(mContext,
645 mCallingPackageName, mAudioSession, ControlPanelEffect.Key.eq_level_range);
Filipe Gonçalves09156c62016-05-31 13:47:09 +0100646 mEqualizerMinBandLevel = (int) Math.max(EQUALIZER_MIN_LEVEL, bandLevelRange[0]);
647 final int mEqualizerMaxBandLevel = (int) Math.min(EQUALIZER_MAX_LEVEL, bandLevelRange[1]);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700648
649 for (int band = 0; band < mNumberEqualizerBands; band++) {
650 // Unit conversion from mHz to Hz and use k prefix if necessary to display
651 final int centerFreq = centerFreqs[band] / 1000;
652 float centerFreqHz = centerFreq;
653 String unitPrefix = "";
654 if (centerFreqHz >= 1000) {
655 centerFreqHz = centerFreqHz / 1000;
656 unitPrefix = "k";
657 }
Marco Nelissen84c2c6c2011-06-29 13:21:58 -0700658 ((TextView) eqcontainer.findViewById(EQViewElementIds[band][0])).setText(
Marco Nelissenf3b27982011-06-28 12:20:14 -0700659 format("%.0f ", centerFreqHz) + unitPrefix + "Hz");
Marco Nelissen84c2c6c2011-06-29 13:21:58 -0700660 mEqualizerSeekBar[band] = (SeekBar) eqcontainer
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700661 .findViewById(EQViewElementIds[band][1]);
662 mEqualizerSeekBar[band].setMax(mEqualizerMaxBandLevel - mEqualizerMinBandLevel);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700663 mEqualizerSeekBar[band].setOnSeekBarChangeListener(this);
664 }
665
666 // Hide the inactive Equalizer bands.
667 for (int band = mNumberEqualizerBands; band < EQUALIZER_MAX_BANDS; band++) {
668 // CenterFreq text
Marco Nelissen84c2c6c2011-06-29 13:21:58 -0700669 eqcontainer.findViewById(EQViewElementIds[band][0]).setVisibility(View.GONE);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700670 // SeekBar
Marco Nelissen84c2c6c2011-06-29 13:21:58 -0700671 eqcontainer.findViewById(EQViewElementIds[band][1]).setVisibility(View.GONE);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700672 }
Marco Nelissenc4724442011-06-30 12:07:50 -0700673
Marco Nelissenc4724442011-06-30 12:07:50 -0700674 TextView tv = (TextView) findViewById(R.id.maxLevelText);
Filipe Gonçalves09156c62016-05-31 13:47:09 +0100675 tv.setText(String.format("+%d dB", (int) Math.ceil(mEqualizerMaxBandLevel / 100)));
Marco Nelissenc4724442011-06-30 12:07:50 -0700676 tv = (TextView) findViewById(R.id.centerLevelText);
677 tv.setText("0 dB");
678 tv = (TextView) findViewById(R.id.minLevelText);
Filipe Gonçalves09156c62016-05-31 13:47:09 +0100679 tv.setText(String.format("%d dB", (int) Math.floor(mEqualizerMinBandLevel / 100)));
Marco Nelissen84c2c6c2011-06-29 13:21:58 -0700680 equalizerUpdateDisplay();
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700681 }
682
Marco Nelissenf3b27982011-06-28 12:20:14 -0700683 private String format(String format, Object... args) {
684 mFormatBuilder.setLength(0);
685 mFormatter.format(format, args);
686 return mFormatBuilder.toString();
687 }
688
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700689 /*
690 * For the EQ Band SeekBars
691 *
692 * (non-Javadoc)
693 *
694 * @see android.widget.SeekBar.OnSeekBarChangeListener#onProgressChanged(android
695 * .widget.SeekBar, int, boolean)
696 */
697
698 @Override
699 public void onProgressChanged(final SeekBar seekbar, final int progress, final boolean fromUser) {
700 final int id = seekbar.getId();
701
702 for (short band = 0; band < mNumberEqualizerBands; band++) {
703 if (id == EQViewElementIds[band][1]) {
704 final short level = (short) (progress + mEqualizerMinBandLevel);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700705 if (fromUser) {
706 equalizerBandUpdate(band, level);
707 }
708 break;
709 }
710 }
711 }
712
713 /*
714 * (non-Javadoc)
715 *
716 * @see android.widget.SeekBar.OnSeekBarChangeListener#onStartTrackingTouch(android
717 * .widget.SeekBar)
718 */
719
720 @Override
721 public void onStartTrackingTouch(final SeekBar seekbar) {
Marco Nelissenc4724442011-06-30 12:07:50 -0700722 // get current levels
723 final int[] bandLevels = ControlPanelEffect.getParameterIntArray(mContext,
724 mCallingPackageName, mAudioSession, ControlPanelEffect.Key.eq_band_level);
725 // copy current levels to user preset
726 for (short band = 0; band < mNumberEqualizerBands; band++) {
727 equalizerBandUpdate(band, bandLevels[band]);
728 }
729 equalizerSetPreset(mEQPresetUserPos);
Marco Nelissen9c373072011-10-31 15:09:10 -0700730 ((Spinner)findViewById(R.id.eqSpinner)).setSelection(mEQPresetUserPos);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700731 }
732
733 /*
734 * Updates the EQ display when the user stops changing.
735 *
736 * (non-Javadoc)
737 *
738 * @see android.widget.SeekBar.OnSeekBarChangeListener#onStopTrackingTouch(android
739 * .widget.SeekBar)
740 */
741
742 @Override
743 public void onStopTrackingTouch(final SeekBar seekbar) {
744 equalizerUpdateDisplay();
745 }
746
747 /**
748 * Updates the EQ by getting the parameters.
749 */
750 private void equalizerUpdateDisplay() {
751 // Update and show the active N-Band Equalizer bands.
752 final int[] bandLevels = ControlPanelEffect.getParameterIntArray(mContext,
753 mCallingPackageName, mAudioSession, ControlPanelEffect.Key.eq_band_level);
754 for (short band = 0; band < mNumberEqualizerBands; band++) {
755 final int level = bandLevels[band];
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700756 final int progress = level - mEqualizerMinBandLevel;
757 mEqualizerSeekBar[band].setProgress(progress);
758 }
759 }
760
761 /**
762 * Updates/sets a given EQ band level.
763 *
764 * @param band
765 * Band id
766 * @param level
767 * EQ band level
768 */
Marco Nelissenc4724442011-06-30 12:07:50 -0700769 private void equalizerBandUpdate(final int band, final int level) {
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700770 ControlPanelEffect.setParameterInt(mContext, mCallingPackageName, mAudioSession,
771 ControlPanelEffect.Key.eq_band_level, level, band);
772 }
773
774 /**
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700775 * Sets the given EQ preset.
776 *
777 * @param preset
778 * EQ preset id.
779 */
780 private void equalizerSetPreset(final int preset) {
Marco Nelissenc4724442011-06-30 12:07:50 -0700781 ControlPanelEffect.setParameterInt(mContext, mCallingPackageName, mAudioSession,
782 ControlPanelEffect.Key.eq_current_preset, preset);
783 equalizerUpdateDisplay();
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700784 }
785
786 /**
787 * Sets the given PR preset.
788 *
789 * @param preset
790 * PR preset id.
791 */
792 private void presetReverbSetPreset(final int preset) {
Marco Nelissene7de6512011-08-18 11:13:20 -0700793 ControlPanelEffect.setParameterInt(mContext, mCallingPackageName, mAudioSession,
794 ControlPanelEffect.Key.pr_current_preset, preset);
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700795 }
796
797 /**
798 * Show msg that headset needs to be plugged.
799 */
800 private void showHeadsetMsg() {
801 final Context context = getApplicationContext();
802 final int duration = Toast.LENGTH_SHORT;
803
804 final Toast toast = Toast.makeText(context, getString(R.string.headset_plug), duration);
805 toast.setGravity(Gravity.CENTER, toast.getXOffset() / 2, toast.getYOffset() / 2);
806 toast.show();
807 }
Marco Nelissen66f2cfe2011-06-23 14:05:10 -0700808}