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