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 21 import android.app.ActionBar; 22 import android.app.Activity; 23 import android.app.AlertDialog; 24 import android.app.Dialog; 25 import android.bluetooth.BluetoothClass; 26 import android.bluetooth.BluetoothDevice; 27 import android.content.BroadcastReceiver; 28 import android.content.Context; 29 import android.content.DialogInterface; 30 import android.content.DialogInterface.OnCancelListener; 31 import android.content.Intent; 32 import android.content.IntentFilter; 33 import android.media.AudioManager; 34 import android.media.audiofx.AudioEffect; 35 import android.media.audiofx.AudioEffect.Descriptor; 36 import android.os.Bundle; 37 import android.util.Log; 38 import android.view.Gravity; 39 import android.view.LayoutInflater; 40 import android.view.MotionEvent; 41 import android.view.View; 42 import android.view.View.OnClickListener; 43 import android.view.View.OnTouchListener; 44 import android.view.ViewGroup; 45 import android.widget.AdapterView; 46 import android.widget.AdapterView.OnItemSelectedListener; 47 import android.widget.ArrayAdapter; 48 import android.widget.CompoundButton; 49 import android.widget.CompoundButton.OnCheckedChangeListener; 50 import android.widget.LinearLayout; 51 import android.widget.ListView; 52 import android.widget.RelativeLayout; 53 import android.widget.SeekBar; 54 import android.widget.SeekBar.OnSeekBarChangeListener; 55 import android.widget.Spinner; 56 import android.widget.Switch; 57 import android.widget.TextView; 58 import android.widget.Toast; 59 60 import java.util.Formatter; 61 import java.util.Locale; 62 import java.util.UUID; 63 64 /** 65 * 66 */ 67 public class ActivityMusic extends Activity implements OnSeekBarChangeListener { 68 private final static String TAG = "MusicFXActivityMusic"; 69 70 /** 71 * Max number of EQ bands supported 72 */ 73 private final static int EQUALIZER_MAX_BANDS = 32; 74 75 /** 76 * 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 /** 86 * Indicates if Virtualizer effect is supported. 87 */ 88 private boolean mVirtualizerSupported; 89 private boolean mVirtualizerIsHeadphoneOnly; 90 /** 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]; 105 private int mNumberEqualizerBands; 106 private int mEqualizerMinBandLevel; 107 private int mEQPresetUserPos = 1; 108 private int mEQPreset; 109 private int mEQPresetPrevious; 110 private int[] mEQPresetUserBandLevelsPrev; 111 private String[] mEQPresetNames; 112 113 private int mPRPreset; 114 private int mPRPresetPrevious; 115 116 private boolean mIsHeadsetOn = false; 117 private CompoundButton mToggleSwitch; 118 119 private StringBuilder mFormatBuilder = new StringBuilder(); 120 private Formatter mFormatter = new Formatter(mFormatBuilder, Locale.getDefault()); 121 122 /** 123 * Mapping for the EQ widget ids per band 124 */ 125 private static final int[][] EQViewElementIds = { 126 { 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 } }; 158 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 onCreate(final Bundle savedInstanceState)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; 263 if (effect.uuid.equals(UUID.fromString("1d4033c0-8557-11df-9f2d-0002a5d5c51b"))) { 264 mVirtualizerIsHeadphoneOnly = true; 265 } 266 } 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); 277 278 // 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 291 // 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. 297 mToggleSwitch = new Switch(this); 298 mToggleSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() { 299 @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 308 setEnabledAllChildren(viewGroup, isChecked); 309 // update UI according to headset state 310 updateUIHeadset(); 311 } 312 }); 313 314 // 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) { 322 if (event.getAction() == MotionEvent.ACTION_UP) { 323 showHeadsetMsg(); 324 } 325 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 }); 364 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 }); 374 } 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) { 384 if (event.getAction() == MotionEvent.ACTION_UP) { 385 showHeadsetMsg(); 386 } 387 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) { 431 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)); 439 } 440 441 // Initialize the Preset Reverb elements. 442 // Set Spinner listeners. 443 if (mPresetReverbSupported) { 444 mPRPreset = ControlPanelEffect.getParameterInt(mContext, mCallingPackageName, 445 mAudioSession, ControlPanelEffect.Key.pr_current_preset); 446 mPRPresetPrevious = mPRPreset; 447 reverbSpinnerInit((Spinner)findViewById(R.id.prSpinner)); 448 } 449 450 } else { 451 viewGroup.setVisibility(View.GONE); 452 ((TextView) findViewById(R.id.noEffectsTextView)).setVisibility(View.VISIBLE); 453 } 454 455 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); 464 } 465 466 /* 467 * (non-Javadoc) 468 * 469 * @see android.app.Activity#onResume() 470 */ 471 @Override onResume()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 onPause()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 reverbSpinnerInit(Spinner spinner)507 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() { 513 514 @Override 515 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 516 if (position != mPRPresetPrevious) { 517 presetReverbSetPreset(position); 518 } 519 mPRPresetPrevious = position; 520 } 521 522 @Override 523 public void onNothingSelected(AdapterView<?> parent) { 524 } 525 }); 526 spinner.setSelection(mPRPreset); 527 } 528 equalizerSpinnerInit(Spinner spinner)529 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 552 /** 553 * En/disables all children for a given view. For linear and relative layout children do this 554 * recursively 555 * 556 * @param viewGroup 557 * @param enabled 558 */ setEnabledAllChildren(final ViewGroup viewGroup, final boolean enabled)559 private void setEnabledAllChildren(final ViewGroup viewGroup, final boolean enabled) { 560 final int count = viewGroup.getChildCount(); 561 for (int i = 0; i < count; i++) { 562 final View view = viewGroup.getChildAt(i); 563 if ((view instanceof ViewGroup)) { 564 final ViewGroup vg = (ViewGroup) view; 565 setEnabledAllChildren(vg, enabled); 566 } 567 view.setEnabled(enabled); 568 } 569 } 570 571 /** 572 * Updates UI (checkbox, seekbars, enabled states) according to the current stored preferences. 573 */ updateUI()574 private void updateUI() { 575 final boolean isEnabled = ControlPanelEffect.getParameterBoolean(mContext, 576 mCallingPackageName, mAudioSession, ControlPanelEffect.Key.global_enabled); 577 mToggleSwitch.setChecked(isEnabled); 578 setEnabledAllChildren((ViewGroup) findViewById(R.id.contentSoundEffects), isEnabled); 579 updateUIHeadset(); 580 581 if (mVirtualizerSupported) { 582 SeekBar bar = (SeekBar) findViewById(R.id.vIStrengthSeekBar); 583 Switch sw = (Switch) findViewById(R.id.vIStrengthToggle); 584 int strength = ControlPanelEffect 585 .getParameterInt(mContext, mCallingPackageName, mAudioSession, 586 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 } 597 } 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) { 604 equalizerUpdateDisplay(); 605 } 606 if (mPresetReverbSupported) { 607 int reverb = ControlPanelEffect.getParameterInt( 608 mContext, mCallingPackageName, mAudioSession, 609 ControlPanelEffect.Key.pr_current_preset); 610 ((Spinner)findViewById(R.id.prSpinner)).setSelection(reverb); 611 } 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 */ updateUIHeadset()619 private void updateUIHeadset() { 620 if (mToggleSwitch.isChecked()) { 621 ((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); 626 ((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 */ equalizerBandsInit(View eqcontainer)635 private void equalizerBandsInit(View eqcontainer) { 636 // 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); 646 mEqualizerMinBandLevel = (int) Math.max(EQUALIZER_MIN_LEVEL, bandLevelRange[0]); 647 final int mEqualizerMaxBandLevel = (int) Math.min(EQUALIZER_MAX_LEVEL, bandLevelRange[1]); 648 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 } 658 ((TextView) eqcontainer.findViewById(EQViewElementIds[band][0])).setText( 659 format("%.0f ", centerFreqHz) + unitPrefix + "Hz"); 660 mEqualizerSeekBar[band] = (SeekBar) eqcontainer 661 .findViewById(EQViewElementIds[band][1]); 662 mEqualizerSeekBar[band].setMax(mEqualizerMaxBandLevel - mEqualizerMinBandLevel); 663 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 669 eqcontainer.findViewById(EQViewElementIds[band][0]).setVisibility(View.GONE); 670 // SeekBar 671 eqcontainer.findViewById(EQViewElementIds[band][1]).setVisibility(View.GONE); 672 } 673 674 TextView tv = (TextView) findViewById(R.id.maxLevelText); 675 tv.setText(String.format("+%d dB", (int) Math.ceil(mEqualizerMaxBandLevel / 100))); 676 tv = (TextView) findViewById(R.id.centerLevelText); 677 tv.setText("0 dB"); 678 tv = (TextView) findViewById(R.id.minLevelText); 679 tv.setText(String.format("%d dB", (int) Math.floor(mEqualizerMinBandLevel / 100))); 680 equalizerUpdateDisplay(); 681 } 682 format(String format, Object... args)683 private String format(String format, Object... args) { 684 mFormatBuilder.setLength(0); 685 mFormatter.format(format, args); 686 return mFormatBuilder.toString(); 687 } 688 689 /* 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 onProgressChanged(final SeekBar seekbar, final int progress, final boolean fromUser)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); 705 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 onStartTrackingTouch(final SeekBar seekbar)721 public void onStartTrackingTouch(final SeekBar seekbar) { 722 // 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); 730 ((Spinner)findViewById(R.id.eqSpinner)).setSelection(mEQPresetUserPos); 731 } 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 onStopTrackingTouch(final SeekBar seekbar)743 public void onStopTrackingTouch(final SeekBar seekbar) { 744 equalizerUpdateDisplay(); 745 } 746 747 /** 748 * Updates the EQ by getting the parameters. 749 */ equalizerUpdateDisplay()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]; 756 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 */ equalizerBandUpdate(final int band, final int level)769 private void equalizerBandUpdate(final int band, final int level) { 770 ControlPanelEffect.setParameterInt(mContext, mCallingPackageName, mAudioSession, 771 ControlPanelEffect.Key.eq_band_level, level, band); 772 } 773 774 /** 775 * Sets the given EQ preset. 776 * 777 * @param preset 778 * EQ preset id. 779 */ equalizerSetPreset(final int preset)780 private void equalizerSetPreset(final int preset) { 781 ControlPanelEffect.setParameterInt(mContext, mCallingPackageName, mAudioSession, 782 ControlPanelEffect.Key.eq_current_preset, preset); 783 equalizerUpdateDisplay(); 784 } 785 786 /** 787 * Sets the given PR preset. 788 * 789 * @param preset 790 * PR preset id. 791 */ presetReverbSetPreset(final int preset)792 private void presetReverbSetPreset(final int preset) { 793 ControlPanelEffect.setParameterInt(mContext, mCallingPackageName, mAudioSession, 794 ControlPanelEffect.Key.pr_current_preset, preset); 795 } 796 797 /** 798 * Show msg that headset needs to be plugged. 799 */ showHeadsetMsg()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 } 808 } 809